- new option enables "auto select system", closed #569

- improved `console` logging format
This commit is contained in:
Mark Friedrich
2018-12-14 21:37:04 +01:00
parent 295ffc8fae
commit c397339e20
35 changed files with 1097 additions and 349 deletions

View File

@@ -183,6 +183,11 @@ class Map extends Controller\AccessController {
'zKillboard' => Config::getPathfinderData('api.z_killboard')
];
// Character default config -------------------------------------------------------------------------------
$return->character = [
'autoLocationSelect' => (bool)Config::getPathfinderData('character.auto_location_select')
];
// Slack integration status -------------------------------------------------------------------------------
$return->slack = [
'status' => (bool)Config::getPathfinderData('slack.status')

View File

@@ -329,7 +329,7 @@ class User extends Controller\Controller{
// character config -----------------------------------------------------------
if(isset($formData['character'])){
$activeCharacter->logLocation = (int)$formData['logLocation'];
$activeCharacter->copyfrom($formData, ['logLocation', 'selectLocation']);
$activeCharacter->save();
}

View File

@@ -142,6 +142,11 @@ class CharacterModel extends BasicModel {
'nullable' => false,
'default' => 1
],
'selectLocation' => [
'type' => Schema::DT_BOOL,
'nullable' => false,
'default' => 0
],
'securityStatus' => [
'type' => Schema::DT_FLOAT,
'nullable' => false,
@@ -186,6 +191,7 @@ class CharacterModel extends BasicModel {
$characterData->role = $this->roleId->getData();
$characterData->shared = $this->shared;
$characterData->logLocation = $this->logLocation;
$characterData->selectLocation = $this->selectLocation;
if($this->authStatus){
$characterData->authStatus = $this->authStatus;

View File

@@ -36,12 +36,15 @@ CHARACTER =
CORPORATION =
ALLIANCE =
[PATHFINDER.CHARACTER]
AUTO_LOCATION_SELECT = 1
; Slack API integration ===========================================================================
[PATHFINDER.SLACK]
; Global Slack API status, check PATHFINDER.MAP section for individual control (0=disabled, 1=enabled)
STATUS = 1
; Slack API integration ===========================================================================
; Discord API integration =========================================================================
[PATHFINDER.DISCORD]
; Global Discord API status, check PATHFINDER.MAP section for individual control (0=disabled, 1=enabled)
STATUS = 1

215
js/app/console.js Normal file
View File

@@ -0,0 +1,215 @@
/**
* Console module
* -> extends default window.console log object
*/
define([], () => {
'use strict';
/**
* init custom window.console object
* -> extend console obj with custom methods for styling and logging
*/
let initConsole = () => {
window.console = (origConsole => {
// save orig methods for byPassing args to original methods
let log = origConsole.log;
let info = origConsole.info;
let warn = origConsole.warn;
let error = origConsole.error;
let styles = {
'indentDefault': {
'padding-left': '3px'
},
'global': {
'font-weight': 500,
'font-size': '11px',
'line-height': '19px',
'font-family': '"Fira Code", "Lucida Console"',
},
'ok': {
'color': '#5cb85c'
},
'log': {
'color': '#adadad'
},
'info': {
'color': '#428bca'
},
'warn': {
'color': '#ffdd9e'
},
'error': {
'color': '#ff8080'
},
'pf': {
'color': '#568a89'
},
'brand': {
'color': '#375959',
'line-height': '35px',
'font-size': '25px'
}
};
let placeholders = {
'%s': {
'style': ['color: #e93f3b; font-style: italic', 'color: inherit']
},
'%i': {
'style': ['color: #9980ff', 'color: inherit'],
},
'%d': {
'style': ['color: #9980ff', 'color: inherit']
},
'%f': {
'style': ['color: #9980ff', 'color: inherit']
},
'%o': {
'style': ['', '']
},
'%O': {
'style': ['', '']
}
};
let findPlaceholders = str => {
let exp = new RegExp(Object.keys(placeholders).join('|'), 'g');
let matches = str.match(exp);
return matches ? matches : [];
};
let addStylePlaceholder = str => {
let exp = new RegExp(Object.keys(placeholders).join('|'), 'g');
return str.replace(exp, function(matched){
return '%c' + matched + '%c';
});
};
let getStyleByPlaceholder = (placeholder, clear = false) => {
let css = '';
if(placeholders.hasOwnProperty(placeholder)){
css = placeholders[placeholder].style[clear ? 1 : 0];
}
return css;
};
let getStyleByLogType = (logType, props = []) => {
let css = '';
if(styles.hasOwnProperty(logType)){
css = Object.keys(styles[logType])
.filter(prop => props.length ? props.includes(prop) : true)
.reduce((css, prop,i, affe) => {
css += prop + ':' + styles[logType][prop] + ';';
return css;
}, '');
}
return css;
};
let setLineStyleByLogType = (logType, args) => {
if(args.length){
let lineStyle = getStyleByLogType('global') + getStyleByLogType(logType);
lineStyle += ['ok', 'log', 'info', 'pf'].includes(logType) ? getStyleByLogType('indentDefault') : '';
let bullet = ['ok', 'log', 'info', 'pf'].includes(logType) ? '●' : '';
if(typeof args[0] === 'string'){
// prepend placeholder to existing message
args[0] = '%c' + bullet + ' ' + args[0];
}else{
// prepend placeholder as new message
args.splice(0, 0, '%c' + bullet + ' ' + logType + ':');
}
// set line style as 2nd argument
args.splice(1, 0, lineStyle);
}
};
let setMessageStyleByLogType = (logType, args) => {
if(typeof args[0] === 'string') {
let placeholdersFound = findPlaceholders(args[0]);
let placeholderCount = placeholdersFound.length;
// add c% placeholders around other placeholders
args[0] = addStylePlaceholder(args[0]);
// add style args for c% placeholders
let placeholderIndex = 0;
let argIndexStart = 1;
let argIndexEnd = argIndexStart + placeholderCount;
let argIndexOffset = 0;
for (let argIndex = argIndexStart; argIndex < argIndexEnd; argIndex++) {
args.splice(argIndex + argIndexOffset, 0, getStyleByPlaceholder(placeholdersFound[placeholderIndex]));
argIndexOffset += 2;
args.splice(argIndex + argIndexOffset, 0, getStyleByPlaceholder(placeholdersFound[placeholderIndex], true) + ';' + getStyleByLogType('global') + getStyleByLogType(logType));
placeholderIndex++;
}
}
};
origConsole.ok = (...args) => {
setMessageStyleByLogType('ok', args);
setLineStyleByLogType('ok', args);
info.apply(origConsole, args);
};
origConsole.info = (...args) => {
setMessageStyleByLogType('info', args);
setLineStyleByLogType('info', args);
info.apply(origConsole, args);
};
origConsole.log = (...args) => {
setMessageStyleByLogType('log', args);
setLineStyleByLogType('log', args);
log.apply(origConsole, args);
};
origConsole.warn = (...args) => {
setMessageStyleByLogType('warn', args);
setLineStyleByLogType('warn', args);
warn.apply(origConsole, args);
};
origConsole.error = (...args) => {
setMessageStyleByLogType('error', args);
setLineStyleByLogType('error', args);
error.apply(origConsole, args);
};
origConsole.pf = (...args) => {
setMessageStyleByLogType('pf', args);
setLineStyleByLogType('pf', args);
info.apply(origConsole, args);
};
origConsole.brand = (...args) => {
setMessageStyleByLogType('brand', args);
setLineStyleByLogType('brand', args);
info.apply(origConsole, args);
};
return origConsole;
})(window.console);
};
initConsole();
/**
* show current program version information console
* @param version
*/
let showVersionInfo = (version) => {
console.ok('%c PATHFINDER',
'color: #477372; font-size: 25px; margin-left: 10px; line-height: 100px; text-shadow: 1px 1px 0 #212C30; ' +
'background: url(https://i.imgur.com/1Gw8mjL.png) no-repeat;');
console.pf('Release: %s', version);
};
return {
showVersionInfo: showVersionInfo
};
});

View File

@@ -1495,7 +1495,7 @@ define([
hiddenOptions.push('delete_system');
}
let mapElement = component.parents('.' + config.mapClass);
let mapElement = component.closest('.' + config.mapClass);
if( !mapElement.find('.' + config.systemActiveClass).length ){
hiddenOptions.push('find_route');
}
@@ -1827,7 +1827,7 @@ define([
let single = function(e){
// check if click was performed on "popover" (x-editable)
let popoverClick = false;
if( $(e.target).parents('.popover').length ){
if( $(e.target).closest('.popover').length ){
popoverClick = true;
}
@@ -2014,7 +2014,7 @@ define([
// register all available connection types ----------------------------------------------------------------
newJsPlumbInstance.registerConnectionTypes(globalMapConfig.connectionTypes);
// event after a new connection is established --------------------------
// event after a new connection is established ------------------------------------------------------------
newJsPlumbInstance.bind('connection', function(info, e){
// set connection observer
setConnectionObserver(newJsPlumbInstance, info.connection);
@@ -2114,6 +2114,54 @@ define([
return MapUtil.getMapInstance(mapId);
};
/**
* check if there is an focus() element found as parent of tabContentElement
* -> or if there is any other active UI element found (e.g. dialog, xEditable, Summernote)
* @param tabContentElement
* @returns {*}
*/
let systemFormsActive = (tabContentElement) => {
let activeNode = null;
if(tabContentElement.length){
// tabContentElement exists ...
tabContentElement = tabContentElement[0];
// ... check for current active/focus() element and is not the default <body> element ...
if(
Util.isDomElement(document.activeElement) &&
document.activeElement !== document.body
){
let activeElementTagName = document.activeElement.tagName.toLocaleLowerCase();
// ... check for active form elements ...
let isFormElement = ['input', 'select', 'textarea'].includes(activeElementTagName);
let isChildElement = tabContentElement.contains(document.activeElement);
if(isFormElement && isChildElement){
activeNode = activeElementTagName;
}else{
// ... check for open dialogs/xEditable elements ...
if(Util.isDomElement(document.querySelector('.bootbox'))){
activeNode = 'dialogOpen';
}else if(Util.isDomElement(document.querySelector('.editable-open'))){
activeNode = 'xEditableOpen';
}else{
// ... check for open Summernote editor
let summernoteElement = tabContentElement.querySelector('.' + Util.config.summernoteClass);
if(
Util.isDomElement(summernoteElement) &&
typeof $(summernoteElement).data().summernote === 'object'
){
activeNode = 'SummernoteOpen';
}
}
}
}
}
return activeNode;
};
/**
* set observer for a map container
* @param map
@@ -2484,17 +2532,30 @@ define([
// triggered from "header" link (if user is active in one of the systems)
mapContainer.on('pf:menuSelectSystem', function(e, data){
let tempMapContainer = $(this);
let systemId = MapUtil.getSystemId(tempMapContainer.data('id'), data.systemId);
let system = $(this).find('#' + systemId);
let mapElement = $(this);
let systemId = MapUtil.getSystemId(mapElement.data('id'), data.systemId);
let system = mapElement.find('#' + systemId);
if(system.length === 1){
// scroll to system
let tempMapWrapper = tempMapContainer.parents('.' + config.mapWrapperClass);
tempMapWrapper.mCustomScrollbar('scrollTo', system);
// system found on map ...
let select = Util.getObjVal(data, 'forceSelect') !== false;
// select system
MapUtil.showSystemInfo(map, system);
if(!select){
// ... select is NOT "forced" -> auto select system on jump
let activeElement = systemFormsActive(MapUtil.getTabContentElementByMapElement(system));
if(activeElement !== null){
console.info('Skip auto select systemId %i. Reason: %o', data.systemId, activeElement);
}else{
select = true;
}
}
if(select){
let mapWrapper = mapElement.closest('.' + config.mapWrapperClass);
mapWrapper.scrollToSystem(MapUtil.getSystemPosition(system));
// select system
MapUtil.showSystemInfo(map, system);
}
}
});
@@ -2595,118 +2656,125 @@ define([
/**
* 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 mapElement
* @param userData
* @returns {boolean}
* @returns {Promise<any>}
*/
$.fn.updateUserData = function(userData){
let returnStatus = true;
let updateUserData = (mapElement, userData) => {
// get new map instance or load existing
let map = getMapInstance(userData.config.id);
let mapElement = map.getContainer();
// container must exist! otherwise systems can not be updated
if(mapElement !== undefined){
mapElement = $(mapElement);
// check if map is frozen
if(mapElement.data('frozen') === true){
return returnStatus;
}
// compact/small system layout or not
let compactView = mapElement.hasClass(MapUtil.config.mapCompactClass);
// get current character log data
let characterLogExists = false;
let currentCharacterLog = Util.getCurrentCharacterLog();
// data for header update
let headerUpdateData = {
mapId: userData.config.id,
userCountInside: 0, // active user on a map
userCountOutside: 0, // active user NOT on map
userCountInactive: 0 // inactive users (no location)
let updateUserDataExecutor = (resolve, reject) => {
let payload = {
action: 'updateUserData'
};
if(
currentCharacterLog &&
currentCharacterLog.system
){
characterLogExists = true;
headerUpdateData.currentSystemName = currentCharacterLog.system.name;
}
// get new map instance or load existing
let map = getMapInstance(userData.config.id);
let mapElement = map.getContainer();
// check if current user was found on the map
let currentUserOnMap = false;
// container must exist! otherwise systems can not be updated
if(mapElement !== undefined){
mapElement = $(mapElement);
// get all systems
let systems = mapElement.find('.' + config.systemClass);
for(let i = 0; i < systems.length; i++){
// get user Data for System
let system = $( systems[i] );
let systemId = $(system).data('systemId');
let tempUserData = null;
// check if user is currently in "this" system
let currentUserIsHere = false;
let j = userData.data.systems.length;
// search backwards to avoid decrement the counter after splice()
while(j--){
let 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.userCountInside += tempUserData.user.length;
// remove system from "search" array -> speed up loop
userData.data.systems.splice(j, 1);
}
// no user update for 'frozen' maps...
if(mapElement.data('frozen') === true){
return resolve(payload);
}
// the current user can only be in a single system ----------------------------------------------------
// compact/small system layout or not
let compactView = mapElement.hasClass(MapUtil.config.mapCompactClass);
// get current character log data
let characterLogExists = false;
let currentCharacterLog = Util.getCurrentCharacterLog();
// data for header update
let headerUpdateData = {
mapId: userData.config.id,
userCountInside: 0, // active user on a map
userCountOutside: 0, // active user NOT on map
userCountInactive: 0, // inactive users (no location)
currentLocation: {
id: 0, // systemId for current active user
name: false // systemName for current active user
}
};
if(
characterLogExists &&
currentCharacterLog.system.id === systemId
currentCharacterLog &&
currentCharacterLog.system
){
if( !currentUserOnMap ){
currentUserIsHere = true;
currentUserOnMap = true;
characterLogExists = true;
headerUpdateData.currentLocation.name = currentCharacterLog.system.name;
}
// set current location data for header update
headerUpdateData.currentSystemId = $(system).data('id');
headerUpdateData.currentSystemName = currentCharacterLog.system.name;
// check if current user was found on the map
let currentUserOnMap = false;
// get all systems
let systems = mapElement.find('.' + config.systemClass);
for(let system of systems){
system = $(system);
let systemId = system.data('systemId');
let tempUserData = null;
// check if user is currently in "this" system
let currentUserIsHere = false;
let j = userData.data.systems.length;
// search backwards to avoid decrement the counter after splice()
while(j--){
let 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.userCountInside += 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(
characterLogExists &&
currentCharacterLog.system.id === systemId
){
if( !currentUserOnMap ){
currentUserIsHere = true;
currentUserOnMap = true;
// set current location data for header update
headerUpdateData.currentLocation.id = system.data('id');
headerUpdateData.currentLocation.name = currentCharacterLog.system.name;
}
}
system.updateSystemUserData(map, tempUserData, currentUserIsHere, {compactView: compactView});
}
// users who are not in any map system ----------------------------------------------------------------
for(let systemData of userData.data.systems){
// users without location are grouped in systemId: 0
if(systemData.id){
headerUpdateData.userCountOutside += systemData.user.length;
}else{
headerUpdateData.userCountInactive += systemData.user.length;
}
}
system.updateSystemUserData(map, tempUserData, currentUserIsHere, {compactView: compactView});
// trigger document event -> update header
$(document).trigger('pf:updateHeaderMapData', headerUpdateData);
}
// users who are not in any map system --------------------------------------------------------------------
for(let i = 0; i < userData.data.systems.length; i++){
// users without location are grouped in systemId: 0
if(userData.data.systems[i].id){
headerUpdateData.userCountOutside += userData.data.systems[i].user.length;
}else{
headerUpdateData.userCountInactive += userData.data.systems[i].user.length;
}
}
resolve(payload);
};
// trigger document event -> update header
$(document).trigger('pf:updateHeaderMapData', headerUpdateData);
}
return returnStatus;
return new Promise(updateUserDataExecutor);
};
/**
@@ -2851,17 +2919,7 @@ define([
updated: parseInt( system.data('updated') )
};
systemData.userCount = (system.data('userCount') ? parseInt( system.data('userCount') ) : 0);
// position ---------------------------------------------------------------------------------------------------
let positionData = {};
let currentX = system.css('left');
let 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;
systemData.position = MapUtil.getSystemPosition(system);
return systemData;
};
@@ -2982,6 +3040,7 @@ define([
return {
getMapInstance: getMapInstance,
loadMap: loadMap,
updateUserData: updateUserData,
saveSystemCallback: saveSystemCallback
};

View File

@@ -70,7 +70,7 @@ define([
};
/**
* scroll to a specific position in the map
* scroll to a specific position on map
* demo: http://manos.malihu.gr/repository/custom-scrollbar/demo/examples/scrollTo_demo.html
* @param position
*/
@@ -79,4 +79,31 @@ define([
$(this).mCustomScrollbar('scrollTo', position);
});
};
/**
* scroll to a specific system on map
* -> subtract some offset for tooltips/connections
* @param position
* @returns {*}
*/
$.fn.scrollToSystem = function(position){
position = getOffsetPosition(position, {x: -15, y: -35});
return this.each(function(){
$(this).mCustomScrollbar('scrollTo', position);
});
};
/**
* add/subtract offset coordinates from position
* -> no negative values returned
* @param position
* @param offset
* @returns {{x: number, y: number}}
*/
let getOffsetPosition = (position, offset) => {
return {
x: Math.max(0, position.x + offset.x),
y: Math.max(0, position.y + offset.y)
};
};
});

View File

@@ -482,7 +482,7 @@ define([
* @param label
* @returns {string}
*/
let getEndpointOverlayContent = (label) => {
let getEndpointOverlayContent = label => {
let newLabel = '';
let colorClass = 'txt-color-grayLighter';
@@ -508,17 +508,14 @@ define([
* @param element
* @returns {*}
*/
let getTabContentElementByMapElement = (element) => {
let tabContentElement = $(element).parents('.' + config.mapTabContentClass);
return tabContentElement;
};
let getTabContentElementByMapElement = element => $(element).closest('.' + config.mapTabContentClass);
/**
* checks if there is an "active" connection on a map
* @param map
* @returns {boolean}
*/
let hasActiveConnection = (map) => {
let hasActiveConnection = map => {
let activeConnections = getConnectionsByType(map, 'active');
return activeConnections.length > 0;
};
@@ -1203,6 +1200,21 @@ define([
return new Promise(setMapDefaultOptionsExecutor);
};
/**
* get system coordinates from systemElement
* @param system
* @returns {{x: number, y: number}}
*/
let getSystemPosition = system => {
let x = system.css('left');
let y = system.css('top');
return {
x: parseInt(x.substring(0, x.length - 2)),
y: parseInt(y.substring(0, y.length - 2))
};
};
/**
* scroll map to default (stored) x/y coordinates
* @param mapElement
@@ -1755,6 +1767,7 @@ define([
deleteLocalData: deleteLocalData,
visualizeMap: visualizeMap,
setMapDefaultOptions: setMapDefaultOptions,
getSystemPosition: getSystemPosition,
scrollToDefaultPosition: scrollToDefaultPosition,
getSystemId: getSystemId,
checkRight: checkRight,

View File

@@ -143,6 +143,7 @@ define([
Init.characterStatus = response.characterStatus;
Init.routes = response.routes;
Init.url = response.url;
Init.character = response.character;
Init.slack = response.slack;
Init.discord = response.discord;
Init.structureStatus = response.structureStatus;
@@ -308,10 +309,10 @@ define([
.then(payload => Promise.all([initMapModule(payload[0]), initMapWorker(payload[1])]))
.then(payload => {
// mapModule initialized and WebSocket configuration working
console.info('%s() complete! command: "%s"; syncStatus: "%s"',
payload[1].action,
payload[1].data.command,
payload[1].data.syncStatus
console.ok('Client syncStatus: %s. %O resolved by command: %s!',
payload[1].data.syncStatus,
payload[1].action + '()',
payload[1].data.command
);
})
.catch(payload => {
@@ -322,10 +323,10 @@ define([
break;
case 'initMapWorker':
// WebSocket not working -> no error here -> fallback to Ajax
console.warn('%s() rejects Promise. command: "%s"; syncStatus: "%s", payload: %o',
payload.action,
payload.data.command,
console.info('Client syncStatus: %s. %O rejected by command: %s! payload: %o',
payload.data.syncStatus,
payload.action + '()',
payload.data.command,
payload.data
);
break;

View File

@@ -458,7 +458,7 @@ define([
mapElement.trigger('pf:updateLocal', currentMapUserData);
// update map with current user data
mapElement.updateUserData(currentMapUserData);
Map.updateUserData(mapElement, currentMapUserData);
}
}

View File

@@ -491,7 +491,7 @@ define([
pageElement.prepend(headRendered);
// init header =====================================================================
// init header ================================================================================================
// init slide menus
let slideMenu = new $.slidebars({
@@ -516,7 +516,7 @@ define([
// current location
$('#' + Util.config.headCurrentLocationId).find('a').on('click', function(){
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: $(this).data('systemId') });
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: $(this).data('systemId')});
});
// program status
@@ -589,7 +589,7 @@ define([
pageElement.prepend(footerElement);
// init footer ==================================================
// init footer ================================================================================================
pageElement.find('.' + config.footerLicenceLinkClass).on('click', function(){
//show credits info dialog
$.fn.showCreditsDialog();
@@ -728,7 +728,7 @@ define([
return false;
});
// END menu events =============================================================================
// END menu events ============================================================================================
// global "popover" callback (for all popovers)
$('.' + Util.config.popoverTriggerClass).on('hide.bs.popover', function(e){
@@ -772,7 +772,7 @@ define([
userCountInside = data.userCountInside;
userCountOutside = data.userCountOutside;
userCountInactive = data.userCountInactive;
currentLocationData = data;
currentLocationData = data.currentLocation;
}
updateHeaderActiveUserCount(userCountInside, userCountOutside, userCountInactive);
updateHeaderCurrentLocation(currentLocationData);
@@ -825,7 +825,7 @@ define([
Util.showNotify({title: 'Logged out', text: data.reason, type: 'error'}, false);
// remove map -------------------------------------------------------
// remove map ---------------------------------------------------------------------------------------------
Util.getMapModule().velocity('fadeOut', {
duration: 300,
complete: function(){
@@ -933,7 +933,7 @@ define([
}
};
// check for character/ship changes ---------------------------------------------
// check for character/ship changes ---------------------------------------------------------------------------
if(
userData &&
userData.character
@@ -953,7 +953,7 @@ define([
return data.id;
});
// update user character data ---------------------------------------------------
// update user character data ---------------------------------------------------------------------------------
if(currentCharactersOptionIds.toString() !== newCharactersOptionIds.toString()){
let currentCharacterChanged = false;
@@ -976,7 +976,7 @@ define([
userInfoElement.data('characterOptionIds', newCharactersOptionIds);
}
// update user ship data --------------------------------------------------------
// update user ship data --------------------------------------------------------------------------------------
if(currentShipId !== newShipData.typeId){
// set new data for next check
userShipElement.data('shipData', newShipData);
@@ -1058,37 +1058,46 @@ define([
};
/**
* update the "current location" element in head
* update the "current location" link element in head
* @param locationData
*/
let updateHeaderCurrentLocation = function(locationData){
let currentLocationElement = $('#' + Util.config.headCurrentLocationId);
let linkElement = currentLocationElement.find('a');
let textElement = linkElement.find('span');
let updateHeaderCurrentLocation = locationData => {
let systemId = locationData.id || 0;
let systemName = locationData.name || false;
let tempSystemName = (locationData.currentSystemName) ? locationData.currentSystemName : false;
let tempSystemId = (locationData.currentSystemId) ? locationData.currentSystemId : 0;
let currentLocationData = Util.getCurrentLocationData();
if(
linkElement.data('systemName') !== tempSystemName ||
linkElement.data('systemId') !== tempSystemId
currentLocationData.name !== systemName ||
currentLocationData.id !== systemId
){
linkElement.data('systemName', tempSystemName);
linkElement.data('systemId', tempSystemId);
linkElement.toggleClass('disabled', !tempSystemId);
Util.setCurrentLocationData(systemId, systemName);
if(tempSystemName !== false){
textElement.text(locationData.currentSystemName);
let currentLocationElement = $('#' + Util.config.headCurrentLocationId);
let linkElement = currentLocationElement.find('a');
linkElement.toggleClass('disabled', !systemId);
if(systemName !== false){
linkElement.find('span').text(locationData.name);
currentLocationElement.velocity('fadeIn', {duration: Init.animationSpeed.headerLink});
}else{
if(currentLocationElement.is(':visible')){
currentLocationElement.velocity('fadeOut', {duration: Init.animationSpeed.headerLink});
}
}
// auto select current system -----------------------------------------------------------------------------
let userData = Util.getCurrentUserData();
if(
Boolean(Util.getObjVal(Init, 'character.autoLocationSelect')) &&
Util.getObjVal(userData, 'character.selectLocation')
){
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: systemId, forceSelect: false});
}
}
};
/**
* shows a test notification for desktop messages
*/

View File

@@ -55,6 +55,7 @@ define([
formErrorContainerClass: Util.config.formErrorContainerClass,
ccpImageServer: Init.url.ccpImageServer,
roleLabel: Util.getLabelByRole(Util.getObjVal(Util.getCurrentUserData(), 'character.role')).prop('outerHTML'),
characterAutoLocationSelectEnabled: Boolean(Util.getObjVal(Init, 'character.autoLocationSelect'))
};
let content = Mustache.render(template, data);

View File

@@ -307,7 +307,7 @@ define([
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
// select system
$(cell).on('click', function(e){
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: rowData.id });
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: rowData.id});
});
}
},{
@@ -597,7 +597,7 @@ define([
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
// select system
$(cell).on('click', function(e){
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: rowData.source.id });
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: rowData.source.id});
});
}
},{
@@ -615,7 +615,7 @@ define([
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
// select system
$(cell).on('click', function(e){
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: rowData.target.id });
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: rowData.target.id});
});
}
},{

View File

@@ -168,7 +168,7 @@ define([
class: 'pf-link',
html: connectionData.sourceAlias + '&nbsp;&nbsp;'
}).on('click', function(){
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: connectionData.source });
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: connectionData.source});
}),
$('<span>', {
class: [config.connectionInfoTableLabelSourceClass].join(' ')
@@ -183,7 +183,7 @@ define([
class: 'pf-link',
html: '&nbsp;&nbsp;' + connectionData.targetAlias
}).on('click', function(){
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: connectionData.target });
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: connectionData.target});
})
)
)

View File

@@ -39,7 +39,7 @@ define([
// description field
descriptionAreaClass: 'pf-system-info-description-area', // class for "description" area
addDescriptionButtonClass: 'pf-system-info-description-button', // class for "add description" button
descriptionTextareaElementClass: 'pf-system-info-description', // class for "description" textarea element (xEditable)
descriptionTextareaElementClass: 'pf-system-info-description', // class for "description" textarea element (Summernote)
// fonts
fontTriglivianClass: 'pf-triglivian', // class for "Triglivian" names (e.g. Abyssal systems)
@@ -177,6 +177,7 @@ define([
descriptionAreaClass: config.descriptionAreaClass,
descriptionButtonClass: config.addDescriptionButtonClass,
descriptionTextareaClass: config.descriptionTextareaElementClass,
summernoteClass: Util.config.summernoteClass,
systemNameClass: () => {
return (val, render) => {
return render(val) === 'A' ? config.fontTriglivianClass : '';
@@ -298,7 +299,7 @@ define([
},
callbacks: {
onInit: function(context){
// make editable field a big larger
// make editable field a bit larger
context.editable.css('height', '150px');
// set default background color

View File

@@ -4,6 +4,7 @@
define([
'jquery',
'app/init',
'app/console',
'conf/system_effect',
'conf/signature_type',
'bootbox',
@@ -18,7 +19,7 @@ define([
'bootstrapConfirmation',
'bootstrapToggle',
'select2'
], ($, Init, SystemEffect, SignatureType, bootbox, localforage) => {
], ($, Init, Con, SystemEffect, SignatureType, bootbox, localforage) => {
'use strict';
@@ -83,6 +84,9 @@ define([
popoverSmallClass: 'pf-popover-small', // class for small "popover"
popoverCharacterClass: 'pf-popover-character', // class for character "popover"
// Summernote
summernoteClass: 'pf-summernote', // class for Summernote "WYSIWYG" elements
// help
helpDefaultClass: 'pf-help-default', // class for "help" tooltip elements
helpClass: 'pf-help', // class for "help" tooltip elements
@@ -878,9 +882,7 @@ define([
/**
* show current program version information in browser console
*/
let showVersionInfo = () => {
console.info('PATHFINDER ' + getVersion());
};
let showVersionInfo = () => Con.showVersionInfo(getVersion());
/**
* polyfill for "passive" events
@@ -2771,16 +2773,28 @@ define([
return Init.currentSystemData;
};
/**
* set current location data
* -> system data where current user is located
* @param systemId
* @param systemName
*/
let setCurrentLocationData = (systemId, systemName) => {
let locationLink = $('#' + config.headCurrentLocationId).find('a');
locationLink.data('systemId', systemId);
locationLink.data('systemName', systemName);
};
/**
* get current location data
* -> system data where current user is located
* @returns {{id: *, name: *}}
*/
let getCurrentLocationData = () => {
let currentLocationLink = $('#' + config.headCurrentLocationId).find('a');
let locationLink = $('#' + config.headCurrentLocationId).find('a');
return {
id: currentLocationLink.data('systemId'),
name: currentLocationLink.data('systemName')
id: locationLink.data('systemId') || 0,
name: locationLink.data('systemName') || false
};
};
@@ -3012,6 +3026,13 @@ define([
return Array.from(doc.body.childNodes).some(node => node.nodeType === 1);
};
/**
* checks if a given object is a DOM element
* @param obj
* @returns {boolean}
*/
let isDomElement = obj => !!(obj && obj.nodeType === 1);
/**
* get deep json object value if exists
* -> e.g. key = 'first.last.third' string
@@ -3189,6 +3210,7 @@ define([
getCurrentCharacterId: getCurrentCharacterId,
setCurrentSystemData: setCurrentSystemData,
getCurrentSystemData: getCurrentSystemData,
setCurrentLocationData: setCurrentLocationData,
getCurrentLocationData: getCurrentLocationData,
getCurrentUserInfo: getCurrentUserInfo,
getCurrentCharacterLog: getCurrentCharacterLog,
@@ -3216,6 +3238,7 @@ define([
htmlEncode: htmlEncode,
htmlDecode: htmlDecode,
isValidHtml: isValidHtml,
isDomElement: isDomElement,
getObjVal: getObjVal,
redirect: redirect,
logout: logout,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,215 @@
/**
* Console module
* -> extends default window.console log object
*/
define([], () => {
'use strict';
/**
* init custom window.console object
* -> extend console obj with custom methods for styling and logging
*/
let initConsole = () => {
window.console = (origConsole => {
// save orig methods for byPassing args to original methods
let log = origConsole.log;
let info = origConsole.info;
let warn = origConsole.warn;
let error = origConsole.error;
let styles = {
'indentDefault': {
'padding-left': '3px'
},
'global': {
'font-weight': 500,
'font-size': '11px',
'line-height': '19px',
'font-family': '"Fira Code", "Lucida Console"',
},
'ok': {
'color': '#5cb85c'
},
'log': {
'color': '#adadad'
},
'info': {
'color': '#428bca'
},
'warn': {
'color': '#ffdd9e'
},
'error': {
'color': '#ff8080'
},
'pf': {
'color': '#568a89'
},
'brand': {
'color': '#375959',
'line-height': '35px',
'font-size': '25px'
}
};
let placeholders = {
'%s': {
'style': ['color: #e93f3b; font-style: italic', 'color: inherit']
},
'%i': {
'style': ['color: #9980ff', 'color: inherit'],
},
'%d': {
'style': ['color: #9980ff', 'color: inherit']
},
'%f': {
'style': ['color: #9980ff', 'color: inherit']
},
'%o': {
'style': ['', '']
},
'%O': {
'style': ['', '']
}
};
let findPlaceholders = str => {
let exp = new RegExp(Object.keys(placeholders).join('|'), 'g');
let matches = str.match(exp);
return matches ? matches : [];
};
let addStylePlaceholder = str => {
let exp = new RegExp(Object.keys(placeholders).join('|'), 'g');
return str.replace(exp, function(matched){
return '%c' + matched + '%c';
});
};
let getStyleByPlaceholder = (placeholder, clear = false) => {
let css = '';
if(placeholders.hasOwnProperty(placeholder)){
css = placeholders[placeholder].style[clear ? 1 : 0];
}
return css;
};
let getStyleByLogType = (logType, props = []) => {
let css = '';
if(styles.hasOwnProperty(logType)){
css = Object.keys(styles[logType])
.filter(prop => props.length ? props.includes(prop) : true)
.reduce((css, prop,i, affe) => {
css += prop + ':' + styles[logType][prop] + ';';
return css;
}, '');
}
return css;
};
let setLineStyleByLogType = (logType, args) => {
if(args.length){
let lineStyle = getStyleByLogType('global') + getStyleByLogType(logType);
lineStyle += ['ok', 'log', 'info', 'pf'].includes(logType) ? getStyleByLogType('indentDefault') : '';
let bullet = ['ok', 'log', 'info', 'pf'].includes(logType) ? '●' : '';
if(typeof args[0] === 'string'){
// prepend placeholder to existing message
args[0] = '%c' + bullet + ' ' + args[0];
}else{
// prepend placeholder as new message
args.splice(0, 0, '%c' + bullet + ' ' + logType + ':');
}
// set line style as 2nd argument
args.splice(1, 0, lineStyle);
}
};
let setMessageStyleByLogType = (logType, args) => {
if(typeof args[0] === 'string') {
let placeholdersFound = findPlaceholders(args[0]);
let placeholderCount = placeholdersFound.length;
// add c% placeholders around other placeholders
args[0] = addStylePlaceholder(args[0]);
// add style args for c% placeholders
let placeholderIndex = 0;
let argIndexStart = 1;
let argIndexEnd = argIndexStart + placeholderCount;
let argIndexOffset = 0;
for (let argIndex = argIndexStart; argIndex < argIndexEnd; argIndex++) {
args.splice(argIndex + argIndexOffset, 0, getStyleByPlaceholder(placeholdersFound[placeholderIndex]));
argIndexOffset += 2;
args.splice(argIndex + argIndexOffset, 0, getStyleByPlaceholder(placeholdersFound[placeholderIndex], true) + ';' + getStyleByLogType('global') + getStyleByLogType(logType));
placeholderIndex++;
}
}
};
origConsole.ok = (...args) => {
setMessageStyleByLogType('ok', args);
setLineStyleByLogType('ok', args);
info.apply(origConsole, args);
};
origConsole.info = (...args) => {
setMessageStyleByLogType('info', args);
setLineStyleByLogType('info', args);
info.apply(origConsole, args);
};
origConsole.log = (...args) => {
setMessageStyleByLogType('log', args);
setLineStyleByLogType('log', args);
log.apply(origConsole, args);
};
origConsole.warn = (...args) => {
setMessageStyleByLogType('warn', args);
setLineStyleByLogType('warn', args);
warn.apply(origConsole, args);
};
origConsole.error = (...args) => {
setMessageStyleByLogType('error', args);
setLineStyleByLogType('error', args);
error.apply(origConsole, args);
};
origConsole.pf = (...args) => {
setMessageStyleByLogType('pf', args);
setLineStyleByLogType('pf', args);
info.apply(origConsole, args);
};
origConsole.brand = (...args) => {
setMessageStyleByLogType('brand', args);
setLineStyleByLogType('brand', args);
info.apply(origConsole, args);
};
return origConsole;
})(window.console);
};
initConsole();
/**
* show current program version information console
* @param version
*/
let showVersionInfo = (version) => {
console.ok('%c PATHFINDER',
'color: #477372; font-size: 25px; margin-left: 10px; line-height: 100px; text-shadow: 1px 1px 0 #212C30; ' +
'background: url(https://i.imgur.com/1Gw8mjL.png) no-repeat;');
console.pf('Release: %s', version);
};
return {
showVersionInfo: showVersionInfo
};
});

View File

@@ -1495,7 +1495,7 @@ define([
hiddenOptions.push('delete_system');
}
let mapElement = component.parents('.' + config.mapClass);
let mapElement = component.closest('.' + config.mapClass);
if( !mapElement.find('.' + config.systemActiveClass).length ){
hiddenOptions.push('find_route');
}
@@ -1827,7 +1827,7 @@ define([
let single = function(e){
// check if click was performed on "popover" (x-editable)
let popoverClick = false;
if( $(e.target).parents('.popover').length ){
if( $(e.target).closest('.popover').length ){
popoverClick = true;
}
@@ -2014,7 +2014,7 @@ define([
// register all available connection types ----------------------------------------------------------------
newJsPlumbInstance.registerConnectionTypes(globalMapConfig.connectionTypes);
// event after a new connection is established --------------------------
// event after a new connection is established ------------------------------------------------------------
newJsPlumbInstance.bind('connection', function(info, e){
// set connection observer
setConnectionObserver(newJsPlumbInstance, info.connection);
@@ -2114,6 +2114,54 @@ define([
return MapUtil.getMapInstance(mapId);
};
/**
* check if there is an focus() element found as parent of tabContentElement
* -> or if there is any other active UI element found (e.g. dialog, xEditable, Summernote)
* @param tabContentElement
* @returns {*}
*/
let systemFormsActive = (tabContentElement) => {
let activeNode = null;
if(tabContentElement.length){
// tabContentElement exists ...
tabContentElement = tabContentElement[0];
// ... check for current active/focus() element and is not the default <body> element ...
if(
Util.isDomElement(document.activeElement) &&
document.activeElement !== document.body
){
let activeElementTagName = document.activeElement.tagName.toLocaleLowerCase();
// ... check for active form elements ...
let isFormElement = ['input', 'select', 'textarea'].includes(activeElementTagName);
let isChildElement = tabContentElement.contains(document.activeElement);
if(isFormElement && isChildElement){
activeNode = activeElementTagName;
}else{
// ... check for open dialogs/xEditable elements ...
if(Util.isDomElement(document.querySelector('.bootbox'))){
activeNode = 'dialogOpen';
}else if(Util.isDomElement(document.querySelector('.editable-open'))){
activeNode = 'xEditableOpen';
}else{
// ... check for open Summernote editor
let summernoteElement = tabContentElement.querySelector('.' + Util.config.summernoteClass);
if(
Util.isDomElement(summernoteElement) &&
typeof $(summernoteElement).data().summernote === 'object'
){
activeNode = 'SummernoteOpen';
}
}
}
}
}
return activeNode;
};
/**
* set observer for a map container
* @param map
@@ -2484,17 +2532,30 @@ define([
// triggered from "header" link (if user is active in one of the systems)
mapContainer.on('pf:menuSelectSystem', function(e, data){
let tempMapContainer = $(this);
let systemId = MapUtil.getSystemId(tempMapContainer.data('id'), data.systemId);
let system = $(this).find('#' + systemId);
let mapElement = $(this);
let systemId = MapUtil.getSystemId(mapElement.data('id'), data.systemId);
let system = mapElement.find('#' + systemId);
if(system.length === 1){
// scroll to system
let tempMapWrapper = tempMapContainer.parents('.' + config.mapWrapperClass);
tempMapWrapper.mCustomScrollbar('scrollTo', system);
// system found on map ...
let select = Util.getObjVal(data, 'forceSelect') !== false;
// select system
MapUtil.showSystemInfo(map, system);
if(!select){
// ... select is NOT "forced" -> auto select system on jump
let activeElement = systemFormsActive(MapUtil.getTabContentElementByMapElement(system));
if(activeElement !== null){
console.info('Skip auto select systemId %i. Reason: %o', data.systemId, activeElement);
}else{
select = true;
}
}
if(select){
let mapWrapper = mapElement.closest('.' + config.mapWrapperClass);
mapWrapper.scrollToSystem(MapUtil.getSystemPosition(system));
// select system
MapUtil.showSystemInfo(map, system);
}
}
});
@@ -2595,118 +2656,125 @@ define([
/**
* 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 mapElement
* @param userData
* @returns {boolean}
* @returns {Promise<any>}
*/
$.fn.updateUserData = function(userData){
let returnStatus = true;
let updateUserData = (mapElement, userData) => {
// get new map instance or load existing
let map = getMapInstance(userData.config.id);
let mapElement = map.getContainer();
// container must exist! otherwise systems can not be updated
if(mapElement !== undefined){
mapElement = $(mapElement);
// check if map is frozen
if(mapElement.data('frozen') === true){
return returnStatus;
}
// compact/small system layout or not
let compactView = mapElement.hasClass(MapUtil.config.mapCompactClass);
// get current character log data
let characterLogExists = false;
let currentCharacterLog = Util.getCurrentCharacterLog();
// data for header update
let headerUpdateData = {
mapId: userData.config.id,
userCountInside: 0, // active user on a map
userCountOutside: 0, // active user NOT on map
userCountInactive: 0 // inactive users (no location)
let updateUserDataExecutor = (resolve, reject) => {
let payload = {
action: 'updateUserData'
};
if(
currentCharacterLog &&
currentCharacterLog.system
){
characterLogExists = true;
headerUpdateData.currentSystemName = currentCharacterLog.system.name;
}
// get new map instance or load existing
let map = getMapInstance(userData.config.id);
let mapElement = map.getContainer();
// check if current user was found on the map
let currentUserOnMap = false;
// container must exist! otherwise systems can not be updated
if(mapElement !== undefined){
mapElement = $(mapElement);
// get all systems
let systems = mapElement.find('.' + config.systemClass);
for(let i = 0; i < systems.length; i++){
// get user Data for System
let system = $( systems[i] );
let systemId = $(system).data('systemId');
let tempUserData = null;
// check if user is currently in "this" system
let currentUserIsHere = false;
let j = userData.data.systems.length;
// search backwards to avoid decrement the counter after splice()
while(j--){
let 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.userCountInside += tempUserData.user.length;
// remove system from "search" array -> speed up loop
userData.data.systems.splice(j, 1);
}
// no user update for 'frozen' maps...
if(mapElement.data('frozen') === true){
return resolve(payload);
}
// the current user can only be in a single system ----------------------------------------------------
// compact/small system layout or not
let compactView = mapElement.hasClass(MapUtil.config.mapCompactClass);
// get current character log data
let characterLogExists = false;
let currentCharacterLog = Util.getCurrentCharacterLog();
// data for header update
let headerUpdateData = {
mapId: userData.config.id,
userCountInside: 0, // active user on a map
userCountOutside: 0, // active user NOT on map
userCountInactive: 0, // inactive users (no location)
currentLocation: {
id: 0, // systemId for current active user
name: false // systemName for current active user
}
};
if(
characterLogExists &&
currentCharacterLog.system.id === systemId
currentCharacterLog &&
currentCharacterLog.system
){
if( !currentUserOnMap ){
currentUserIsHere = true;
currentUserOnMap = true;
characterLogExists = true;
headerUpdateData.currentLocation.name = currentCharacterLog.system.name;
}
// set current location data for header update
headerUpdateData.currentSystemId = $(system).data('id');
headerUpdateData.currentSystemName = currentCharacterLog.system.name;
// check if current user was found on the map
let currentUserOnMap = false;
// get all systems
let systems = mapElement.find('.' + config.systemClass);
for(let system of systems){
system = $(system);
let systemId = system.data('systemId');
let tempUserData = null;
// check if user is currently in "this" system
let currentUserIsHere = false;
let j = userData.data.systems.length;
// search backwards to avoid decrement the counter after splice()
while(j--){
let 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.userCountInside += 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(
characterLogExists &&
currentCharacterLog.system.id === systemId
){
if( !currentUserOnMap ){
currentUserIsHere = true;
currentUserOnMap = true;
// set current location data for header update
headerUpdateData.currentLocation.id = system.data('id');
headerUpdateData.currentLocation.name = currentCharacterLog.system.name;
}
}
system.updateSystemUserData(map, tempUserData, currentUserIsHere, {compactView: compactView});
}
// users who are not in any map system ----------------------------------------------------------------
for(let systemData of userData.data.systems){
// users without location are grouped in systemId: 0
if(systemData.id){
headerUpdateData.userCountOutside += systemData.user.length;
}else{
headerUpdateData.userCountInactive += systemData.user.length;
}
}
system.updateSystemUserData(map, tempUserData, currentUserIsHere, {compactView: compactView});
// trigger document event -> update header
$(document).trigger('pf:updateHeaderMapData', headerUpdateData);
}
// users who are not in any map system --------------------------------------------------------------------
for(let i = 0; i < userData.data.systems.length; i++){
// users without location are grouped in systemId: 0
if(userData.data.systems[i].id){
headerUpdateData.userCountOutside += userData.data.systems[i].user.length;
}else{
headerUpdateData.userCountInactive += userData.data.systems[i].user.length;
}
}
resolve(payload);
};
// trigger document event -> update header
$(document).trigger('pf:updateHeaderMapData', headerUpdateData);
}
return returnStatus;
return new Promise(updateUserDataExecutor);
};
/**
@@ -2851,17 +2919,7 @@ define([
updated: parseInt( system.data('updated') )
};
systemData.userCount = (system.data('userCount') ? parseInt( system.data('userCount') ) : 0);
// position ---------------------------------------------------------------------------------------------------
let positionData = {};
let currentX = system.css('left');
let 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;
systemData.position = MapUtil.getSystemPosition(system);
return systemData;
};
@@ -2982,6 +3040,7 @@ define([
return {
getMapInstance: getMapInstance,
loadMap: loadMap,
updateUserData: updateUserData,
saveSystemCallback: saveSystemCallback
};

View File

@@ -70,7 +70,7 @@ define([
};
/**
* scroll to a specific position in the map
* scroll to a specific position on map
* demo: http://manos.malihu.gr/repository/custom-scrollbar/demo/examples/scrollTo_demo.html
* @param position
*/
@@ -79,4 +79,31 @@ define([
$(this).mCustomScrollbar('scrollTo', position);
});
};
/**
* scroll to a specific system on map
* -> subtract some offset for tooltips/connections
* @param position
* @returns {*}
*/
$.fn.scrollToSystem = function(position){
position = getOffsetPosition(position, {x: -15, y: -35});
return this.each(function(){
$(this).mCustomScrollbar('scrollTo', position);
});
};
/**
* add/subtract offset coordinates from position
* -> no negative values returned
* @param position
* @param offset
* @returns {{x: number, y: number}}
*/
let getOffsetPosition = (position, offset) => {
return {
x: Math.max(0, position.x + offset.x),
y: Math.max(0, position.y + offset.y)
};
};
});

View File

@@ -482,7 +482,7 @@ define([
* @param label
* @returns {string}
*/
let getEndpointOverlayContent = (label) => {
let getEndpointOverlayContent = label => {
let newLabel = '';
let colorClass = 'txt-color-grayLighter';
@@ -508,17 +508,14 @@ define([
* @param element
* @returns {*}
*/
let getTabContentElementByMapElement = (element) => {
let tabContentElement = $(element).parents('.' + config.mapTabContentClass);
return tabContentElement;
};
let getTabContentElementByMapElement = element => $(element).closest('.' + config.mapTabContentClass);
/**
* checks if there is an "active" connection on a map
* @param map
* @returns {boolean}
*/
let hasActiveConnection = (map) => {
let hasActiveConnection = map => {
let activeConnections = getConnectionsByType(map, 'active');
return activeConnections.length > 0;
};
@@ -1203,6 +1200,21 @@ define([
return new Promise(setMapDefaultOptionsExecutor);
};
/**
* get system coordinates from systemElement
* @param system
* @returns {{x: number, y: number}}
*/
let getSystemPosition = system => {
let x = system.css('left');
let y = system.css('top');
return {
x: parseInt(x.substring(0, x.length - 2)),
y: parseInt(y.substring(0, y.length - 2))
};
};
/**
* scroll map to default (stored) x/y coordinates
* @param mapElement
@@ -1755,6 +1767,7 @@ define([
deleteLocalData: deleteLocalData,
visualizeMap: visualizeMap,
setMapDefaultOptions: setMapDefaultOptions,
getSystemPosition: getSystemPosition,
scrollToDefaultPosition: scrollToDefaultPosition,
getSystemId: getSystemId,
checkRight: checkRight,

View File

@@ -143,6 +143,7 @@ define([
Init.characterStatus = response.characterStatus;
Init.routes = response.routes;
Init.url = response.url;
Init.character = response.character;
Init.slack = response.slack;
Init.discord = response.discord;
Init.structureStatus = response.structureStatus;
@@ -308,10 +309,10 @@ define([
.then(payload => Promise.all([initMapModule(payload[0]), initMapWorker(payload[1])]))
.then(payload => {
// mapModule initialized and WebSocket configuration working
console.info('%s() complete! command: "%s"; syncStatus: "%s"',
payload[1].action,
payload[1].data.command,
payload[1].data.syncStatus
console.ok('Client syncStatus: %s. %O resolved by command: %s!',
payload[1].data.syncStatus,
payload[1].action + '()',
payload[1].data.command
);
})
.catch(payload => {
@@ -322,10 +323,10 @@ define([
break;
case 'initMapWorker':
// WebSocket not working -> no error here -> fallback to Ajax
console.warn('%s() rejects Promise. command: "%s"; syncStatus: "%s", payload: %o',
payload.action,
payload.data.command,
console.info('Client syncStatus: %s. %O rejected by command: %s! payload: %o',
payload.data.syncStatus,
payload.action + '()',
payload.data.command,
payload.data
);
break;

View File

@@ -458,7 +458,7 @@ define([
mapElement.trigger('pf:updateLocal', currentMapUserData);
// update map with current user data
mapElement.updateUserData(currentMapUserData);
Map.updateUserData(mapElement, currentMapUserData);
}
}

View File

@@ -491,7 +491,7 @@ define([
pageElement.prepend(headRendered);
// init header =====================================================================
// init header ================================================================================================
// init slide menus
let slideMenu = new $.slidebars({
@@ -516,7 +516,7 @@ define([
// current location
$('#' + Util.config.headCurrentLocationId).find('a').on('click', function(){
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: $(this).data('systemId') });
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: $(this).data('systemId')});
});
// program status
@@ -589,7 +589,7 @@ define([
pageElement.prepend(footerElement);
// init footer ==================================================
// init footer ================================================================================================
pageElement.find('.' + config.footerLicenceLinkClass).on('click', function(){
//show credits info dialog
$.fn.showCreditsDialog();
@@ -728,7 +728,7 @@ define([
return false;
});
// END menu events =============================================================================
// END menu events ============================================================================================
// global "popover" callback (for all popovers)
$('.' + Util.config.popoverTriggerClass).on('hide.bs.popover', function(e){
@@ -772,7 +772,7 @@ define([
userCountInside = data.userCountInside;
userCountOutside = data.userCountOutside;
userCountInactive = data.userCountInactive;
currentLocationData = data;
currentLocationData = data.currentLocation;
}
updateHeaderActiveUserCount(userCountInside, userCountOutside, userCountInactive);
updateHeaderCurrentLocation(currentLocationData);
@@ -825,7 +825,7 @@ define([
Util.showNotify({title: 'Logged out', text: data.reason, type: 'error'}, false);
// remove map -------------------------------------------------------
// remove map ---------------------------------------------------------------------------------------------
Util.getMapModule().velocity('fadeOut', {
duration: 300,
complete: function(){
@@ -933,7 +933,7 @@ define([
}
};
// check for character/ship changes ---------------------------------------------
// check for character/ship changes ---------------------------------------------------------------------------
if(
userData &&
userData.character
@@ -953,7 +953,7 @@ define([
return data.id;
});
// update user character data ---------------------------------------------------
// update user character data ---------------------------------------------------------------------------------
if(currentCharactersOptionIds.toString() !== newCharactersOptionIds.toString()){
let currentCharacterChanged = false;
@@ -976,7 +976,7 @@ define([
userInfoElement.data('characterOptionIds', newCharactersOptionIds);
}
// update user ship data --------------------------------------------------------
// update user ship data --------------------------------------------------------------------------------------
if(currentShipId !== newShipData.typeId){
// set new data for next check
userShipElement.data('shipData', newShipData);
@@ -1058,37 +1058,46 @@ define([
};
/**
* update the "current location" element in head
* update the "current location" link element in head
* @param locationData
*/
let updateHeaderCurrentLocation = function(locationData){
let currentLocationElement = $('#' + Util.config.headCurrentLocationId);
let linkElement = currentLocationElement.find('a');
let textElement = linkElement.find('span');
let updateHeaderCurrentLocation = locationData => {
let systemId = locationData.id || 0;
let systemName = locationData.name || false;
let tempSystemName = (locationData.currentSystemName) ? locationData.currentSystemName : false;
let tempSystemId = (locationData.currentSystemId) ? locationData.currentSystemId : 0;
let currentLocationData = Util.getCurrentLocationData();
if(
linkElement.data('systemName') !== tempSystemName ||
linkElement.data('systemId') !== tempSystemId
currentLocationData.name !== systemName ||
currentLocationData.id !== systemId
){
linkElement.data('systemName', tempSystemName);
linkElement.data('systemId', tempSystemId);
linkElement.toggleClass('disabled', !tempSystemId);
Util.setCurrentLocationData(systemId, systemName);
if(tempSystemName !== false){
textElement.text(locationData.currentSystemName);
let currentLocationElement = $('#' + Util.config.headCurrentLocationId);
let linkElement = currentLocationElement.find('a');
linkElement.toggleClass('disabled', !systemId);
if(systemName !== false){
linkElement.find('span').text(locationData.name);
currentLocationElement.velocity('fadeIn', {duration: Init.animationSpeed.headerLink});
}else{
if(currentLocationElement.is(':visible')){
currentLocationElement.velocity('fadeOut', {duration: Init.animationSpeed.headerLink});
}
}
// auto select current system -----------------------------------------------------------------------------
let userData = Util.getCurrentUserData();
if(
Boolean(Util.getObjVal(Init, 'character.autoLocationSelect')) &&
Util.getObjVal(userData, 'character.selectLocation')
){
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: systemId, forceSelect: false});
}
}
};
/**
* shows a test notification for desktop messages
*/

View File

@@ -55,6 +55,7 @@ define([
formErrorContainerClass: Util.config.formErrorContainerClass,
ccpImageServer: Init.url.ccpImageServer,
roleLabel: Util.getLabelByRole(Util.getObjVal(Util.getCurrentUserData(), 'character.role')).prop('outerHTML'),
characterAutoLocationSelectEnabled: Boolean(Util.getObjVal(Init, 'character.autoLocationSelect'))
};
let content = Mustache.render(template, data);

View File

@@ -307,7 +307,7 @@ define([
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
// select system
$(cell).on('click', function(e){
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: rowData.id });
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: rowData.id});
});
}
},{
@@ -597,7 +597,7 @@ define([
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
// select system
$(cell).on('click', function(e){
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: rowData.source.id });
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: rowData.source.id});
});
}
},{
@@ -615,7 +615,7 @@ define([
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
// select system
$(cell).on('click', function(e){
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: rowData.target.id });
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: rowData.target.id});
});
}
},{

View File

@@ -168,7 +168,7 @@ define([
class: 'pf-link',
html: connectionData.sourceAlias + '&nbsp;&nbsp;'
}).on('click', function(){
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: connectionData.source });
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: connectionData.source});
}),
$('<span>', {
class: [config.connectionInfoTableLabelSourceClass].join(' ')
@@ -183,7 +183,7 @@ define([
class: 'pf-link',
html: '&nbsp;&nbsp;' + connectionData.targetAlias
}).on('click', function(){
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: connectionData.target });
Util.getMapModule().getActiveMap().triggerMenuEvent('SelectSystem', {systemId: connectionData.target});
})
)
)

View File

@@ -39,7 +39,7 @@ define([
// description field
descriptionAreaClass: 'pf-system-info-description-area', // class for "description" area
addDescriptionButtonClass: 'pf-system-info-description-button', // class for "add description" button
descriptionTextareaElementClass: 'pf-system-info-description', // class for "description" textarea element (xEditable)
descriptionTextareaElementClass: 'pf-system-info-description', // class for "description" textarea element (Summernote)
// fonts
fontTriglivianClass: 'pf-triglivian', // class for "Triglivian" names (e.g. Abyssal systems)
@@ -177,6 +177,7 @@ define([
descriptionAreaClass: config.descriptionAreaClass,
descriptionButtonClass: config.addDescriptionButtonClass,
descriptionTextareaClass: config.descriptionTextareaElementClass,
summernoteClass: Util.config.summernoteClass,
systemNameClass: () => {
return (val, render) => {
return render(val) === 'A' ? config.fontTriglivianClass : '';
@@ -298,7 +299,7 @@ define([
},
callbacks: {
onInit: function(context){
// make editable field a big larger
// make editable field a bit larger
context.editable.css('height', '150px');
// set default background color

View File

@@ -4,6 +4,7 @@
define([
'jquery',
'app/init',
'app/console',
'conf/system_effect',
'conf/signature_type',
'bootbox',
@@ -18,7 +19,7 @@ define([
'bootstrapConfirmation',
'bootstrapToggle',
'select2'
], ($, Init, SystemEffect, SignatureType, bootbox, localforage) => {
], ($, Init, Con, SystemEffect, SignatureType, bootbox, localforage) => {
'use strict';
@@ -83,6 +84,9 @@ define([
popoverSmallClass: 'pf-popover-small', // class for small "popover"
popoverCharacterClass: 'pf-popover-character', // class for character "popover"
// Summernote
summernoteClass: 'pf-summernote', // class for Summernote "WYSIWYG" elements
// help
helpDefaultClass: 'pf-help-default', // class for "help" tooltip elements
helpClass: 'pf-help', // class for "help" tooltip elements
@@ -878,9 +882,7 @@ define([
/**
* show current program version information in browser console
*/
let showVersionInfo = () => {
console.info('PATHFINDER ' + getVersion());
};
let showVersionInfo = () => Con.showVersionInfo(getVersion());
/**
* polyfill for "passive" events
@@ -2771,16 +2773,28 @@ define([
return Init.currentSystemData;
};
/**
* set current location data
* -> system data where current user is located
* @param systemId
* @param systemName
*/
let setCurrentLocationData = (systemId, systemName) => {
let locationLink = $('#' + config.headCurrentLocationId).find('a');
locationLink.data('systemId', systemId);
locationLink.data('systemName', systemName);
};
/**
* get current location data
* -> system data where current user is located
* @returns {{id: *, name: *}}
*/
let getCurrentLocationData = () => {
let currentLocationLink = $('#' + config.headCurrentLocationId).find('a');
let locationLink = $('#' + config.headCurrentLocationId).find('a');
return {
id: currentLocationLink.data('systemId'),
name: currentLocationLink.data('systemName')
id: locationLink.data('systemId') || 0,
name: locationLink.data('systemName') || false
};
};
@@ -3012,6 +3026,13 @@ define([
return Array.from(doc.body.childNodes).some(node => node.nodeType === 1);
};
/**
* checks if a given object is a DOM element
* @param obj
* @returns {boolean}
*/
let isDomElement = obj => !!(obj && obj.nodeType === 1);
/**
* get deep json object value if exists
* -> e.g. key = 'first.last.third' string
@@ -3189,6 +3210,7 @@ define([
getCurrentCharacterId: getCurrentCharacterId,
setCurrentSystemData: setCurrentSystemData,
getCurrentSystemData: getCurrentSystemData,
setCurrentLocationData: setCurrentLocationData,
getCurrentLocationData: getCurrentLocationData,
getCurrentUserInfo: getCurrentUserInfo,
getCurrentCharacterLog: getCurrentCharacterLog,
@@ -3216,6 +3238,7 @@ define([
htmlEncode: htmlEncode,
htmlDecode: htmlDecode,
isValidHtml: isValidHtml,
isDomElement: isDomElement,
getObjVal: getObjVal,
redirect: redirect,
logout: logout,

View File

@@ -227,17 +227,36 @@
<h4 class="pf-dynamic-area"><img src="{{ccpImageServer}}/Character/{{id}}_64.jpg">&nbsp;&nbsp;{{name}}&nbsp;&nbsp;{{{roleLabel}}}</h4>
<div class="row">
<div class="col-xs-8 col-sm-6">
<div class="col-xs-12 col-sm-6">
<div class="form-group">
<div class="col-sm-offset-1 col-sm-11">
<div class="checkbox checkbox-primary" title="show/share current location on map">
<div class="checkbox checkbox-primary">
<input id="logLocation" name="logLocation" value="1" type="checkbox" {{#logLocation}}checked{{/logLocation}}>
<label for="logLocation">Auto update current location</label>
<label for="logLocation">
Auto update current location
<i class="fas fa-fw fa-question-circle pf-help-light" title="show/share current location on map"></i>
</label>
</div>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6">
<div class="form-group">
<div class="col-sm-12">
<div class="checkbox checkbox-warning" {{^characterAutoLocationSelectEnabled}}title="Globally disabled for all characters"{{/characterAutoLocationSelectEnabled}}>
<input id="selectLocation" name="selectLocation" value="1" type="checkbox" {{#selectLocation}}checked{{/selectLocation}} {{^characterAutoLocationSelectEnabled}}disabled{{/characterAutoLocationSelectEnabled}}>
<label for="selectLocation">
Auto select current location
<i class="fas fa-fw fa-question-circle pf-help-light" title="Auto select current system after jump.
Unsaved changes (e.g. system description) will be discarded!"
></i>
<span class="badge bg-color bg-color-grayDarker txt-color txt-color-warning">beta</span>
</label>
</div>
</div>
</div>
</div>
<div class="col-sm-6"></div>
</div>
<input type="hidden" name="character">

View File

@@ -38,7 +38,7 @@
{{! info text ================================================================================================ }}
<div class="col-xs-12 col-sm-9">
<div class="pf-dynamic-area {{descriptionAreaClass}}">
<div class="{{descriptionTextareaClass}}"></div>
<div class="{{descriptionTextareaClass}} {{summernoteClass}}"></div>
<i class="fas fa-fw fa-lg fa-pen pull-right {{moduleHeadlineIconClass}} {{descriptionButtonClass}}" data-toggle="tooltip" title="edit description"></i>
</div>
</div>

View File

@@ -143,6 +143,22 @@
@include rotate( -90deg );
}
// rainbow background =============================================================================
@keyframes rotateRainbow{
0%{
background-position-x: 0;
}
100%{
background-position-x: 100vw;
}
}
@mixin rainbow(){
background: repeating-linear-gradient(-45deg, $green-light 0%, $teal-lighter 12.5%, $teal-lightest 25%, $green 37.5%, $green-light 50%);
background-size:100vw 100vw;
@include animation(rotateRainbow 3s infinite linear forwards);
}
// navigation link active/hover indicator =========================================================
@mixin navigation-active-indicator($position) {
content: '';

View File

@@ -12,7 +12,8 @@
left: 0;
width: 100%;
height: 3px;
@include background-image(linear-gradient(to right, $green-light, $green-light 100%));
@include rainbow;
&.warning{
@include background-image(linear-gradient(to right, $brand-warning, $brand-warning 100%));

View File

@@ -89,7 +89,7 @@ $mapWrapperMaxWidth: $mapWidth + 35px;
position: absolute;
display: none; // triggered by js
z-index: 10000;
right: 26px;
right: 25px;
background: rgba($black, 0.25);
@include border-radius(5px);