- NEW "Thera connections" UI module, closed #829
- Upgraded "[_pathfinder_esi_](https://github.com/exodus4d/pathfinder_esi)" Web API client`v1.3.2` → `v2.0.0` - Fixed a js bug where current active(selected) system becomes deselected after system was dragged on map - Fixed a js bug where new auto mapped systems (e.g. after jump) were positioned outside current map scroll viewport - Fixed a js bug where map sync failed after map tabs switch - Fixed blurry map when map zoom was changed - Fixed multiple minor JS bugs where map render/update failed
This commit is contained in:
@@ -35,7 +35,7 @@ class GitHub extends Controller\Controller {
|
||||
$return->version->delta = null;
|
||||
$return->version->dev = false;
|
||||
|
||||
$releases = $f3->gitHubClient()->getProjectReleases('exodus4d/pathfinder', $releaseCount);
|
||||
$releases = $f3->gitHubClient()->send('getProjectReleases', 'exodus4d/pathfinder', $releaseCount);
|
||||
|
||||
foreach($releases as $key => &$release){
|
||||
// check version ------------------------------------------------------------------------------------------
|
||||
@@ -67,7 +67,7 @@ class GitHub extends Controller\Controller {
|
||||
|
||||
// convert Markdown to HTML -> use either gitHub API (in oder to create abs, issue links)
|
||||
// -> or F3´s markdown as fallback
|
||||
$html = $f3->gitHubClient()->markdownToHtml('exodus4d/pathfinder', $body);
|
||||
$html = $f3->gitHubClient()->send('markdownToHtml', 'exodus4d/pathfinder', $body);
|
||||
|
||||
if(!empty($html)){
|
||||
$body = $html;
|
||||
|
||||
@@ -179,7 +179,8 @@ class Map extends Controller\AccessController {
|
||||
'zKillboard' => Config::getPathfinderData('api.z_killboard'),
|
||||
'eveeye' => Config::getPathfinderData('api.eveeye'),
|
||||
'dotlan' => Config::getPathfinderData('api.dotlan'),
|
||||
'anoik' => Config::getPathfinderData('api.anoik')
|
||||
'anoik' => Config::getPathfinderData('api.anoik'),
|
||||
'eveScout' => Config::getPathfinderData('api.eve_scout')
|
||||
];
|
||||
|
||||
// get Plugin config --------------------------------------------------------------------------------------
|
||||
|
||||
@@ -93,10 +93,16 @@ class Connection extends AbstractRestController {
|
||||
$connection->mapId = $map;
|
||||
$connection->source = $source;
|
||||
$connection->target = $target;
|
||||
$connection->copyfrom($connectionData, ['scope', 'type']);
|
||||
|
||||
// change the default type for the new connection
|
||||
$connection->setDefaultTypeData();
|
||||
// if scope + type data send -> use them ...
|
||||
if($requestData['scope'] && !empty($requestData['type'])){
|
||||
$connection->copyfrom($requestData, ['scope', 'type']);
|
||||
}
|
||||
|
||||
// ... set/change default scope + type
|
||||
if(!$requestData['disableAutoScope']){
|
||||
$connection->setAutoScopeAndType();
|
||||
}
|
||||
|
||||
if($connection->save($activeCharacter)){
|
||||
$connectionData = $connection->getData();
|
||||
|
||||
@@ -14,7 +14,7 @@ class Route extends AbstractRestController {
|
||||
/**
|
||||
* cache key for current Thera connections from eve-scout.com
|
||||
*/
|
||||
const CACHE_KEY_THERA_CONNECTIONS = 'CACHED_THERA_CONNECTIONS';
|
||||
const CACHE_KEY_THERA_JUMP_DATA = 'CACHED_THERA_JUMP_DATA';
|
||||
|
||||
/**
|
||||
* route search depth
|
||||
@@ -260,9 +260,9 @@ class Route extends AbstractRestController {
|
||||
* -> Connected wormholes pulled from eve-scout.com
|
||||
*/
|
||||
private function setTheraJumpData(){
|
||||
if(!$this->getF3()->exists(self::CACHE_KEY_THERA_CONNECTIONS, $jumpData)){
|
||||
if(!$this->getF3()->exists(self::CACHE_KEY_THERA_JUMP_DATA, $jumpData)){
|
||||
$jumpData = [];
|
||||
$connectionsData = $this->getF3()->eveScoutClient()->getTheraConnections();
|
||||
$connectionsData = $this->getF3()->eveScoutClient()->send('getTheraConnections');
|
||||
|
||||
if(!empty($connectionsData) && !isset($connectionsData['error'])){
|
||||
/**
|
||||
@@ -294,12 +294,12 @@ class Route extends AbstractRestController {
|
||||
};
|
||||
|
||||
foreach((array)$connectionsData['connections'] as $connectionData){
|
||||
$enrichJumpData($connectionData, 'source', 'target');
|
||||
$enrichJumpData($connectionData, 'target', 'source');
|
||||
$enrichJumpData($connectionData, 'source', 'target');
|
||||
$enrichJumpData($connectionData, 'target', 'source');
|
||||
}
|
||||
|
||||
if(!empty($jumpData)){
|
||||
$this->getF3()->set(self::CACHE_KEY_THERA_CONNECTIONS, $jumpData, $this->theraJumpDataCacheTime);
|
||||
$this->getF3()->set(self::CACHE_KEY_THERA_JUMP_DATA, $jumpData, $this->theraJumpDataCacheTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -337,7 +337,7 @@ class Route extends AbstractRestController {
|
||||
if( !is_array($this->jumpArray[$systemId]) ){
|
||||
$this->jumpArray[$systemId] = [];
|
||||
}
|
||||
$this->jumpArray[$systemId] = array_merge($row['jumpNodes'], $this->jumpArray[$systemId]);
|
||||
$this->jumpArray[$systemId] = array_merge((array)$row['jumpNodes'], $this->jumpArray[$systemId]);
|
||||
|
||||
// add systemName to end (if not already there)
|
||||
if(end($this->jumpArray[$systemId]) != $systemName){
|
||||
@@ -668,7 +668,7 @@ class Route extends AbstractRestController {
|
||||
'connections' => $connections
|
||||
];
|
||||
|
||||
$result = $this->getF3()->ccpClient()->getRouteData($systemFromId, $systemToId, $options);
|
||||
$result = $this->getF3()->ccpClient()->send('getRoute', $systemFromId, $systemToId, $options);
|
||||
|
||||
// format result ------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
131
app/Controller/Api/Rest/SystemThera.php
Normal file
131
app/Controller/Api/Rest/SystemThera.php
Normal file
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Exodus4D\Pathfinder\Controller\Api\Rest;
|
||||
|
||||
use Exodus4D\Pathfinder\Lib\Config;
|
||||
|
||||
class SystemThera extends AbstractRestController {
|
||||
|
||||
/**
|
||||
* cache key for HTTP response
|
||||
*/
|
||||
const CACHE_KEY_THERA_CONNECTIONS = 'CACHED_THERA_CONNECTIONS';
|
||||
|
||||
/**
|
||||
* get Thera connections data from Eve-Scout
|
||||
* @param \Base $f3
|
||||
*/
|
||||
public function get(\Base $f3){
|
||||
$ttl = 60 * 3;
|
||||
if(!$exists = $f3->exists(self::CACHE_KEY_THERA_CONNECTIONS, $connectionsData)){
|
||||
$connectionsData = $this->getEveScoutTheraConnections();
|
||||
$f3->set(self::CACHE_KEY_THERA_CONNECTIONS, $connectionsData, $ttl);
|
||||
}
|
||||
|
||||
$f3->expire(Config::ttlLeft($exists, $ttl));
|
||||
|
||||
$this->out($connectionsData);
|
||||
}
|
||||
|
||||
/**
|
||||
* get Thera connections data from EveScout API
|
||||
* -> map response to Pathfinder format
|
||||
* @return array
|
||||
*/
|
||||
protected function getEveScoutTheraConnections() : array {
|
||||
$connectionsData = [];
|
||||
|
||||
/**
|
||||
* map system data from eveScout response to Pathfinder´s 'system' format
|
||||
* @param string $key
|
||||
* @param array $eveScoutConnection
|
||||
* @param array $connectionData
|
||||
*/
|
||||
$enrichWithSystemData = function(string $key, array $eveScoutConnection, array &$connectionData) : void {
|
||||
$eveScoutSystem = (array)$eveScoutConnection[$key];
|
||||
$systemData = [
|
||||
'id' => (int)$eveScoutSystem['id'],
|
||||
'name' => (string)$eveScoutSystem['name'],
|
||||
'trueSec' => round((float)$eveScoutSystem['security'], 4)
|
||||
];
|
||||
if(!empty($eveScoutSystem['constellationID'])){
|
||||
$systemData['constellation'] = ['id' => (int)$eveScoutSystem['constellationID']];
|
||||
}
|
||||
if(!empty($region = (array)$eveScoutSystem['region']) && !empty($region['id'])){
|
||||
$systemData['region'] = ['id' => (int)$region['id'], 'name' => (string)$region['name']];
|
||||
}
|
||||
$connectionData[$key] = $systemData;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param array $eveScoutConnection
|
||||
* @param array $connectionData
|
||||
*/
|
||||
$enrichWithSignatureData = function(string $key, array $eveScoutConnection, array &$connectionData) : void {
|
||||
$eveScoutSignature = (array)$eveScoutConnection[$key];
|
||||
$signatureData = [
|
||||
'name' => $eveScoutSignature['name'] ? : null
|
||||
];
|
||||
if(!empty($sigType = (array)$eveScoutSignature['type']) && !empty($sigType['name'])){
|
||||
$signatureData['type'] = ['name' => strtoupper((string)$sigType['name'])];
|
||||
}
|
||||
$connectionData[$key] = $signatureData;
|
||||
};
|
||||
|
||||
/**
|
||||
* map wormhole data from eveScout to Pathfinder´s connection format
|
||||
* @param array $wormholeData
|
||||
* @param array $connectionsData
|
||||
*/
|
||||
$enrichWithWormholeData = function(array $wormholeData, array &$connectionsData) : void {
|
||||
$type = [];
|
||||
if($wormholeData['mass'] === 'reduced'){
|
||||
$type[] = 'wh_reduced';
|
||||
}else if($wormholeData['mass'] === 'critical'){
|
||||
$type[] = 'wh_critical';
|
||||
}else{
|
||||
$type[] = 'wh_fresh';
|
||||
}
|
||||
|
||||
if($wormholeData['eol'] === 'critical'){
|
||||
$type[] = 'wh_eol';
|
||||
}
|
||||
$connectionsData['type'] = $type;
|
||||
$connectionsData['estimatedEol'] = $wormholeData['estimatedEol'];
|
||||
};
|
||||
|
||||
$eveScoutResponse = $this->getF3()->eveScoutClient()->send('getTheraConnections');
|
||||
if(!empty($eveScoutResponse) && !isset($eveScoutResponse['error'])){
|
||||
foreach((array)$eveScoutResponse['connections'] as $eveScoutConnection){
|
||||
if(
|
||||
$eveScoutConnection['type'] === 'wormhole' &&
|
||||
isset($eveScoutConnection['source']) && isset($eveScoutConnection['target'])
|
||||
){
|
||||
try{
|
||||
$data = [
|
||||
'id' => (int)$eveScoutConnection['id'],
|
||||
'scope' => 'wh',
|
||||
'created' => [
|
||||
'created' => (new \DateTime($eveScoutConnection['created']))->getTimestamp(),
|
||||
'character' => (array)$eveScoutConnection['character']
|
||||
],
|
||||
'updated' => (new \DateTime($eveScoutConnection['updated']))->getTimestamp()
|
||||
];
|
||||
$enrichWithWormholeData((array)$eveScoutConnection['wormhole'], $data);
|
||||
$enrichWithSystemData('source', $eveScoutConnection, $data);
|
||||
$enrichWithSystemData('target', $eveScoutConnection, $data);
|
||||
$enrichWithSignatureData('sourceSignature', $eveScoutConnection, $data);
|
||||
$enrichWithSignatureData('targetSignature', $eveScoutConnection, $data);
|
||||
$connectionsData[] = $data;
|
||||
}catch(\Exception $e){
|
||||
// new \DateTime Exception -> skip this data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $connectionsData;
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,7 @@ class System extends Controller\AccessController {
|
||||
];
|
||||
|
||||
foreach($destData as $data){
|
||||
$response = $f3->ccpClient()->setWaypoint((int)$data['id'], $accessToken, $options);
|
||||
$response = $f3->ccpClient()->send('setWaypoint', (int)$data['id'], $accessToken, $options);
|
||||
|
||||
if(empty($response)){
|
||||
$return->destData[] = $data;
|
||||
|
||||
@@ -215,7 +215,7 @@ class User extends Controller\Controller{
|
||||
if( $targetId = (int)$data['targetId']){
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
$response = $f3->ccpClient()->openWindow($targetId, $activeCharacter->getAccessToken());
|
||||
$response = $f3->ccpClient()->send('openWindow', $targetId, $activeCharacter->getAccessToken());
|
||||
|
||||
if(empty($response)){
|
||||
$return->targetId = $targetId;
|
||||
|
||||
@@ -390,7 +390,7 @@ class Sso extends Api\User{
|
||||
$accessData->refreshToken = null;
|
||||
$accessData->esiAccessTokenExpires = 0;
|
||||
|
||||
$authCodeRequestData = $this->getF3()->ssoClient()->getAccessData($this->getAuthorizationData(), $requestParams);
|
||||
$authCodeRequestData = $this->getF3()->ssoClient()->send('getAccess', $this->getAuthorizationData(), $requestParams);
|
||||
|
||||
if( !empty($authCodeRequestData) ){
|
||||
if( !empty($authCodeRequestData['accessToken']) ){
|
||||
@@ -429,7 +429,7 @@ class Sso extends Api\User{
|
||||
* @return array
|
||||
*/
|
||||
public function verifyCharacterData(string $accessToken) : array {
|
||||
$characterData = $this->getF3()->ssoClient()->getVerifyCharacterData($accessToken);
|
||||
$characterData = $this->getF3()->ssoClient()->send('getVerifyCharacter', $accessToken);
|
||||
|
||||
if( !empty($characterData) ){
|
||||
// convert string with scopes to array
|
||||
@@ -451,8 +451,7 @@ class Sso extends Api\User{
|
||||
$characterData = (object) [];
|
||||
|
||||
if($characterId){
|
||||
$characterDataBasic = $this->getF3()->ccpClient()->getCharacterData($characterId);
|
||||
|
||||
$characterDataBasic = $this->getF3()->ccpClient()->send('getCharacter', $characterId);
|
||||
if( !empty($characterDataBasic) ){
|
||||
// remove some "unwanted" data -> not relevant for Pathfinder
|
||||
$characterData->character = array_filter($characterDataBasic, function($key){
|
||||
|
||||
@@ -22,7 +22,7 @@ class Universe extends Controller\Controller {
|
||||
$regionsWhitelist = [
|
||||
10000002 // The Forge (13 constellations -> 93 systems)
|
||||
];
|
||||
$regionIds = $f3->ccpClient()->getUniverseRegions();
|
||||
$regionIds = $f3->ccpClient()->send('getUniverseRegions');
|
||||
$regionIds = array_intersect($regionsWhitelist, $regionIds);
|
||||
|
||||
$region = Model\Universe\AbstractUniverseModel::getNew('RegionModel');
|
||||
@@ -43,7 +43,7 @@ class Universe extends Controller\Controller {
|
||||
$constellationsWhitelist = [
|
||||
20000014 // Mal (11 systems)
|
||||
];
|
||||
$constellationIds = $f3->ccpClient()->getUniverseConstellations();
|
||||
$constellationIds = $f3->ccpClient()->send('getUniverseConstellations');
|
||||
$constellationIds = array_intersect($constellationsWhitelist, $constellationIds);
|
||||
$constellation = Model\Universe\AbstractUniverseModel::getNew('ConstellationModel');
|
||||
foreach($constellationIds as $constellationId){
|
||||
@@ -306,13 +306,13 @@ class Universe extends Controller\Controller {
|
||||
$f3 = \Base::instance();
|
||||
$universeNameData = [];
|
||||
if( !empty($categories) && !empty($search)){
|
||||
$universeIds = $f3->ccpClient()->search($categories, $search, $strict);
|
||||
$universeIds = $f3->ccpClient()->send('search', $categories, $search, $strict);
|
||||
if(isset($universeIds['error'])){
|
||||
// ESI error
|
||||
$universeNameData = $universeIds;
|
||||
}elseif( !empty($universeIds) ){
|
||||
$universeIds = Util::arrayFlattenByValue($universeIds);
|
||||
$universeNameData = $f3->ccpClient()->getUniverseNamesData($universeIds);
|
||||
$universeNameData = $f3->ccpClient()->send('getUniverseNames', $universeIds);
|
||||
}
|
||||
}
|
||||
return $universeNameData;
|
||||
|
||||
@@ -565,7 +565,7 @@ class Controller {
|
||||
'routes' => []
|
||||
];
|
||||
|
||||
$serverStatus = $client->getServerStatus();
|
||||
$serverStatus = $client->send('getServerStatus');
|
||||
if( !isset($serverStatus['error']) ){
|
||||
$statusData = $serverStatus['status'];
|
||||
// calculate time diff since last server restart
|
||||
@@ -587,7 +587,7 @@ class Controller {
|
||||
$return->error[] = (new PathfinderException($serverStatus['error'], 500))->getError();
|
||||
}
|
||||
|
||||
$apiStatus = $client->getStatusForRoutes('latest');
|
||||
$apiStatus = $client->send('getStatus', 'latest', true);
|
||||
if( !isset($apiStatus['error']) ){
|
||||
// find top status
|
||||
$status = 'OK';
|
||||
|
||||
@@ -119,13 +119,13 @@ class CcpSystemsUpdate extends AbstractCron {
|
||||
|
||||
// get current jump data --------------------------------------------------------------------------------------
|
||||
$time_start = microtime(true);
|
||||
$jumpData = $f3->ccpClient()->getUniverseJumps();
|
||||
$jumpData = $f3->ccpClient()->send('getUniverseJumps');
|
||||
$time_end = microtime(true);
|
||||
$execTimeGetJumpData = $time_end - $time_start;
|
||||
|
||||
// get current kill data --------------------------------------------------------------------------------------
|
||||
$time_start = microtime(true);
|
||||
$killData = $f3->ccpClient()->getUniverseKills();
|
||||
$killData = $f3->ccpClient()->send('getUniverseKills');
|
||||
$time_end = microtime(true);
|
||||
$execTimeGetKillData = $time_end - $time_start;
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ class Universe extends AbstractCron {
|
||||
switch($type){
|
||||
case 'system':
|
||||
// load systems + dependencies (planets, star, types,...)
|
||||
$ids = $f3->ccpClient()->getUniverseSystems();
|
||||
$ids = $f3->ccpClient()->send('getUniverseSystems');
|
||||
$modelClass = 'SystemModel';
|
||||
$setupModel = function(Model\Universe\SystemModel &$model, int $id){
|
||||
$model->loadById($id);
|
||||
@@ -195,7 +195,7 @@ class Universe extends AbstractCron {
|
||||
break;
|
||||
case 'stargate':
|
||||
// load all stargates. Systems must be present first!
|
||||
$ids = $f3->ccpClient()->getUniverseSystems();
|
||||
$ids = $f3->ccpClient()->send('getUniverseSystems');
|
||||
$modelClass = 'SystemModel';
|
||||
$setupModel = function(Model\Universe\SystemModel &$model, int $id){
|
||||
$model->loadById($id);
|
||||
@@ -203,7 +203,7 @@ class Universe extends AbstractCron {
|
||||
};
|
||||
break;
|
||||
case 'station':
|
||||
$ids = $f3->ccpClient()->getUniverseSystems();
|
||||
$ids = $f3->ccpClient()->send('getUniverseSystems');
|
||||
$modelClass = 'SystemModel';
|
||||
$setupModel = function(Model\Universe\SystemModel &$model, int $id){
|
||||
if($model->getById($id)){
|
||||
@@ -216,7 +216,7 @@ class Universe extends AbstractCron {
|
||||
break;
|
||||
case 'sovereignty':
|
||||
// load sovereignty map data. Systems must be present first!
|
||||
$sovData = $f3->ccpClient()->getSovereigntyMap();
|
||||
$sovData = $f3->ccpClient()->send('getSovereigntyMap');
|
||||
$ids = !empty($sovData = $sovData['map']) ? array_keys($sovData): [];
|
||||
$modelClass = 'SystemModel';
|
||||
$setupModel = function(Model\Universe\SystemModel &$model, int $id) use ($sovData) {
|
||||
@@ -229,7 +229,7 @@ class Universe extends AbstractCron {
|
||||
};
|
||||
break;
|
||||
case 'faction_war_systems':
|
||||
$fwSystems = $f3->ccpClient()->getFactionWarSystems();
|
||||
$fwSystems = $f3->ccpClient()->send('getFactionWarSystems');
|
||||
$ids = !empty($fwSystems = $fwSystems['systems']) ? array_keys($fwSystems): [];
|
||||
$modelClass = 'SystemModel';
|
||||
$setupModel = function(Model\Universe\SystemModel &$model, int $id) use ($fwSystems) {
|
||||
@@ -243,7 +243,7 @@ class Universe extends AbstractCron {
|
||||
break;
|
||||
case 'index_system':
|
||||
// setup system index, Systems must be present first!
|
||||
$ids = $f3->ccpClient()->getUniverseSystems();
|
||||
$ids = $f3->ccpClient()->send('getUniverseSystems');
|
||||
$modelClass = 'SystemModel';
|
||||
$setupModel = function(Model\Universe\SystemModel &$model, int $id){
|
||||
$model->getById($id); // no loadById() here! would take "forever" when system not exists and must be build up first...
|
||||
@@ -310,8 +310,8 @@ class Universe extends AbstractCron {
|
||||
*/
|
||||
$system = Model\Universe\AbstractUniverseModel::getNew('SystemModel');
|
||||
|
||||
$sovData = $f3->ccpClient()->getSovereigntyMap();
|
||||
$fwSystems = $f3->ccpClient()->getFactionWarSystems();
|
||||
$sovData = $f3->ccpClient()->send('getSovereigntyMap');
|
||||
$fwSystems = $f3->ccpClient()->send('getFactionWarSystems');
|
||||
$fwSystems = $fwSystems['systems'];
|
||||
$ids = !empty($sovData = $sovData['map']) ? array_keys($sovData): [];
|
||||
sort($ids, SORT_NUMERIC);
|
||||
|
||||
@@ -298,8 +298,8 @@ abstract class AbstractClient extends \Prefab {
|
||||
public function __call(string $name, array $arguments = []){
|
||||
$return = [];
|
||||
if(is_object($this->client)){
|
||||
if( method_exists($this->client, $name) ){
|
||||
$return = call_user_func_array([$this->client, $name], $arguments);
|
||||
if(method_exists($this->client, $name)){
|
||||
$return = call_user_func_array([$this->client, $name], $arguments);
|
||||
}else{
|
||||
$errorMsg = $this->getMissingMethodError(get_class($this->client), $name);
|
||||
$this->getLogger('ERROR')->write($errorMsg);
|
||||
@@ -336,18 +336,20 @@ abstract class AbstractClient extends \Prefab {
|
||||
$client->setNewLog($this->newLog());
|
||||
$client->setIsLoggable($this->isLoggable($f3));
|
||||
|
||||
$client->setLogStats(true); // add cURL stats (e.g. transferTime) to logged requests
|
||||
$client->setLogCache(true); // add cache info (e.g. from cached) to logged requests
|
||||
//$client->setLogAllStatus(true); // log all requests regardless of response HTTP status code
|
||||
$client->setLogFile('esi_requests');//
|
||||
$client->setLogStats(true); // add cURL stats (e.g. transferTime) to loggable requests
|
||||
$client->setLogCache(true); // add cache info (e.g. from cached) to loggable requests
|
||||
$client->setLogAllStatus(false); // log all requests regardless of response HTTP status code
|
||||
$client->setLogRequestHeaders(false); // add request HTTP headers to loggable requests
|
||||
$client->setLogResponseHeaders(false); // add response HTTP headers to loggable requests
|
||||
$client->setLogFile('esi_requests');
|
||||
|
||||
$client->setRetryLogFile('esi_retry_requests');
|
||||
|
||||
$client->setCacheDebug(true);
|
||||
$client->setCachePool($this->getCachePool($f3));
|
||||
|
||||
// use local proxy server for debugging requests
|
||||
//$client->setProxy('127.0.0.1:8888');
|
||||
|
||||
//$client->setProxy('127.0.0.1:8888'); // use local proxy server for debugging requests
|
||||
|
||||
// disable SSL certificate verification -> allow proxy to decode(view) request
|
||||
//$client->setVerify(false);
|
||||
|
||||
@@ -11,14 +11,13 @@ namespace Exodus4D\Pathfinder\Lib\Api;
|
||||
use Exodus4D\Pathfinder\Lib\Config;
|
||||
use Exodus4D\ESI\Client\ApiInterface;
|
||||
use Exodus4D\ESI\Client\Ccp\Esi\Esi as Client;
|
||||
use Exodus4D\ESI\Client\Ccp\Esi\EsiInterface as ClientInterface;
|
||||
|
||||
/**
|
||||
* Class CcpClient
|
||||
* @package lib\api
|
||||
*
|
||||
* @method ClientInterface getServerStatus()
|
||||
* @method ClientInterface getStatusForRoutes(string $version)
|
||||
* @method ApiInterface send(string $requestHandler, ...$handlerParams)
|
||||
* @method ApiInterface sendBatch(array $configs)
|
||||
*/
|
||||
class CcpClient extends AbstractClient {
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@ namespace Exodus4D\Pathfinder\Lib\Api;
|
||||
use Exodus4D\Pathfinder\Lib\Config;
|
||||
use Exodus4D\ESI\Client\ApiInterface;
|
||||
use Exodus4D\ESI\Client\EveScout\EveScout as Client;
|
||||
use Exodus4D\ESI\Client\EveScout\EveScoutInterface as ClientInterface;
|
||||
|
||||
/**
|
||||
* Class EveScoutClient
|
||||
* @package lib\api
|
||||
*
|
||||
* @method ClientInterface getTheraConnections()
|
||||
* @method ApiInterface send(string $requestHandler, ...$handlerParams)
|
||||
* @method ApiInterface sendBatch(array $configs)
|
||||
*/
|
||||
class EveScoutClient extends AbstractClient {
|
||||
|
||||
|
||||
@@ -11,14 +11,13 @@ namespace Exodus4D\Pathfinder\Lib\Api;
|
||||
use Exodus4D\Pathfinder\Lib\Config;
|
||||
use Exodus4D\ESI\Client\ApiInterface;
|
||||
use Exodus4D\ESI\Client\GitHub\GitHub as Client;
|
||||
use Exodus4D\ESI\Client\GitHub\GitHubInterface as ClientInterface;
|
||||
|
||||
/**
|
||||
* Class GitHubClient
|
||||
* @package lib\api
|
||||
*
|
||||
* @method ClientInterface getProjectReleases(string $projectName, int $count) : array
|
||||
* @method ClientInterface markdownToHtml(string $context, string $markdown) : string
|
||||
* @method ApiInterface send(string $requestHandler, ...$handlerParams)
|
||||
* @method ApiInterface sendBatch(array $configs)
|
||||
*/
|
||||
class GitHubClient extends AbstractClient {
|
||||
|
||||
|
||||
@@ -150,7 +150,7 @@ class AllianceModel extends AbstractPathfinderModel {
|
||||
$loaded = parent::getById($id, $ttl, $isActive);
|
||||
if($this->isOutdated()){
|
||||
// request alliance data
|
||||
$allianceData = self::getF3()->ccpClient()->getAllianceData($id);
|
||||
$allianceData = self::getF3()->ccpClient()->send('getAlliance', $id);
|
||||
if(!empty($allianceData) && !isset($allianceData['error'])){
|
||||
$this->copyfrom($allianceData, ['id', 'name', 'ticker']);
|
||||
$this->save();
|
||||
|
||||
@@ -792,7 +792,7 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
*/
|
||||
public function updateCloneData(){
|
||||
if($accessToken = $this->getAccessToken()){
|
||||
$clonesData = self::getF3()->ccpClient()->getCharacterClonesData($this->_id, $accessToken);
|
||||
$clonesData = self::getF3()->ccpClient()->send('getCharacterClones', $this->_id, $accessToken);
|
||||
if(!isset($clonesData['error'])){
|
||||
if(!empty($homeLocationData = $clonesData['home']['location'])){
|
||||
// clone home location data
|
||||
@@ -816,7 +816,7 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
* @return array
|
||||
*/
|
||||
protected function getOnlineData(string $accessToken) : array {
|
||||
return self::getF3()->ccpClient()->getCharacterOnlineData($this->_id, $accessToken);
|
||||
return self::getF3()->ccpClient()->send('getCharacterOnline', $this->_id, $accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -855,7 +855,7 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
// Try to pull data from API
|
||||
if($accessToken = $this->getAccessToken()){
|
||||
if($this->isOnline($accessToken)){
|
||||
$locationData = self::getF3()->ccpClient()->getCharacterLocationData($this->_id, $accessToken);
|
||||
$locationData = self::getF3()->ccpClient()->send('getCharacterLocation', $this->_id, $accessToken);
|
||||
|
||||
if(!empty($locationData['system']['id'])){
|
||||
// character is currently in-game
|
||||
@@ -886,7 +886,7 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
// get "more" data for systemId ---------------------------------------------------------------
|
||||
if(!empty($lookupUniverseIds)){
|
||||
// get "more" information for some Ids (e.g. name)
|
||||
$universeData = self::getF3()->ccpClient()->getUniverseNamesData($lookupUniverseIds);
|
||||
$universeData = self::getF3()->ccpClient()->send('getUniverseNames', $lookupUniverseIds);
|
||||
|
||||
if(!empty($universeData) && !isset($universeData['error'])){
|
||||
// We expect max ONE system AND/OR station data, not an array of e.g. systems
|
||||
@@ -967,7 +967,7 @@ class CharacterModel extends AbstractPathfinderModel {
|
||||
|
||||
// check ship data for changes ----------------------------------------------------------------
|
||||
if(!$deleteLog){
|
||||
$shipData = self::getF3()->ccpClient()->getCharacterShipData($this->_id, $accessToken);
|
||||
$shipData = self::getF3()->ccpClient()->send('getCharacterShip', $this->_id, $accessToken);
|
||||
|
||||
// IDs for "shipTypeId" that require more data
|
||||
$lookupShipTypeId = 0;
|
||||
|
||||
@@ -130,7 +130,7 @@ class ConnectionModel extends AbstractMapTrackingModel {
|
||||
$connectionData->source = $this->source->id;
|
||||
$connectionData->target = $this->target->id;
|
||||
$connectionData->scope = $this->scope;
|
||||
$connectionData->type = $this->type;
|
||||
$connectionData->type = (array)json_decode($this->get('type', true));
|
||||
$connectionData->updated = strtotime($this->updated);
|
||||
$connectionData->created = strtotime($this->created);
|
||||
$connectionData->eolUpdated = strtotime($this->eolUpdated);
|
||||
@@ -219,10 +219,10 @@ class ConnectionModel extends AbstractMapTrackingModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* set default connection type by search route between endpoints
|
||||
* set default connection scope + type by search route between endpoints
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function setDefaultTypeData(){
|
||||
public function setAutoScopeAndType(){
|
||||
if(
|
||||
is_object($this->source) &&
|
||||
is_object($this->target)
|
||||
@@ -233,15 +233,16 @@ class ConnectionModel extends AbstractMapTrackingModel {
|
||||
){
|
||||
$this->scope = 'abyssal';
|
||||
$this->type = ['abyssal'];
|
||||
}elseif(
|
||||
$this->source->isKspace() &&
|
||||
$this->target->isKspace() &&
|
||||
(new Route())->searchRoute($this->source->systemId, $this->target->systemId, 1)['routePossible']
|
||||
){
|
||||
$this->scope = 'stargate';
|
||||
$this->type = ['stargate'];
|
||||
}else{
|
||||
$route = (new Route())->searchRoute($this->source->systemId, $this->target->systemId, 1);
|
||||
if($route['routePossible']){
|
||||
$this->scope = 'stargate';
|
||||
$this->type = ['stargate'];
|
||||
}else{
|
||||
$this->scope = 'wh';
|
||||
$this->type = ['wh_fresh'];
|
||||
}
|
||||
$this->scope = 'wh';
|
||||
$this->type = ['wh_fresh'];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -294,7 +295,7 @@ class ConnectionModel extends AbstractMapTrackingModel {
|
||||
!$this->scope ||
|
||||
empty($types)
|
||||
){
|
||||
$this->setDefaultTypeData();
|
||||
$this->setAutoScopeAndType();
|
||||
}
|
||||
|
||||
return $this->isValid() ? parent::beforeInsertEvent($self, $pkeys) : false;
|
||||
|
||||
@@ -292,7 +292,7 @@ class CorporationModel extends AbstractPathfinderModel {
|
||||
!empty($accessToken) &&
|
||||
!$this->isNPC
|
||||
){
|
||||
$response = self::getF3()->ccpClient()->getCorporationRoles($this->_id, $accessToken);
|
||||
$response = self::getF3()->ccpClient()->send('getCorporationRoles', $this->_id, $accessToken);
|
||||
if( !empty($response['roles']) ){
|
||||
$characterRolesData = (array)$response['roles'];
|
||||
}
|
||||
@@ -356,10 +356,10 @@ class CorporationModel extends AbstractPathfinderModel {
|
||||
$loaded = parent::getById($id, $ttl, $isActive);
|
||||
if($this->isOutdated()){
|
||||
// request corporation data
|
||||
$corporationData = self::getF3()->ccpClient()->getCorporationData($id);
|
||||
$corporationData = self::getF3()->ccpClient()->send('getCorporation', $id);
|
||||
if(!empty($corporationData) && !isset($corporationData['error'])){
|
||||
// check for NPC corporation
|
||||
$corporationData['isNPC'] = self::getF3()->ccpClient()->isNpcCorporation($id);
|
||||
$corporationData['isNPC'] = in_array($id, self::getF3()->ccpClient()->send('getNpcCorporations'));
|
||||
|
||||
$this->copyfrom($corporationData, ['id', 'name', 'ticker', 'memberCount', 'isNPC']);
|
||||
$this->save();
|
||||
|
||||
@@ -85,7 +85,7 @@ class AllianceModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getAllianceData($id);
|
||||
$data = self::getF3()->ccpClient()->send('getAlliance', $id);
|
||||
if(!empty($data) && !isset($data['error'])){
|
||||
if($data['factionId']){
|
||||
/**
|
||||
|
||||
@@ -178,14 +178,14 @@ class CategoryModel extends AbstractUniverseModel {
|
||||
* @return array
|
||||
*/
|
||||
public static function getUniverseCategoryData(int $id) : array {
|
||||
return self::getF3()->ccpClient()->getUniverseCategoryData($id);
|
||||
return self::getF3()->ccpClient()->send('getUniverseCategory', $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getUniverseCategories() : array {
|
||||
return self::getF3()->ccpClient()->getUniverseCategories();
|
||||
return self::getF3()->ccpClient()->send('getUniverseCategories');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -80,7 +80,7 @@ class ConstellationModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseConstellationData($id);
|
||||
$data = self::getF3()->ccpClient()->send('getUniverseConstellation', $id);
|
||||
if(!empty($data)){
|
||||
/**
|
||||
* @var $region RegionModel
|
||||
@@ -99,7 +99,7 @@ class ConstellationModel extends AbstractUniverseModel {
|
||||
*/
|
||||
public function loadSystemsData(){
|
||||
if( !$this->dry() ){
|
||||
$data = self::getF3()->ccpClient()->getUniverseConstellationData($this->_id);
|
||||
$data = self::getF3()->ccpClient()->send('getUniverseConstellation', $this->_id);
|
||||
if(!empty($data)){
|
||||
foreach((array)$data['systems'] as $systemId){
|
||||
/**
|
||||
|
||||
@@ -105,10 +105,10 @@ class CorporationModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getCorporationData($id);
|
||||
$data = self::getF3()->ccpClient()->send('getCorporation', $id);
|
||||
if(!empty($data) && !isset($data['error'])){
|
||||
// check for NPC corporation
|
||||
$data['isNPC'] = self::getF3()->ccpClient()->isNpcCorporation($id);
|
||||
$data['isNPC'] = in_array($id, self::getF3()->ccpClient()->send('getNpcCorporations'));
|
||||
|
||||
if($data['factionId']){
|
||||
/**
|
||||
|
||||
@@ -88,7 +88,7 @@ class DogmaAttributeModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getDogmaAttributeData($id);
|
||||
$data = self::getF3()->ccpClient()->send('getDogmaAttribute', $id);
|
||||
if(!empty($data) && !isset($data['error'])){
|
||||
$this->copyfrom($data, ['id', 'name', 'displayName', 'description', 'published', 'stackable', 'highIsGood', 'defaultValue', 'iconId', 'unitId']);
|
||||
$this->save();
|
||||
|
||||
@@ -84,7 +84,7 @@ class FactionModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseFactionData($id);
|
||||
$data = self::getF3()->ccpClient()->send('getUniverseFaction', $id);
|
||||
if(!empty($data) && !isset($data['error'])){
|
||||
$this->copyfrom($data, ['id', 'name', 'description', 'sizeFactor', 'stationCount', 'stationSystemCount']);
|
||||
$this->save();
|
||||
|
||||
@@ -178,14 +178,14 @@ class GroupModel extends AbstractUniverseModel {
|
||||
* @return array
|
||||
*/
|
||||
public static function getUniverseGroupData(int $id) : array {
|
||||
return self::getF3()->ccpClient()->getUniverseGroupData($id);
|
||||
return self::getF3()->ccpClient()->send('getUniverseGroup', $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function getUniverseGroups() : array {
|
||||
return self::getF3()->ccpClient()->getUniverseGroups();
|
||||
return self::getF3()->ccpClient()->send('getUniverseGroups');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -87,7 +87,7 @@ class PlanetModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniversePlanetData($id);
|
||||
$data = self::getF3()->ccpClient()->send('getUniversePlanet', $id);
|
||||
if(!empty($data)){
|
||||
/**
|
||||
* @var $system SystemModel
|
||||
|
||||
@@ -66,7 +66,7 @@ class RaceModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseRaceData($id);
|
||||
$data = self::getF3()->ccpClient()->send('getUniverseRace', $id);
|
||||
if(!empty($data) && !isset($data['error'])){
|
||||
/**
|
||||
* @var $faction FactionModel
|
||||
|
||||
@@ -56,7 +56,7 @@ class RegionModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseRegionData($id);
|
||||
$data = self::getF3()->ccpClient()->send('getUniverseRegion', $id);
|
||||
if(!empty($data)){
|
||||
$this->copyfrom($data, ['id', 'name', 'description']);
|
||||
$this->save();
|
||||
@@ -68,7 +68,7 @@ class RegionModel extends AbstractUniverseModel {
|
||||
*/
|
||||
public function loadConstellationsData(){
|
||||
if( !$this->dry() ){
|
||||
$data = self::getF3()->ccpClient()->getUniverseRegionData($this->_id);
|
||||
$data = self::getF3()->ccpClient()->send('getUniverseRegion', $this->_id);
|
||||
if(!empty($data)){
|
||||
foreach((array)$data['constellations'] as $constellationsId){
|
||||
/**
|
||||
|
||||
@@ -86,7 +86,7 @@ class StarModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseStarData($id);
|
||||
$data = self::getF3()->ccpClient()->send('getUniverseStar', $id);
|
||||
if(!empty($data)){
|
||||
/**
|
||||
* @var $type TypeModel
|
||||
|
||||
@@ -94,7 +94,7 @@ class StargateModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseStargateData($id);
|
||||
$data = self::getF3()->ccpClient()->send('getUniverseStargate', $id);
|
||||
|
||||
if(!empty($data)){
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ class StationModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseStationData($id);
|
||||
$data = self::getF3()->ccpClient()->send('getUniverseStation', $id);
|
||||
if(!empty($data) && !isset($data['error'])){
|
||||
/**
|
||||
* @var $system SystemModel
|
||||
|
||||
@@ -90,7 +90,7 @@ class StructureModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseStructureData($id, $accessToken);
|
||||
$data = self::getF3()->ccpClient()->send('getUniverseStructure', $id, $accessToken);
|
||||
if(!empty($data) && !isset($data['error'])){
|
||||
/**
|
||||
* @var $type TypeModel
|
||||
|
||||
@@ -491,7 +491,7 @@ class SystemModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseSystemData($id);
|
||||
$data = self::getF3()->ccpClient()->send('getUniverseSystem', $id);
|
||||
|
||||
if(!empty($data)){
|
||||
/**
|
||||
@@ -521,7 +521,7 @@ class SystemModel extends AbstractUniverseModel {
|
||||
*/
|
||||
public function loadPlanetsData(){
|
||||
if($this->valid()){
|
||||
$data = self::getF3()->ccpClient()->getUniverseSystemData($this->_id);
|
||||
$data = self::getF3()->ccpClient()->send('getUniverseSystem', $this->_id);
|
||||
if($data['planets']){
|
||||
// planets are optional since ESI v4 (e.g. Abyssal systems)
|
||||
foreach((array)$data['planets'] as $planetData){
|
||||
@@ -542,7 +542,7 @@ class SystemModel extends AbstractUniverseModel {
|
||||
*/
|
||||
public function loadStargatesData(){
|
||||
if($this->valid()){
|
||||
$data = self::getF3()->ccpClient()->getUniverseSystemData($this->_id);
|
||||
$data = self::getF3()->ccpClient()->send('getUniverseSystem', $this->_id);
|
||||
if($data['stargates']){
|
||||
foreach((array)$data['stargates'] as $stargateId){
|
||||
/**
|
||||
@@ -561,7 +561,7 @@ class SystemModel extends AbstractUniverseModel {
|
||||
*/
|
||||
public function loadStationsData(){
|
||||
if($this->valid()){
|
||||
$data = self::getF3()->ccpClient()->getUniverseSystemData($this->_id);
|
||||
$data = self::getF3()->ccpClient()->send('getUniverseSystem', $this->_id);
|
||||
if($data['stations']){
|
||||
foreach((array)$data['stations'] as $stationId){
|
||||
/**
|
||||
|
||||
@@ -352,7 +352,7 @@ class TypeModel extends AbstractUniverseModel {
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient()->getUniverseTypesData($id);
|
||||
$data = self::getF3()->ccpClient()->send('getUniverseType', $id);
|
||||
if(!empty($data)){
|
||||
$this->manipulateDogmaAttributes($data);
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
"cache/namespaced-cache": "1.0.*",
|
||||
"react/socket": "1.3.*",
|
||||
"react/promise-stream": "1.2.*",
|
||||
"clue/ndjson-react": "1.0.*",
|
||||
"clue/ndjson-react": "1.1.*",
|
||||
"exodus4d/pathfinder_esi": "dev-develop as 0.0.x-dev"
|
||||
},
|
||||
"suggest": {
|
||||
|
||||
@@ -49,8 +49,8 @@
|
||||
"cache/namespaced-cache": "1.0.*",
|
||||
"react/socket": "1.3.*",
|
||||
"react/promise-stream": "1.2.*",
|
||||
"clue/ndjson-react": "1.0.*",
|
||||
"exodus4d/pathfinder_esi": "1.3.3"
|
||||
"clue/ndjson-react": "1.1.*",
|
||||
"exodus4d/pathfinder_esi": "2.0.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-redis": "Redis can be used as cache backend."
|
||||
|
||||
@@ -516,7 +516,7 @@ gulp.task('task:hintJS', () => {
|
||||
* concat/build JS files by modules
|
||||
*/
|
||||
gulp.task('task:concatJS', () => {
|
||||
let modules = ['login', 'mappage', 'setup', 'admin', 'PNotify.loader', 'datatables.loader'];
|
||||
let modules = ['login', 'mappage', 'setup', 'admin', 'pnotify.loader', 'datatables.loader', 'summernote.loader'];
|
||||
let srcModules = ['./js/app/*(' + modules.join('|') + ').js'];
|
||||
|
||||
return gulp.src(srcModules, {base: 'js'})
|
||||
|
||||
@@ -70,16 +70,16 @@ requirejs.config({
|
||||
'datatables.net-buttons': 'lib/datatables/Buttons-1.5.6/js/dataTables.buttons.min',
|
||||
'datatables.net-buttons-html': 'lib/datatables/Buttons-1.5.6/js/buttons.html5.min',
|
||||
'datatables.net-responsive': 'lib/datatables/Responsive-2.2.2/js/dataTables.responsive.min',
|
||||
'datatables.net-rowgroup': 'lib/datatables/RowGroup-1.1.1/js/dataTables.rowGroup.min',
|
||||
'datatables.net-select': 'lib/datatables/Select-1.3.0/js/dataTables.select.min',
|
||||
'datatables.plugins.render.ellipsis': 'lib/datatables/plugins/render/ellipsis',
|
||||
|
||||
// PNotify // v4.0.0 PNotify - notification core file - https://sciactive.com/pnotify
|
||||
'PNotify.loader': './app/pnotify.loader',
|
||||
'pnotify.loader': './app/pnotify.loader',
|
||||
'PNotify': 'lib/pnotify/PNotify',
|
||||
'PNotifyButtons': 'lib/pnotify/PNotifyButtons',
|
||||
'PNotifyNonBlock': 'lib/pnotify/PNotifyNonBlock',
|
||||
'PNotifyDesktop': 'lib/pnotify/PNotifyDesktop',
|
||||
'PNotifyCallbacks': 'lib/pnotify/PNotifyCallbacks',
|
||||
'PNotifyDesktop': 'lib/pnotify/PNotifyDesktop',
|
||||
'NonBlock': 'lib/pnotify/NonBlock' // v1.0.8 NonBlock.js - for PNotify "nonblock" feature
|
||||
},
|
||||
shim: {
|
||||
@@ -116,6 +116,9 @@ requirejs.config({
|
||||
'datatables.net-responsive': {
|
||||
deps: ['datatables.net']
|
||||
},
|
||||
'datatables.net-rowgroup': {
|
||||
deps: ['datatables.net']
|
||||
},
|
||||
'datatables.net-select': {
|
||||
deps: ['datatables.net']
|
||||
},
|
||||
|
||||
@@ -107,7 +107,7 @@ define([
|
||||
updateDateDiff(element, date, round);
|
||||
}
|
||||
};
|
||||
Cron.set(counterTask);
|
||||
counterTask.start();
|
||||
|
||||
element.attr(config.counterTaskAttr, taskName);
|
||||
}
|
||||
@@ -138,7 +138,7 @@ define([
|
||||
counterTask.task = timer => {
|
||||
tableApi.cells(null, columnSelector).every(cellUpdate);
|
||||
};
|
||||
Cron.set(counterTask);
|
||||
counterTask.start();
|
||||
|
||||
tableElement.attr(config.counterTaskAttr, taskName);
|
||||
};
|
||||
|
||||
@@ -8,7 +8,8 @@ define([
|
||||
'datatables.net-select',
|
||||
'datatables.net-buttons',
|
||||
'datatables.net-buttons-html',
|
||||
'datatables.net-responsive'
|
||||
'datatables.net-responsive',
|
||||
'datatables.net-rowgroup'
|
||||
], ($, Init, Counter, DeferredPromise, TimeoutPromise) => {
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -5,7 +5,7 @@ define([], () => {
|
||||
* Abstract Cache Strategy class
|
||||
* @type {AbstractStrategy}
|
||||
*/
|
||||
let AbstractStrategy = class AbstractStrategy {
|
||||
class AbstractStrategy {
|
||||
constructor(){
|
||||
if(new.target === AbstractStrategy){
|
||||
throw new TypeError('Cannot construct AbstractStrategy instances directly');
|
||||
@@ -19,7 +19,7 @@ define([], () => {
|
||||
static create(){
|
||||
return new this();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* LIFO Cache Strategy - First In First Out
|
||||
@@ -27,7 +27,7 @@ define([], () => {
|
||||
* without any regard to how often or how many times they were accessed before.
|
||||
* @type {StrategyFIFO}
|
||||
*/
|
||||
let StrategyFIFO = class StrategyFIFO extends AbstractStrategy {
|
||||
class StrategyFIFO extends AbstractStrategy {
|
||||
valueToCompare(metaData){
|
||||
return metaData.age();
|
||||
}
|
||||
@@ -35,7 +35,7 @@ define([], () => {
|
||||
compare(a, b){
|
||||
return b - a;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* LFU Cache Strategy - Least Frequently Used
|
||||
@@ -43,7 +43,7 @@ define([], () => {
|
||||
* Those that are used least often are discarded first
|
||||
* @type {StrategyLFU}
|
||||
*/
|
||||
let StrategyLFU = class StrategyLFU extends AbstractStrategy {
|
||||
class StrategyLFU extends AbstractStrategy {
|
||||
valueToCompare(metaData){
|
||||
return metaData.hitCount;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ define([], () => {
|
||||
compare(a, b){
|
||||
return a - b;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* LRU Cache Strategy - Least Recently Used
|
||||
@@ -59,7 +59,7 @@ define([], () => {
|
||||
* No matter how often they have been accessed.
|
||||
* @type {StrategyLRU}
|
||||
*/
|
||||
let StrategyLRU = class StrategyLRU extends AbstractStrategy {
|
||||
class StrategyLRU extends AbstractStrategy {
|
||||
valueToCompare(metaData){
|
||||
return metaData.hits[metaData.hits.length - 1] || metaData.set;
|
||||
}
|
||||
@@ -67,26 +67,26 @@ define([], () => {
|
||||
compare(a, b){
|
||||
return a - b;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Each entry in cache also has its own instance of CacheEntryMeta
|
||||
* -> The configured Cache Strategy use this meta data for eviction policy
|
||||
* @type {CacheEntryMeta}
|
||||
*/
|
||||
let CacheEntryMeta = class CacheEntryMeta {
|
||||
class CacheEntryMeta {
|
||||
constructor(ttl, tSet){
|
||||
this.ttl = ttl;
|
||||
this.tSet = tSet || this.constructor.now();
|
||||
this.tHits = [];
|
||||
this._ttl = ttl; // ttl < 0 => no expire
|
||||
this._tSet = tSet || this.constructor.now();
|
||||
this._tHits = [];
|
||||
}
|
||||
|
||||
get set(){
|
||||
return this.tSet;
|
||||
return this._tSet;
|
||||
}
|
||||
|
||||
get hits(){
|
||||
return this.tHits;
|
||||
return this._tHits;
|
||||
}
|
||||
|
||||
get hitCount(){
|
||||
@@ -94,15 +94,15 @@ define([], () => {
|
||||
}
|
||||
|
||||
newHit(current){
|
||||
this.tHits.push(current || this.constructor.now());
|
||||
this._tHits.push(current || this.constructor.now());
|
||||
}
|
||||
|
||||
age(current){
|
||||
return (current || this.constructor.now()) - this.tSet;
|
||||
return (current || this.constructor.now()) - this._tSet;
|
||||
}
|
||||
|
||||
expired(current){
|
||||
return this.ttl < this.age(current);
|
||||
return this._ttl < 0 ? false : this._ttl < this.age(current);
|
||||
}
|
||||
|
||||
static now(){
|
||||
@@ -112,7 +112,7 @@ define([], () => {
|
||||
static create(ttl, tSet){
|
||||
return new this(ttl, tSet);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Each instance of Cache represents a key value in memory data store
|
||||
@@ -123,26 +123,18 @@ define([], () => {
|
||||
* if cache reaches maxSize limit, to increase performance.
|
||||
* @type {Cache}
|
||||
*/
|
||||
let Cache = class Cache {
|
||||
class Cache {
|
||||
|
||||
constructor(config){
|
||||
this.config = Object.assign({},{
|
||||
name: 'Default', // custom unique name for identification
|
||||
ttl: 3600, // default ttl for cache entries
|
||||
maxSize: 600, // max cache entries
|
||||
bufferSize: 10, // cache entry count in percent to be removed if maxSize reached
|
||||
strategy: 'FIFO', // cache strategy policy
|
||||
debug: false // debug output in console
|
||||
}, config);
|
||||
|
||||
this.store = new Map();
|
||||
this.metaStore = new WeakMap();
|
||||
this.strategy = this.constructor.setStrategy(this.config.strategy);
|
||||
constructor(config = {}){
|
||||
this._config = Object.assign({}, Cache.defaultConfig, config);
|
||||
this._store = new Map();
|
||||
this._metaStore = new WeakMap();
|
||||
this._strategy = this.constructor.setStrategy(this._config.strategy);
|
||||
|
||||
this.debug = (msg,...data) => {
|
||||
if(this.config.debug){
|
||||
if(this._config.debug){
|
||||
data = (data || []);
|
||||
data.unshift(this.config.name);
|
||||
data.unshift(this._config.name);
|
||||
console.debug('debug: CACHE %o | ' + msg, ...data);
|
||||
}
|
||||
};
|
||||
@@ -151,34 +143,34 @@ define([], () => {
|
||||
}
|
||||
|
||||
get size(){
|
||||
return this.store.size;
|
||||
return this._store.size;
|
||||
}
|
||||
|
||||
isFull(){
|
||||
return this.size>= this.config.maxSize;
|
||||
return this.size>= this._config.maxSize;
|
||||
}
|
||||
|
||||
set(key, value, ttl){
|
||||
if(this.store.has(key)){
|
||||
if(this._store.has(key)){
|
||||
this.debug('SET key %o, UPDATE value %o', key, value);
|
||||
this.store.set(key, value);
|
||||
this._store.set(key, value);
|
||||
}else{
|
||||
this.debug('SET key %o, NEW value %o', key, value);
|
||||
if(this.isFull()){
|
||||
this.debug(' ↪ FULL trim cache…');
|
||||
this.trim(this.trimCount(1));
|
||||
}
|
||||
this.store.set(key, value);
|
||||
this._store.set(key, value);
|
||||
}
|
||||
|
||||
this.metaStore.set(value, CacheEntryMeta.create(ttl || this.config.ttl));
|
||||
this._metaStore.set(value, CacheEntryMeta.create(ttl || this._config.ttl));
|
||||
}
|
||||
|
||||
get(key){
|
||||
if(this.store.has(key)){
|
||||
let value = this.store.get(key);
|
||||
if(this._store.has(key)){
|
||||
let value = this._store.get(key);
|
||||
if(value){
|
||||
let metaData = this.metaStore.get(value);
|
||||
let metaData = this._metaStore.get(value);
|
||||
if(metaData.expired()){
|
||||
this.debug('EXPIRED key %o delete', key);
|
||||
this.delete(key);
|
||||
@@ -199,8 +191,8 @@ define([], () => {
|
||||
keysForTrim(count){
|
||||
let trimKeys = [];
|
||||
let compare = [];
|
||||
for(let [key, value] of this.store){
|
||||
let metaData = this.metaStore.get(value);
|
||||
for(let [key, value] of this._store){
|
||||
let metaData = this._metaStore.get(value);
|
||||
if(metaData.expired()){
|
||||
trimKeys.push(key);
|
||||
if(count === trimKeys.length){
|
||||
@@ -209,14 +201,14 @@ define([], () => {
|
||||
}else{
|
||||
compare.push({
|
||||
key: key,
|
||||
value: this.strategy.valueToCompare(metaData)
|
||||
value: this._strategy.valueToCompare(metaData)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let countLeft = count - trimKeys.length;
|
||||
if(countLeft > 0){
|
||||
compare = compare.sort((a, b) => this.strategy.compare(a.value, b.value));
|
||||
compare = compare.sort((a, b) => this._strategy.compare(a.value, b.value));
|
||||
trimKeys = trimKeys.concat(compare.splice(0, countLeft).map(a => a.key));
|
||||
}
|
||||
|
||||
@@ -224,20 +216,20 @@ define([], () => {
|
||||
}
|
||||
|
||||
keys(){
|
||||
return this.store.keys();
|
||||
return this._store.keys();
|
||||
}
|
||||
|
||||
delete(key){
|
||||
return this.store.delete(key);
|
||||
return this._store.delete(key);
|
||||
}
|
||||
|
||||
clear(){
|
||||
this.store.clear();
|
||||
this._store.clear();
|
||||
}
|
||||
|
||||
trimCount(spaceLeft){
|
||||
let bufferSize = Math.max(Math.round(this.config.maxSize / 100 * this.config.bufferSize), spaceLeft);
|
||||
return Math.min(Math.max(this.size - this.config.maxSize + bufferSize, 0), this.size);
|
||||
let bufferSize = Math.max(Math.round(this._config.maxSize / 100 * this._config.bufferSize), spaceLeft);
|
||||
return Math.min(Math.max(this.size - this._config.maxSize + bufferSize, 0), this.size);
|
||||
}
|
||||
|
||||
trim(count){
|
||||
@@ -253,9 +245,9 @@ define([], () => {
|
||||
|
||||
status(){
|
||||
return {
|
||||
config: this.config,
|
||||
store: this.store,
|
||||
metaStore: this.metaStore
|
||||
config: this._config,
|
||||
store: this._store,
|
||||
metaStore: this._metaStore
|
||||
};
|
||||
}
|
||||
|
||||
@@ -269,6 +261,15 @@ define([], () => {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cache.defaultConfig = {
|
||||
name: 'Default', // custom unique name for identification
|
||||
ttl: 3600, // default ttl for cache entries
|
||||
maxSize: 600, // max cache entries
|
||||
bufferSize: 10, // cache entry count in percent to be removed if maxSize reached
|
||||
strategy: 'FIFO', // cache strategy policy
|
||||
debug: false // debug output in console
|
||||
};
|
||||
|
||||
return Cache;
|
||||
|
||||
@@ -11,7 +11,7 @@ define([
|
||||
console.info('task1 function():', timer.getTotalTimeValues());
|
||||
return 'OK';
|
||||
};
|
||||
Cron.set(task1);
|
||||
task1.start();
|
||||
|
||||
Example2 run task every 3 seconds ---------------------------------------------------------------------------------
|
||||
let task1 = Cron.new('task1', {precision: 'seconds', interval: 3, timeout: 100});
|
||||
@@ -19,7 +19,7 @@ define([
|
||||
console.info('task1 function():', timer.getTotalTimeValues());
|
||||
return 'OK';
|
||||
};
|
||||
Cron.set(task1);
|
||||
task1.start();
|
||||
|
||||
Example3 resolve Promise on run ----------------------------------------------------------------------------------
|
||||
let task1 = Cron.new('task1', {precision: 'seconds', interval: 1, timeout: 100});
|
||||
@@ -35,14 +35,14 @@ define([
|
||||
});
|
||||
});
|
||||
};
|
||||
Cron.set(task1);
|
||||
task1.start();
|
||||
|
||||
Example4 run task once at given Date() --------------------------------------------------------------------------
|
||||
let dueDate = new Date();
|
||||
dueDate.setSeconds(dueDate.getSeconds() + 5);
|
||||
let task2 = Cron.new('task2', {precision: 'seconds', timeout: 100, dueDate: dueDate});
|
||||
task2.task = () => 'OK task2';
|
||||
Cron.set(task2);
|
||||
task2.start();
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -51,35 +51,42 @@ define([
|
||||
* @type {Task}
|
||||
*/
|
||||
let Task = class Task {
|
||||
constructor(name, config){
|
||||
/**
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {{}} config
|
||||
* @param {CronManager} manager
|
||||
*/
|
||||
constructor(name, config, manager = null){
|
||||
if(typeof name !== 'string'){
|
||||
throw new TypeError('Task "name" must be instance of String, Type of "' + typeof name + '" given');
|
||||
}
|
||||
this._config = Object.assign({}, this.constructor.defaultConfig, config);
|
||||
this._name = name; // unique name for identification
|
||||
this._task = undefined; // task to run, instanceof Function, can also return a Promise
|
||||
this._manager = undefined; // reference to CronManager() that handles this task
|
||||
this._task = (timer, task) => {}; // task to run, instanceof Function, can also return a Promise
|
||||
this._manager = manager; // reference to CronManager() that handles this task
|
||||
this._runCount = 0; // counter for run() calls
|
||||
this._runQueue = new Map(); // current run() processes. > 1 requires config.isParallel: true
|
||||
this._runCount = 0; // total run counter for this task
|
||||
this._lastTotalTimeValues = undefined; // time values of last run()
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
get name(){
|
||||
return this._name;
|
||||
}
|
||||
|
||||
get task(){
|
||||
/**
|
||||
* @returns {(function())} task
|
||||
*/
|
||||
get task() {
|
||||
return this._task;
|
||||
}
|
||||
|
||||
get runCount(){
|
||||
return this._runCount;
|
||||
}
|
||||
|
||||
get precision(){
|
||||
return this._config.precision;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {(function())} task
|
||||
*/
|
||||
set task(task){
|
||||
if(task instanceof Function){
|
||||
this._task = task;
|
||||
@@ -88,34 +95,120 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
get runCount(){
|
||||
return this._runCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
get precision(){
|
||||
return this.get('precision');
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get paused(){
|
||||
return this.get('paused');
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get targetAchieved(){
|
||||
return this.get('targetRunCount') ? this.runCount >= this.get('targetRunCount') : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
get targetProgress(){
|
||||
return parseFloat(
|
||||
parseFloat(
|
||||
(!this.get('targetRunCount') || !this.runCount) ?
|
||||
0 :
|
||||
(100 / this.get('targetRunCount') * this.runCount)
|
||||
).toFixed(2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param option
|
||||
* @returns {*}
|
||||
*/
|
||||
get(option){
|
||||
return this._config[option];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} option
|
||||
* @param {*} value
|
||||
*/
|
||||
set(option, value){
|
||||
this._config[option] = value;
|
||||
}
|
||||
|
||||
setManager(manager){
|
||||
this._manager = manager;
|
||||
/**
|
||||
* connect CronManager with instance
|
||||
* @param {CronManager} manager
|
||||
*/
|
||||
connect(manager = this._manager){
|
||||
if(manager instanceof CronManager){
|
||||
if(manager !== this._manager){
|
||||
// disconnect from current manager (if exists)
|
||||
this.disconnect();
|
||||
this._manager = manager;
|
||||
}
|
||||
this._manager.set(this);
|
||||
}else{
|
||||
throw new TypeError('Parameter must be instance of CronManager. Type of "' + typeof manager + '" given');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* disconnect from CronManager
|
||||
* @param {CronManager} manager
|
||||
*/
|
||||
disconnect(manager = this._manager){
|
||||
if(manager instanceof CronManager){
|
||||
if(this.isConnected(manager)){
|
||||
this._manager.delete(this._name);
|
||||
}
|
||||
}else{
|
||||
throw new TypeError('Parameter must be instance of CronManager. Type of "' + typeof manager + '" given');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if CronManager is connected with instance
|
||||
* @param {CronManager} manager
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isConnected(manager = this._manager){
|
||||
return (manager instanceof CronManager) &&
|
||||
manager === this._manager &&
|
||||
manager.has(this._name);
|
||||
}
|
||||
|
||||
/**
|
||||
* if task is currently running
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isRunning(){
|
||||
return !!this._runQueue.size;
|
||||
}
|
||||
|
||||
delete(){
|
||||
let isDeleted = false;
|
||||
if(this._manager){
|
||||
isDeleted = this._manager.delete(this._name);
|
||||
}
|
||||
return isDeleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timer
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isDue(timer){
|
||||
if(this._config.dueDate instanceof Date){
|
||||
if(this.get('dueDate') instanceof Date){
|
||||
// run once at dueDate
|
||||
if(new Date().getTime() >= this._config.dueDate.getTime()){
|
||||
if(new Date().getTime() >= this.get('dueDate').getTime()){
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
@@ -124,8 +217,8 @@ define([
|
||||
let totalTimeValuePrecision = totalTimeValues[this.precision];
|
||||
totalTimeValuePrecision -= this._lastTotalTimeValues ? this._lastTotalTimeValues[this.precision] : 0;
|
||||
if(
|
||||
this._config.interval === 1 ||
|
||||
totalTimeValuePrecision % this._config.interval === 0
|
||||
this.get('interval') === 1 ||
|
||||
totalTimeValuePrecision % this.get('interval') === 0
|
||||
){
|
||||
return true;
|
||||
}
|
||||
@@ -133,23 +226,30 @@ define([
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timer
|
||||
*/
|
||||
invoke(timer){
|
||||
if(
|
||||
!this.paused &&
|
||||
this.isDue(timer) &&
|
||||
(!this.isRunning() || this._config.isParallel)
|
||||
(!this.isRunning() || this.get('isParallel'))
|
||||
){
|
||||
this.run(timer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timer
|
||||
*/
|
||||
run(timer){
|
||||
this._lastTotalTimeValues = Object.assign({}, timer.getTotalTimeValues());
|
||||
let runId = 'run_' + (++this._runCount);
|
||||
let runExec = resolve => {
|
||||
resolve(this.task(timer, this));
|
||||
resolve(this._task(timer, this));
|
||||
};
|
||||
|
||||
let myProm = this._config.timeout > 0 ? new TimeoutPromise(runExec, this._config.timeout) : new Promise(runExec);
|
||||
let myProm = this.get('timeout') > 0 ? new TimeoutPromise(runExec, this.get('timeout')) : new Promise(runExec);
|
||||
myProm.then(payload => {
|
||||
// resolved within timeout -> wait for finally() block
|
||||
}).catch(error => {
|
||||
@@ -162,14 +262,37 @@ define([
|
||||
// -> remove from _runQueue
|
||||
this._runQueue.delete(runId);
|
||||
|
||||
// remove this task from store after run
|
||||
if(this._config.dueDate instanceof Date){
|
||||
this.delete();
|
||||
if(this.get('dueDate') instanceof Date){
|
||||
this.disconnect();
|
||||
}
|
||||
|
||||
if(this.targetAchieved){
|
||||
this.stop();
|
||||
}
|
||||
});
|
||||
|
||||
this._runQueue.set(runId, myProm);
|
||||
}
|
||||
|
||||
// Task controls ----------------------------------------------------------------------------------------------
|
||||
|
||||
start(){
|
||||
this.set('paused', false);
|
||||
this.connect();
|
||||
}
|
||||
|
||||
stop(){
|
||||
this.reset();
|
||||
this.disconnect();
|
||||
}
|
||||
|
||||
pause(){
|
||||
this.set('paused', true);
|
||||
}
|
||||
|
||||
reset(){
|
||||
this._runCount = 0;
|
||||
}
|
||||
};
|
||||
|
||||
Task.defaultConfig = {
|
||||
@@ -177,7 +300,9 @@ define([
|
||||
isParallel: false, // if true this task can run parallel, e.g. if prev execution has not finished
|
||||
interval: 1, // relates to 'precision'. 'interval' = 3 and 'precision' = "seconds" -> run every 3 seconds
|
||||
dueDate: undefined, // if Date() instance is set, task only runs once at dueDate
|
||||
timeout: 50 // if > 0, execution time that exceeds timeout (ms) throw error
|
||||
timeout: 50, // if > 0, execution time that exceeds timeout (ms) throw error
|
||||
paused: false, // if true this task will not run() but will be invoce()´ed
|
||||
targetRunCount: 0 // if > 0, task will stop if targetRunCount is reached
|
||||
};
|
||||
|
||||
|
||||
@@ -188,6 +313,9 @@ define([
|
||||
*/
|
||||
let CronManager = class CronManager {
|
||||
|
||||
/**
|
||||
* @param {{}} config
|
||||
*/
|
||||
constructor(config){
|
||||
this._config = Object.assign({}, this.constructor.defaultConfig, config);
|
||||
this._timerConfig = Object.assign({}, this.constructor.defaultTimerConfig);
|
||||
@@ -211,47 +339,75 @@ define([
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {{}} config
|
||||
* @returns {Task}
|
||||
*/
|
||||
new(name, config){
|
||||
return new Task(name, config);
|
||||
return new Task(name, config, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Task} task
|
||||
*/
|
||||
set(task){
|
||||
if(task instanceof Task){
|
||||
// check for unique task name, or update existing task
|
||||
if(!this.has(task.name) || (this.get(task.name) === task)){
|
||||
// set new or update existing task
|
||||
task.setManager(this);
|
||||
// check for unique task name
|
||||
if(!this.has(task.name)){
|
||||
// connect new task
|
||||
// -> must be before connect(this)! (prevents infinite loop)
|
||||
this._tasks.set(task.name, task);
|
||||
task.connect(this);
|
||||
|
||||
this.debug('SET/UPDATE task: %o config: %o', task.name, task);
|
||||
// start timer (if it is not already running)
|
||||
this.auto();
|
||||
}else{
|
||||
console.warn('FAILED to set task. Task name %o already exists', task.name);
|
||||
}
|
||||
}else{
|
||||
throw new TypeError('Parameter must be instance of Task');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {{}} config
|
||||
*/
|
||||
setNew(name, config){
|
||||
this.set(this.new(name, config));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {Task|undefined}
|
||||
*/
|
||||
get(name){
|
||||
return this._tasks.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {boolean}
|
||||
*/
|
||||
has(name){
|
||||
return this._tasks.has(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
delete(name){
|
||||
let isDeleted = this._tasks.delete(name);
|
||||
if(isDeleted){
|
||||
if(this.has(name)){
|
||||
let task = this._tasks.get(name);
|
||||
// disconnect task
|
||||
// -> must be before disconnect(this)! (prevents infinite loop)
|
||||
this._tasks.delete(name);
|
||||
task.disconnect(this);
|
||||
|
||||
this.debug('DELETE task: %o', name);
|
||||
// stop timer (if no more tasks connected)
|
||||
this.auto();
|
||||
}
|
||||
return isDeleted;
|
||||
}
|
||||
|
||||
clear(){
|
||||
@@ -260,6 +416,10 @@ define([
|
||||
this.auto();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} precision
|
||||
* @returns {Task[]}
|
||||
*/
|
||||
tasksByPrecision(precision){
|
||||
let tasks = [];
|
||||
this._tasks.forEach(task => {
|
||||
|
||||
@@ -34,7 +34,7 @@ define([], () => {
|
||||
}
|
||||
|
||||
get(obj, key) {
|
||||
return this._store.has(obj) && this._store.get(obj).get(key);
|
||||
return this._store.has(obj) && (key ? this._store.get(obj).get(key) : this._store.get(obj));
|
||||
}
|
||||
|
||||
has(obj, key) {
|
||||
@@ -45,6 +45,8 @@ define([], () => {
|
||||
let ret = false;
|
||||
if (this._store.has(obj)) {
|
||||
ret = this._store.get(obj).delete(key);
|
||||
// remove obj if store is empty
|
||||
// -> 'size' property is does not exist if valueStore is WeakMap
|
||||
if (!this._store.get(obj).size) {
|
||||
this._store.delete(obj);
|
||||
}
|
||||
|
||||
@@ -193,10 +193,10 @@ define([
|
||||
}
|
||||
|
||||
/**
|
||||
* set LocalStoreManager for this instance
|
||||
* connect LocalStoreManager with instance
|
||||
* @param {LocalStoreManager} manager
|
||||
*/
|
||||
setManager(manager){
|
||||
connect(manager){
|
||||
if(manager instanceof LocalStoreManager){
|
||||
this._manager = manager;
|
||||
}else{
|
||||
@@ -299,7 +299,7 @@ define([
|
||||
/**
|
||||
* check var for Object
|
||||
* @param obj
|
||||
* @returns {boolean|boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static isObject(obj){
|
||||
return (!!obj) && (obj.constructor === Object);
|
||||
@@ -372,7 +372,7 @@ define([
|
||||
}, {
|
||||
name: LocalStore.buildDbName(name)
|
||||
});
|
||||
store.setManager(this);
|
||||
store.connect(this);
|
||||
this._store.set(name, store);
|
||||
}
|
||||
return this._store.get(name);
|
||||
|
||||
11
js/app/lib/prototypes.js
vendored
11
js/app/lib/prototypes.js
vendored
@@ -103,14 +103,9 @@ define([
|
||||
* @returns {number}
|
||||
*/
|
||||
String.prototype.hashCode = function(){
|
||||
let hash = 0, i, chr;
|
||||
if(this.length === 0) return hash;
|
||||
for(i = 0; i < this.length; i++){
|
||||
chr = this.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash) + chr;
|
||||
hash |= 0; // Convert to 32bit integer
|
||||
}
|
||||
return hash;
|
||||
let hash = this.split('').reduce((a,b) => (((a << 5) - a) + b.charCodeAt(0))|0, 0);
|
||||
// make positive
|
||||
return (hash + 2147483647) + 1;
|
||||
};
|
||||
|
||||
String.prototype.trimLeftChars = function(charList){
|
||||
|
||||
@@ -222,7 +222,7 @@ define([
|
||||
* @param excludeMenu
|
||||
*/
|
||||
let closeMenus = excludeMenu => {
|
||||
let allMenus = $('.' + config.contextMenuClass + '[role="menu"]');
|
||||
let allMenus = $('.' + config.contextMenuClass + '[role="menu"][style*="display: block"]');
|
||||
if(excludeMenu){
|
||||
allMenus = allMenus.not(excludeMenu);
|
||||
}
|
||||
@@ -291,17 +291,15 @@ define([
|
||||
|
||||
/**
|
||||
* default config (skeleton) for valid context menu configuration
|
||||
* @returns {{hidden: Array, active: Array, disabled: Array, id: string, selectCallback: null}}
|
||||
* @returns {{hidden: [], active: [], disabled: [], id: string, selectCallback: null}}
|
||||
*/
|
||||
let defaultMenuOptionConfig = () => {
|
||||
return {
|
||||
'id': '',
|
||||
'selectCallback': null,
|
||||
'hidden': [],
|
||||
'active': [],
|
||||
'disabled': []
|
||||
};
|
||||
};
|
||||
let defaultMenuOptionConfig = () => ({
|
||||
'id': '',
|
||||
'selectCallback': null,
|
||||
'hidden': [],
|
||||
'active': [],
|
||||
'disabled': []
|
||||
});
|
||||
|
||||
return {
|
||||
config: config,
|
||||
|
||||
@@ -29,7 +29,6 @@ define([
|
||||
|
||||
mapIdPrefix: 'pf-map-', // id prefix for all maps
|
||||
systemClass: 'pf-system', // class for all systems
|
||||
systemActiveClass: 'pf-system-active', // class for an active system on a map
|
||||
systemSelectedClass: 'pf-system-selected', // class for selected systems on a map
|
||||
systemHeadClass: 'pf-system-head', // class for system head
|
||||
systemHeadNameClass: 'pf-system-head-name', // class for system name
|
||||
@@ -116,7 +115,7 @@ define([
|
||||
},
|
||||
connectionsDetachable: true, // dragOptions are set -> allow detaching them
|
||||
maxConnections: 10, // due to isTarget is true, this is the max count of !out!-going connections
|
||||
// isSource:true
|
||||
//isSource:true
|
||||
},
|
||||
target: {
|
||||
filter: filterSystemHeadEvent,
|
||||
@@ -125,10 +124,10 @@ define([
|
||||
//allowLoopBack: false, // loopBack connections are not allowed
|
||||
cssClass: config.endpointTargetClass,
|
||||
dropOptions: {
|
||||
hoverClass: config.systemActiveClass,
|
||||
//hoverClass: '',
|
||||
activeClass: 'dragActive'
|
||||
},
|
||||
// uniqueEndpoint: false
|
||||
//uniqueEndpoint: false
|
||||
},
|
||||
endpointTypes: Init.endpointTypes,
|
||||
connectionTypes: Init.connectionTypes
|
||||
@@ -876,23 +875,23 @@ define([
|
||||
* connect two systems
|
||||
* @param map
|
||||
* @param connectionData
|
||||
* @returns new connection
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let drawConnection = (map, connectionData) => {
|
||||
let drawConnection = (map, connectionData) => new Promise((resolve, reject) => {
|
||||
let mapContainer = $(map.getContainer());
|
||||
let mapId = mapContainer.data('id');
|
||||
let connectionId = connectionData.id || 0;
|
||||
let connection;
|
||||
let sourceSystem = $('#' + MapUtil.getSystemId(mapId, connectionData.source));
|
||||
let targetSystem = $('#' + MapUtil.getSystemId(mapId, connectionData.target));
|
||||
|
||||
// check if both systems exists
|
||||
// (If not -> something went wrong e.g. DB-Foreign keys for "ON DELETE",...)
|
||||
if(
|
||||
sourceSystem.length &&
|
||||
targetSystem.length
|
||||
){
|
||||
connection = map.connect({
|
||||
if(!sourceSystem.length){
|
||||
reject(new Error(`drawConnection(): source system (id: ${connectionData.source}) not found`));
|
||||
}else if(!targetSystem.length){
|
||||
reject(new Error(`drawConnection(): target system (id: ${connectionData.target}) not found`));
|
||||
}else{
|
||||
let connection = map.connect({
|
||||
source: sourceSystem[0],
|
||||
target: targetSystem[0],
|
||||
scope: connectionData.scope || map.Defaults.Scope,
|
||||
@@ -948,18 +947,18 @@ define([
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if( !sourceSystem.length ){
|
||||
console.warn('drawConnection(): source system (id: ' + connectionData.source + ') not found');
|
||||
}
|
||||
if( !targetSystem.length ){
|
||||
console.warn('drawConnection(): target system (id: ' + connectionData.target + ') not found');
|
||||
|
||||
resolve({
|
||||
action: 'drawConnection',
|
||||
data: {
|
||||
connection: connection
|
||||
}
|
||||
});
|
||||
}else{
|
||||
reject(new Error(`drawConnection(): connection must be instanceof jsPlumb.Connection`));
|
||||
}
|
||||
}
|
||||
|
||||
return connection;
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* compares the current data and new data of a connection and updates status
|
||||
@@ -1233,168 +1232,178 @@ define([
|
||||
* @param reject
|
||||
*/
|
||||
let updateMapExecutor = (resolve, reject) => {
|
||||
// jsPlumb needs to be initialized. This is not the case when switching between map tabs right after refresh
|
||||
let mapContainer = mapConfig.map ? $(mapConfig.map.getContainer()) : null;
|
||||
if(mapContainer){
|
||||
let mapId = mapConfig.config.id;
|
||||
|
||||
// add additional information for this map
|
||||
if(mapContainer.data('updated') !== mapConfig.config.updated.updated){
|
||||
mapContainer.data('name', mapConfig.config.name);
|
||||
mapContainer.data('scopeId', mapConfig.config.scope.id);
|
||||
mapContainer.data('typeId', mapConfig.config.type.id);
|
||||
mapContainer.data('typeName', mapConfig.config.type.name);
|
||||
mapContainer.data('icon', mapConfig.config.icon);
|
||||
mapContainer.data('created', mapConfig.config.created.created);
|
||||
mapContainer.data('updated', mapConfig.config.updated.updated);
|
||||
}
|
||||
|
||||
// get map data
|
||||
let mapData = getMapDataForSync(mapContainer, [], true);
|
||||
|
||||
|
||||
if(mapData !== false){
|
||||
// map data available -> map not locked by update counter :)
|
||||
let currentSystemData = mapData.data.systems;
|
||||
let currentConnectionData = mapData.data.connections;
|
||||
|
||||
// update systems =================================================================================
|
||||
for(let i = 0; i < mapConfig.data.systems.length; i++){
|
||||
let systemData = mapConfig.data.systems[i];
|
||||
|
||||
// add system
|
||||
let addNewSystem = true;
|
||||
|
||||
for(let 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(let a = 0; a < currentSystemData.length; a++){
|
||||
let deleteThisSystem = true;
|
||||
|
||||
for(let b = 0; b < mapConfig.data.systems.length; b++){
|
||||
let deleteSystemData = mapConfig.data.systems[b];
|
||||
|
||||
if(deleteSystemData.id === currentSystemData[a].id){
|
||||
deleteThisSystem = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(deleteThisSystem === true){
|
||||
let deleteSystem = $('#' + MapUtil.getSystemId(mapContainer.data('id'), currentSystemData[a].id));
|
||||
|
||||
// system not found -> delete system
|
||||
System.removeSystems(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(let j = 0; j < mapConfig.data.connections.length; j++){
|
||||
let connectionData = mapConfig.data.connections[j];
|
||||
|
||||
// add connection
|
||||
let addNewConnection= true;
|
||||
|
||||
for(let 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
|
||||
updateConnection(currentConnectionData[c].connection, connectionData);
|
||||
}
|
||||
|
||||
addNewConnection = false;
|
||||
break;
|
||||
}else if(
|
||||
currentConnectionData[c].id === 0 &&
|
||||
currentConnectionData[c].source === connectionData.source &&
|
||||
currentConnectionData[c].target === connectionData.target
|
||||
){
|
||||
// if ids don´t match -> check for unsaved connection
|
||||
updateConnection(currentConnectionData[c].connection, connectionData);
|
||||
|
||||
addNewConnection = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(addNewConnection === true){
|
||||
drawConnection(mapConfig.map, connectionData);
|
||||
}
|
||||
}
|
||||
|
||||
// check for connections that are gone -> delete connection
|
||||
for(let d = 0; d < currentConnectionData.length; d++){
|
||||
// skip connections with id = 0 -> they might get updated before
|
||||
if(currentConnectionData[d].id === 0){
|
||||
continue;
|
||||
}
|
||||
|
||||
let deleteThisConnection = true;
|
||||
|
||||
for(let e = 0; e < mapConfig.data.connections.length;e++){
|
||||
let deleteConnectionData = mapConfig.data.connections[e];
|
||||
|
||||
if(deleteConnectionData.id === currentConnectionData[d].id){
|
||||
deleteThisConnection = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(deleteThisConnection === true){
|
||||
// connection not found -> delete connection
|
||||
let deleteConnection = currentConnectionData[d].connection;
|
||||
|
||||
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.deleteConnection(deleteConnection, {fireEvent: false});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// update local connection cache
|
||||
updateConnectionsCache(mapConfig.map);
|
||||
}else{
|
||||
// map is currently logged -> queue update for this map until unlock
|
||||
if( mapUpdateQueue.indexOf(mapId) === -1 ){
|
||||
mapUpdateQueue.push(mapId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolve({
|
||||
let payload = {
|
||||
action: 'updateMap',
|
||||
data: {
|
||||
mapConfig: mapConfig
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// jsPlumb needs to be initialized. This is not the case when switching between map tabs right after refresh
|
||||
let mapContainer = mapConfig.map ? mapConfig.map.getContainer() : null;
|
||||
if(!mapContainer){
|
||||
return resolve(payload);
|
||||
}
|
||||
|
||||
let mapId = mapConfig.config.id;
|
||||
|
||||
// mapData == false -> map locked by update counter. Skip update
|
||||
let mapData = getMapDataForSync(mapContainer, [], true);
|
||||
|
||||
if(!mapData){
|
||||
// map is currently locked -> queue update for this map until unlock
|
||||
if(mapUpdateQueue.indexOf(mapId) === -1){
|
||||
mapUpdateQueue.push(mapId);
|
||||
}
|
||||
return resolve(payload);
|
||||
}
|
||||
|
||||
mapContainer = $(mapContainer);
|
||||
|
||||
// add additional information for this map
|
||||
if(mapContainer.data('updated') !== mapConfig.config.updated.updated){
|
||||
mapContainer.data('name', mapConfig.config.name);
|
||||
mapContainer.data('scopeId', mapConfig.config.scope.id);
|
||||
mapContainer.data('typeId', mapConfig.config.type.id);
|
||||
mapContainer.data('typeName', mapConfig.config.type.name);
|
||||
mapContainer.data('icon', mapConfig.config.icon);
|
||||
mapContainer.data('created', mapConfig.config.created.created);
|
||||
mapContainer.data('updated', mapConfig.config.updated.updated);
|
||||
}
|
||||
|
||||
// map data available -> map not locked by update counter :)
|
||||
let currentSystemData = mapData.data.systems;
|
||||
let currentConnectionData = mapData.data.connections;
|
||||
|
||||
// update systems =========================================================================================
|
||||
for(let i = 0; i < mapConfig.data.systems.length; i++){
|
||||
let systemData = mapConfig.data.systems[i];
|
||||
|
||||
// add system
|
||||
let addNewSystem = true;
|
||||
|
||||
for(let 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).catch(console.warn);
|
||||
}
|
||||
}
|
||||
|
||||
// check for systems that are gone -> delete system
|
||||
for(let a = 0; a < currentSystemData.length; a++){
|
||||
let deleteThisSystem = true;
|
||||
|
||||
for(let b = 0; b < mapConfig.data.systems.length; b++){
|
||||
let deleteSystemData = mapConfig.data.systems[b];
|
||||
|
||||
if(deleteSystemData.id === currentSystemData[a].id){
|
||||
deleteThisSystem = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(deleteThisSystem === true){
|
||||
let deleteSystem = $('#' + MapUtil.getSystemId(mapContainer.data('id'), currentSystemData[a].id));
|
||||
|
||||
// system not found -> delete system
|
||||
System.removeSystems(mapConfig.map, deleteSystem);
|
||||
}
|
||||
}
|
||||
|
||||
// update connections =====================================================================================
|
||||
|
||||
// jsPlumb setSuspendDrawing() (batch() did not work because it async 'scopes' out updates).
|
||||
// -> Otherwise there are some "strange" visual bugs when switching maps (Endpoints are not displayed correctly)
|
||||
// -> needs to be "disabled" later in this method.
|
||||
mapConfig.map.setSuspendDrawing(true);
|
||||
|
||||
for(let j = 0; j < mapConfig.data.connections.length; j++){
|
||||
let connectionData = mapConfig.data.connections[j];
|
||||
|
||||
// add connection
|
||||
let addNewConnection= true;
|
||||
|
||||
for(let 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
|
||||
updateConnection(currentConnectionData[c].connection, connectionData);
|
||||
}
|
||||
|
||||
addNewConnection = false;
|
||||
break;
|
||||
}else if(
|
||||
currentConnectionData[c].id === 0 &&
|
||||
currentConnectionData[c].source === connectionData.source &&
|
||||
currentConnectionData[c].target === connectionData.target
|
||||
){
|
||||
// if ids don´t match -> check for unsaved connection
|
||||
updateConnection(currentConnectionData[c].connection, connectionData);
|
||||
|
||||
addNewConnection = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(addNewConnection === true){
|
||||
drawConnection(mapConfig.map, connectionData).catch(console.warn);
|
||||
}
|
||||
}
|
||||
|
||||
// check for connections that are gone -> delete connection
|
||||
for(let d = 0; d < currentConnectionData.length; d++){
|
||||
// skip connections with id = 0 -> they might get updated before
|
||||
if(currentConnectionData[d].id === 0){
|
||||
continue;
|
||||
}
|
||||
|
||||
let deleteThisConnection = true;
|
||||
|
||||
for(let e = 0; e < mapConfig.data.connections.length;e++){
|
||||
let deleteConnectionData = mapConfig.data.connections[e];
|
||||
|
||||
if(deleteConnectionData.id === currentConnectionData[d].id){
|
||||
deleteThisConnection = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(deleteThisConnection === true){
|
||||
// connection not found -> delete connection
|
||||
let deleteConnection = currentConnectionData[d].connection;
|
||||
|
||||
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.deleteConnection(deleteConnection, {fireEvent: false});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mapConfig.map.setSuspendDrawing(false, true);
|
||||
|
||||
// update local connection cache
|
||||
updateConnectionsCache(mapConfig.map);
|
||||
|
||||
|
||||
|
||||
return resolve(payload);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1402,44 +1411,53 @@ define([
|
||||
* @param payload
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let filterMapByScopes = payload => {
|
||||
let filterMapByScopesExecutor = resolve => {
|
||||
Util.getLocalStore('map').getItem(payload.data.mapConfig.config.id).then(dataStore => {
|
||||
let scopes = [];
|
||||
if(dataStore && dataStore.filterScopes){
|
||||
scopes = dataStore.filterScopes;
|
||||
}
|
||||
|
||||
MapUtil.filterMapByScopes(payload.data.mapConfig.map, scopes);
|
||||
resolve(payload);
|
||||
});
|
||||
};
|
||||
|
||||
return new Promise(filterMapByScopesExecutor);
|
||||
};
|
||||
let filterMapByScopes = payload => new Promise(resolve => {
|
||||
Util.getLocalStore('map').getItem(payload.data.mapConfig.config.id).then(dataStore => {
|
||||
let scopes = [];
|
||||
if(dataStore && dataStore.filterScopes){
|
||||
scopes = dataStore.filterScopes;
|
||||
}
|
||||
MapUtil.filterMapByScopes(payload.data.mapConfig.map, scopes);
|
||||
resolve(payload);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* show signature overlays
|
||||
* @param payload
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let showInfoSignatureOverlays = payload => {
|
||||
let showInfoSignatureOverlaysExecutor = resolve => {
|
||||
Util.getLocalStore('map').getItem(payload.data.mapConfig.config.id).then(dataStore => {
|
||||
if(dataStore && dataStore.mapSignatureOverlays){
|
||||
MapOverlay.showInfoSignatureOverlays($(payload.data.mapConfig.map.getContainer()));
|
||||
}
|
||||
let showInfoSignatureOverlays = payload => new Promise(resolve => {
|
||||
Util.getLocalStore('map').getItem(payload.data.mapConfig.config.id).then(dataStore => {
|
||||
if(dataStore && dataStore.mapSignatureOverlays){
|
||||
MapOverlay.showInfoSignatureOverlays($(payload.data.mapConfig.map.getContainer()));
|
||||
}
|
||||
resolve(payload);
|
||||
});
|
||||
});
|
||||
|
||||
resolve(payload);
|
||||
/**
|
||||
* after map update is complete
|
||||
* -> trigger update event for 'global' modules
|
||||
* @param payload
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let afterUpdate = payload => new Promise(resolve => {
|
||||
// in rare cases there is a bug where map is undefined (hard to reproduce
|
||||
let map = Util.getObjVal(payload, 'data.mapConfig.map');
|
||||
if(map){
|
||||
let tabContentEl = map.getContainer().closest(`.${Util.config.mapTabContentClass}`);
|
||||
$(tabContentEl).trigger('pf:updateGlobalModules', {
|
||||
payload: Util.getObjVal(payload, 'data.mapConfig.config.id')
|
||||
});
|
||||
};
|
||||
|
||||
return new Promise(showInfoSignatureOverlaysExecutor);
|
||||
};
|
||||
}
|
||||
resolve(payload);
|
||||
});
|
||||
|
||||
return new Promise(updateMapExecutor)
|
||||
.then(showInfoSignatureOverlays)
|
||||
.then(filterMapByScopes);
|
||||
.then(filterMapByScopes)
|
||||
.then(afterUpdate);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1530,28 +1548,22 @@ define([
|
||||
* @param systemData
|
||||
* @returns {boolean}
|
||||
*/
|
||||
let isValidSystem = systemData => {
|
||||
let isValid = true;
|
||||
if(
|
||||
!systemData.hasOwnProperty('name') ||
|
||||
systemData.name.length === 0
|
||||
){
|
||||
return false;
|
||||
}
|
||||
|
||||
return isValid;
|
||||
};
|
||||
let isValidSystem = systemData => (Util.getObjVal(systemData, 'name') || '').length > 0;
|
||||
|
||||
/**
|
||||
* draw a system with its data to a map
|
||||
* @param map
|
||||
* @param systemData
|
||||
* @param connectedSystem
|
||||
* @param connectionData
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let drawSystem = (map, systemData, connectedSystem) => {
|
||||
|
||||
// check if systemData is valid
|
||||
let drawSystem = (map, systemData, connectedSystem, connectionData = null) => new Promise((resolve, reject) => {
|
||||
if(isValidSystem(systemData)){
|
||||
let payloadDrawSystem = {
|
||||
action: 'drawSystem'
|
||||
};
|
||||
|
||||
let mapContainer = $(map.getContainer());
|
||||
|
||||
// get System Element by data
|
||||
@@ -1575,24 +1587,37 @@ define([
|
||||
// register system to "magnetizer"
|
||||
Magnetizer.addElement(systemData.mapId, newSystem[0]);
|
||||
|
||||
payloadDrawSystem.data = {
|
||||
system: newSystem
|
||||
};
|
||||
|
||||
// connect new system (if connection data is given)
|
||||
if(connectedSystem){
|
||||
|
||||
// hint: "scope + type" might be changed automatically when it gets saved
|
||||
// -> based on jump distance,..
|
||||
let connectionData = {
|
||||
connectionData = Object.assign({}, {
|
||||
source: $(connectedSystem).data('id'),
|
||||
target: newSystem.data('id'),
|
||||
scope: map.Defaults.Scope,
|
||||
type: [MapUtil.getDefaultConnectionTypeByScope(map.Defaults.Scope)]
|
||||
};
|
||||
let connection = drawConnection(map, connectionData);
|
||||
}, connectionData);
|
||||
|
||||
// store connection
|
||||
saveConnection(connection);
|
||||
drawConnection(map, connectionData)
|
||||
.then(payload => saveConnection(payload.data.connection, Boolean(connectionData.disableAutoScope)))
|
||||
.then(payload => {
|
||||
payloadDrawSystem.data = {
|
||||
connection: payload.data.connection
|
||||
};
|
||||
resolve(payloadDrawSystem);
|
||||
})
|
||||
.catch(reject);
|
||||
}else{
|
||||
resolve(payloadDrawSystem);
|
||||
}
|
||||
}else{
|
||||
reject(new Error(`drawSystem() failed. Invalid systemData`));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* make a system name/alias editable by x-editable
|
||||
@@ -1656,56 +1681,69 @@ define([
|
||||
/**
|
||||
* stores a connection in database
|
||||
* @param connection
|
||||
* @param disableAutoScope
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let saveConnection = connection => {
|
||||
if(connection instanceof jsPlumb.Connection){
|
||||
connection.addType('state_process');
|
||||
|
||||
let map = connection._jsPlumb.instance;
|
||||
let mapContainer = $(map.getContainer());
|
||||
let mapId = mapContainer.data('id');
|
||||
|
||||
let connectionData = MapUtil.getDataByConnection(connection);
|
||||
connectionData.mapId = mapId;
|
||||
|
||||
Util.request('PUT', 'connection', [], connectionData, {
|
||||
connection: connection,
|
||||
map: map,
|
||||
mapId: mapId,
|
||||
oldConnectionData: connectionData
|
||||
}).then(
|
||||
payload => {
|
||||
let newConnectionData = payload.data;
|
||||
|
||||
if(!$.isEmptyObject(newConnectionData)){
|
||||
// update connection data e.g. "scope" has auto detected
|
||||
connection = updateConnection(payload.context.connection, newConnectionData);
|
||||
|
||||
// new/updated connection should be cached immediately!
|
||||
updateConnectionCache(payload.context.mapId, connection);
|
||||
|
||||
// connection scope
|
||||
let scope = MapUtil.getScopeInfoForConnection(newConnectionData.scope, 'label');
|
||||
|
||||
let title = 'New connection established';
|
||||
if(payload.context.oldConnectionData.id > 0){
|
||||
title = 'Connection switched';
|
||||
}
|
||||
|
||||
Util.showNotify({title: title, text: 'Scope: ' + scope, type: 'success'});
|
||||
}else{
|
||||
// some save errors
|
||||
payload.context.map.deleteConnection(payload.context.connection, {fireEvent: false});
|
||||
}
|
||||
},
|
||||
payload => {
|
||||
// remove this connection from map
|
||||
payload.context.map.deleteConnection(payload.context.connection, {fireEvent: false});
|
||||
Util.handleAjaxErrorResponse(payload);
|
||||
}
|
||||
);
|
||||
let saveConnection = (connection, disableAutoScope = false) => new Promise((resolve, reject) => {
|
||||
if(!(connection instanceof jsPlumb.Connection)){
|
||||
reject(new Error(`saveConnection(): connection must be instanceof jsPlumb.Connection`));
|
||||
}
|
||||
};
|
||||
|
||||
connection.addType('state_process');
|
||||
|
||||
let map = connection._jsPlumb.instance;
|
||||
let mapContainer = $(map.getContainer());
|
||||
let mapId = mapContainer.data('id');
|
||||
|
||||
let connectionData = MapUtil.getDataByConnection(connection);
|
||||
connectionData.mapId = mapId;
|
||||
connectionData.disableAutoScope = disableAutoScope;
|
||||
|
||||
Util.request('PUT', 'connection', [], connectionData, {
|
||||
connection: connection,
|
||||
map: map,
|
||||
mapId: mapId,
|
||||
oldConnectionData: connectionData
|
||||
}).then(
|
||||
payload => {
|
||||
let newConnectionData = payload.data;
|
||||
|
||||
if(!$.isEmptyObject(newConnectionData)){
|
||||
// update connection data e.g. "scope" has auto detected
|
||||
connection = updateConnection(payload.context.connection, newConnectionData);
|
||||
|
||||
// new/updated connection should be cached immediately!
|
||||
updateConnectionCache(payload.context.mapId, connection);
|
||||
|
||||
// connection scope
|
||||
let scope = MapUtil.getScopeInfoForConnection(newConnectionData.scope, 'label');
|
||||
|
||||
let title = 'New connection established';
|
||||
if(payload.context.oldConnectionData.id > 0){
|
||||
title = 'Connection switched';
|
||||
}
|
||||
|
||||
Util.showNotify({title: title, text: 'Scope: ' + scope, type: 'success'});
|
||||
resolve({
|
||||
action: 'saveConnection',
|
||||
data: {
|
||||
connection: connection
|
||||
}
|
||||
});
|
||||
}else{
|
||||
// some save errors
|
||||
payload.context.map.deleteConnection(payload.context.connection, {fireEvent: false});
|
||||
reject(new Error(`saveConnection(): response error`));
|
||||
}
|
||||
},
|
||||
payload => {
|
||||
// remove this connection from map
|
||||
payload.context.map.deleteConnection(payload.context.connection, {fireEvent: false});
|
||||
Util.handleAjaxErrorResponse(payload);
|
||||
reject(new Error(`saveConnection(): request error`));
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* get context menu config for a map component (e.g. system, connection,..)
|
||||
@@ -1742,7 +1780,7 @@ define([
|
||||
options.hidden.push('delete_system');
|
||||
}
|
||||
|
||||
if( !mapContainer.find('.' + config.systemActiveClass).length){
|
||||
if( !mapContainer.find('.' + MapUtil.config.systemActiveClass).length){
|
||||
options.hidden.push('find_route');
|
||||
}
|
||||
|
||||
@@ -1755,7 +1793,7 @@ define([
|
||||
}
|
||||
|
||||
// disabled menu actions
|
||||
if(system.hasClass(config.systemActiveClass)){
|
||||
if(system.hasClass(MapUtil.config.systemActiveClass)){
|
||||
options.disabled.push('find_route');
|
||||
}
|
||||
|
||||
@@ -1898,6 +1936,8 @@ define([
|
||||
// map overlay will be set on "drag" start
|
||||
let mapOverlayTimer = null;
|
||||
|
||||
let debounceDrag = false;
|
||||
|
||||
// make system draggable
|
||||
map.draggable(system, {
|
||||
containment: 'parent',
|
||||
@@ -1907,7 +1947,7 @@ define([
|
||||
snapThreshold: MapUtil.config.mapSnapToGridDimension, // distance for grid snapping "magnet" effect (optional)
|
||||
start: function(params){
|
||||
let dragSystem = $(params.el);
|
||||
|
||||
dragSystem.css('pointer-events','none');
|
||||
mapOverlayTimer = MapOverlayUtil.getMapOverlay(dragSystem, 'timer');
|
||||
|
||||
// start map update timer
|
||||
@@ -1920,9 +1960,6 @@ define([
|
||||
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
|
||||
let selectedSystems = mapContainer.getSelectedSystems().get();
|
||||
selectedSystems = selectedSystems.concat(dragSystem.get());
|
||||
@@ -1938,12 +1975,19 @@ define([
|
||||
$(selectedSystems).updateSystemZIndex();
|
||||
},
|
||||
drag: function(p){
|
||||
// start map update timer
|
||||
mapOverlayTimer.startMapUpdateCounter();
|
||||
if(!debounceDrag) {
|
||||
requestAnimationFrame(() => {
|
||||
// start map update timer
|
||||
mapOverlayTimer.startMapUpdateCounter();
|
||||
|
||||
// update system positions for "all" systems that are effected by drag&drop
|
||||
// this requires "magnet" feature to be active! (optional)
|
||||
Magnetizer.executeAtEvent(map, p.e);
|
||||
// update system positions for "all" systems that are effected by drag&drop
|
||||
// this requires "magnet" feature to be active! (optional)
|
||||
Magnetizer.executeAtEvent(map, p.e);
|
||||
|
||||
debounceDrag = false;
|
||||
});
|
||||
}
|
||||
debounceDrag = true;
|
||||
},
|
||||
stop: function(params){
|
||||
let dragSystem = $(params.el);
|
||||
@@ -1951,10 +1995,6 @@ define([
|
||||
// start map update timer
|
||||
mapOverlayTimer.startMapUpdateCounter();
|
||||
|
||||
setTimeout(function(){
|
||||
dragSystem.removeClass('no-click');
|
||||
}, Init.timer.DBL_CLICK + 50);
|
||||
|
||||
// show tooltip
|
||||
dragSystem.toggleSystemTooltip('show', {show: true});
|
||||
|
||||
@@ -1975,7 +2015,7 @@ define([
|
||||
|
||||
// update all dragged systems -> added to DragSelection
|
||||
params.selection.forEach(elData => {
|
||||
MapUtil.markAsChanged($(elData[0]));
|
||||
MapUtil.markAsChanged($(elData[0]).css('pointer-events','initial'));
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -2016,23 +2056,20 @@ define([
|
||||
if(!popoverClick){
|
||||
let system = $(this);
|
||||
|
||||
// check if system is locked for "click" events
|
||||
if(!system.hasClass('no-click')){
|
||||
// left mouse button
|
||||
if(e.which === 1){
|
||||
if(e.ctrlKey === true){
|
||||
// select system
|
||||
MapUtil.toggleSystemsSelect(map, [system]);
|
||||
}else{
|
||||
MapUtil.showSystemInfo(map, system);
|
||||
}
|
||||
// left mouse button
|
||||
if(e.which === 1){
|
||||
if(e.ctrlKey === true){
|
||||
// select system
|
||||
MapUtil.toggleSystemsSelect(map, [system]);
|
||||
}else{
|
||||
MapUtil.showSystemInfo(map, system);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Util.singleDoubleClick(system, single, double);
|
||||
Util.singleDoubleClick(system[0], single, double);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -2040,10 +2077,10 @@ define([
|
||||
* @param map
|
||||
* @param newSystemData
|
||||
* @param sourceSystem
|
||||
* @param connectionData
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let saveSystemCallback = (map, newSystemData, sourceSystem) => {
|
||||
drawSystem(map, newSystemData, sourceSystem);
|
||||
};
|
||||
let saveSystemCallback = (map, newSystemData, sourceSystem, connectionData = null) => drawSystem(map, newSystemData, sourceSystem, connectionData);
|
||||
|
||||
/**
|
||||
* select all (selectable) systems on a mapElement
|
||||
@@ -2193,17 +2230,8 @@ define([
|
||||
return false;
|
||||
}
|
||||
|
||||
// lock the target system for "click" events
|
||||
// to prevent loading system information
|
||||
let sourceSystem = $('#' + sourceId);
|
||||
let targetSystem = $('#' + targetId);
|
||||
sourceSystem.addClass('no-click');
|
||||
targetSystem.addClass('no-click');
|
||||
|
||||
setTimeout(() => {
|
||||
sourceSystem.removeClass('no-click');
|
||||
targetSystem.removeClass('no-click');
|
||||
}, Init.timer.DBL_CLICK + 50);
|
||||
|
||||
// switch connection type to "abyss" in case source OR target system belongs to "a-space"
|
||||
if(sourceSystem.data('typeId') === 3 || targetSystem.data('typeId') === 3){
|
||||
@@ -2227,7 +2255,7 @@ define([
|
||||
}
|
||||
|
||||
// always save the new connection
|
||||
saveConnection(connection);
|
||||
saveConnection(connection).catch(console.warn);
|
||||
|
||||
return true;
|
||||
});
|
||||
@@ -2721,7 +2749,7 @@ define([
|
||||
selectSystem(mapContainer, data);
|
||||
break;
|
||||
case 'AddSystem':
|
||||
System.showNewSystemDialog(map, data, saveSystemCallback);
|
||||
System.showNewSystemDialog(map, data, typeof data.callback === 'function' ? data.callback : saveSystemCallback);
|
||||
break;
|
||||
default:
|
||||
console.warn('Unknown menuAction %o event name', action);
|
||||
@@ -2938,16 +2966,16 @@ define([
|
||||
|
||||
/**
|
||||
* collect all map data from client for server or client sync
|
||||
* @param mapContainer
|
||||
* @param {HTMLElement} mapContainer
|
||||
* @param filter
|
||||
* @param minimal
|
||||
* @returns {boolean}
|
||||
* @returns {boolean|{}}
|
||||
*/
|
||||
let getMapDataForSync = (mapContainer, filter = [], minimal = false) => {
|
||||
let mapData = false;
|
||||
// check if there is an active map counter that prevents collecting map data (locked map)
|
||||
if(!MapOverlayUtil.getMapOverlayInterval(mapContainer)){
|
||||
mapData = mapContainer.getMapDataFromClient(filter, minimal);
|
||||
if(!MapOverlayUtil.isMapCounterOverlayActive(mapContainer)){
|
||||
mapData = $(mapContainer).getMapDataFromClient(filter, minimal);
|
||||
}
|
||||
return mapData;
|
||||
};
|
||||
@@ -2957,6 +2985,7 @@ define([
|
||||
* this function returns the "client" data NOT the "server" data for a map
|
||||
* @param filter
|
||||
* @param minimal
|
||||
* @returns {{}}
|
||||
*/
|
||||
$.fn.getMapDataFromClient = function(filter = [], minimal = false){
|
||||
let mapContainer = $(this);
|
||||
@@ -3099,34 +3128,29 @@ define([
|
||||
* @param options
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let initMapOptions = (mapConfig, options) => {
|
||||
|
||||
let initMapOptionsExecutor = (resolve, reject) => {
|
||||
let payload = {
|
||||
action: 'initMapOptions',
|
||||
data: {
|
||||
mapConfig: mapConfig
|
||||
}
|
||||
};
|
||||
|
||||
if(options.showAnimation){
|
||||
let mapElement = $(mapConfig.map.getContainer());
|
||||
MapUtil.setMapDefaultOptions(mapElement, mapConfig.config)
|
||||
.then(payload => MapUtil.visualizeMap(mapElement, 'show'))
|
||||
.then(payload => MapUtil.zoomToDefaultScale(mapConfig.map))
|
||||
.then(payload => MapUtil.scrollToDefaultPosition(mapConfig.map))
|
||||
.then(payload => {
|
||||
Util.showNotify({title: 'Map initialized', text: mapConfig.config.name + ' - loaded', type: 'success'});
|
||||
})
|
||||
.then(() => resolve(payload));
|
||||
}else{
|
||||
// nothing to do here...
|
||||
resolve(payload);
|
||||
let initMapOptions = (mapConfig, options) => new Promise((resolve, reject) => {
|
||||
let payload = {
|
||||
action: 'initMapOptions',
|
||||
data: {
|
||||
mapConfig: mapConfig
|
||||
}
|
||||
};
|
||||
|
||||
return new Promise(initMapOptionsExecutor);
|
||||
};
|
||||
if(options.showAnimation){
|
||||
let mapElement = $(mapConfig.map.getContainer());
|
||||
MapUtil.setMapDefaultOptions(mapElement, mapConfig.config)
|
||||
.then(payload => MapUtil.visualizeMap(mapElement, 'show'))
|
||||
.then(payload => MapUtil.zoomToDefaultScale(mapConfig.map))
|
||||
.then(payload => MapUtil.scrollToDefaultPosition(mapConfig.map))
|
||||
.then(payload => {
|
||||
Util.showNotify({title: 'Map initialized', text: mapConfig.config.name + ' - loaded', type: 'success'});
|
||||
})
|
||||
.then(() => resolve(payload));
|
||||
}else{
|
||||
// nothing to do here...
|
||||
resolve(payload);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* load OR updates system map
|
||||
@@ -3136,6 +3160,9 @@ define([
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let loadMap = (areaMap, mapConfig, options) => {
|
||||
// whether map gets loaded (initialized) for the first time
|
||||
// or just updated an existing map
|
||||
let isFirstLoad = false;
|
||||
|
||||
/**
|
||||
* load map promise
|
||||
@@ -3150,6 +3177,7 @@ define([
|
||||
|
||||
if(mapConfig.map.getContainer() === undefined){
|
||||
// map not loaded -> create & update
|
||||
isFirstLoad = true;
|
||||
newMapElement(areaMap, mapConfig)
|
||||
.then(payload => updateMap(payload.data.mapConfig))
|
||||
.then(payload => resolve(payload));
|
||||
@@ -3162,7 +3190,12 @@ define([
|
||||
};
|
||||
|
||||
return new Promise(loadMapExecutor)
|
||||
.then(payload => initMapOptions(payload.data.mapConfig, options));
|
||||
.then(payload => initMapOptions(payload.data.mapConfig, options))
|
||||
.then(payload => ({
|
||||
action: 'loadMap',
|
||||
data: payload.data,
|
||||
isFirstLoad
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -3330,7 +3363,9 @@ define([
|
||||
loadMap: loadMap,
|
||||
updateUserData: updateUserData,
|
||||
getMapDataForSync: getMapDataForSync,
|
||||
saveSystemCallback: saveSystemCallback
|
||||
saveSystemCallback: saveSystemCallback,
|
||||
drawConnection: drawConnection,
|
||||
saveConnection: saveConnection
|
||||
};
|
||||
|
||||
});
|
||||
@@ -7,8 +7,9 @@ define([
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/map/overlay/util',
|
||||
'app/map/util'
|
||||
], ($, Init, Util, MapOverlayUtil, MapUtil) => {
|
||||
'app/map/util',
|
||||
'app/lib/cron'
|
||||
], ($, Init, Util, MapOverlayUtil, MapUtil, Cron) => {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
@@ -107,119 +108,120 @@ define([
|
||||
let type = 'info_signature';
|
||||
connectionsData = Util.arrayToObject(connectionsData);
|
||||
|
||||
map.batch(() => {
|
||||
map.getAllConnections().forEach(connection => {
|
||||
let connectionId = connection.getParameter('connectionId');
|
||||
let sourceEndpoint = connection.endpoints[0];
|
||||
let targetEndpoint = connection.endpoints[1];
|
||||
map.setSuspendDrawing(true);
|
||||
|
||||
let connectionData = connectionsData.hasOwnProperty(connectionId) ? connectionsData[connectionId] : undefined;
|
||||
let signatureTypeData = MapUtil.getConnectionDataFromSignatures(connection, connectionData);
|
||||
map.getAllConnections().forEach(connection => {
|
||||
let connectionId = connection.getParameter('connectionId');
|
||||
let sourceEndpoint = connection.endpoints[0];
|
||||
let targetEndpoint = connection.endpoints[1];
|
||||
|
||||
let sizeLockedBySignature = false;
|
||||
let connectionData = Util.getObjVal(connectionsData, `${connectionId}`);
|
||||
let signatureTypeData = MapUtil.getConnectionDataFromSignatures(connection, connectionData);
|
||||
|
||||
if(connection.scope === 'wh'){
|
||||
if(!connection.hasType(type)){
|
||||
connection.addType(type);
|
||||
}
|
||||
let sizeLockedBySignature = false;
|
||||
|
||||
let overlayArrow = connection.getOverlay(MapOverlayUtil.config.connectionOverlayArrowId);
|
||||
if(connection.scope === 'wh'){
|
||||
if(!connection.hasType(type)){
|
||||
connection.addType(type);
|
||||
}
|
||||
|
||||
// Arrow overlay needs to be cleared() (removed) if 'info_signature' gets removed!
|
||||
// jsPlumb does not handle overlay updates for Arrow overlays... so we need to re-apply the the overlay manually
|
||||
if(overlayArrow.path && !overlayArrow.path.isConnected){
|
||||
connection.canvas.appendChild(overlayArrow.path);
|
||||
}
|
||||
let overlayArrow = connection.getOverlay(MapOverlayUtil.config.connectionOverlayArrowId);
|
||||
|
||||
// since there "could" be multiple sig labels on each endpoint,
|
||||
// there can only one "primary label picked up for wormhole jump mass detection!
|
||||
let primLabel;
|
||||
// Arrow overlay needs to be cleared() (removed) if 'info_signature' gets removed!
|
||||
// jsPlumb does not handle overlay updates for Arrow overlays... so we need to re-apply the the overlay manually
|
||||
if(overlayArrow.path && !overlayArrow.path.isConnected){
|
||||
connection.canvas.appendChild(overlayArrow.path);
|
||||
}
|
||||
|
||||
let overlayType = 'diamond'; // not specified
|
||||
let arrowDirection = 1;
|
||||
// since there "could" be multiple sig labels on each endpoint,
|
||||
// there can only one "primary label picked up for wormhole jump mass detection!
|
||||
let primeLabel;
|
||||
|
||||
if(connectionData && connectionData.signatures){
|
||||
// signature data found for current connection
|
||||
let sourceLabel = signatureTypeData.source.labels;
|
||||
let targetLabel = signatureTypeData.target.labels;
|
||||
let overlayType = 'diamond'; // not specified
|
||||
let arrowDirection = 1;
|
||||
|
||||
// add arrow (connection) overlay that points from "XXX" => "K162" ----------------------------
|
||||
if(
|
||||
(sourceLabel.includes('K162') && targetLabel.includes('K162')) ||
|
||||
(sourceLabel.length === 0 && targetLabel.length === 0) ||
|
||||
(
|
||||
sourceLabel.length > 0 && targetLabel.length > 0 &&
|
||||
!sourceLabel.includes('K162') && !targetLabel.includes('K162')
|
||||
)
|
||||
){
|
||||
// unknown direction -> show default 'diamond' overlay
|
||||
overlayType = 'diamond';
|
||||
}else if(
|
||||
(sourceLabel.includes('K162')) ||
|
||||
(sourceLabel.length === 0 && !targetLabel.includes('K162'))
|
||||
){
|
||||
// convert default arrow direction
|
||||
overlayType = 'arrow';
|
||||
arrowDirection = -1;
|
||||
if(connectionData && connectionData.signatures){
|
||||
// signature data found for current connection
|
||||
let sourceLabel = signatureTypeData.source.labels;
|
||||
let targetLabel = signatureTypeData.target.labels;
|
||||
|
||||
primLabel = targetLabel.find(label => label !== 'K162');
|
||||
}else{
|
||||
// default arrow direction is fine
|
||||
overlayType = 'arrow';
|
||||
// add arrow (connection) overlay that points from "XXX" => "K162" ----------------------------
|
||||
if(
|
||||
(sourceLabel.includes('K162') && targetLabel.includes('K162')) ||
|
||||
(sourceLabel.length === 0 && targetLabel.length === 0) ||
|
||||
(
|
||||
sourceLabel.length > 0 && targetLabel.length > 0 &&
|
||||
!sourceLabel.includes('K162') && !targetLabel.includes('K162')
|
||||
)
|
||||
){
|
||||
// unknown direction -> show default 'diamond' overlay
|
||||
overlayType = 'diamond';
|
||||
}else if(
|
||||
(sourceLabel.includes('K162')) ||
|
||||
(sourceLabel.length === 0 && !targetLabel.includes('K162'))
|
||||
){
|
||||
// convert default arrow direction
|
||||
overlayType = 'arrow';
|
||||
arrowDirection = -1;
|
||||
|
||||
primLabel = sourceLabel.find(label => label !== 'K162');
|
||||
}
|
||||
}
|
||||
|
||||
// class changes must be done on "connection" itself not on "overlayArrow"
|
||||
// -> because Arrow might not be rendered to map at this point (if it does not exist already)
|
||||
if(overlayType === 'arrow'){
|
||||
connection.updateClasses(
|
||||
MapOverlayUtil.config.connectionArrowOverlaySuccessClass,
|
||||
MapOverlayUtil.config.connectionArrowOverlayDangerClass
|
||||
);
|
||||
primeLabel = targetLabel.find(label => label !== 'K162');
|
||||
}else{
|
||||
connection.updateClasses(
|
||||
MapOverlayUtil.config.connectionArrowOverlayDangerClass,
|
||||
MapOverlayUtil.config.connectionArrowOverlaySuccessClass
|
||||
);
|
||||
}
|
||||
// default arrow direction is fine
|
||||
overlayType = 'arrow';
|
||||
|
||||
overlayArrow.updateFrom(getConnectionArrowOverlayParams(overlayType, arrowDirection));
|
||||
|
||||
// update/add endpoint overlays -------------------------------------------------------------------
|
||||
updateEndpointOverlaySignatureLabel(sourceEndpoint, signatureTypeData.source);
|
||||
updateEndpointOverlaySignatureLabel(targetEndpoint, signatureTypeData.target);
|
||||
|
||||
// fix/overwrite existing jump mass connection type -----------------------------------------------
|
||||
// if a connection type for "jump mass" (e.g. S, M, L, XL) is set for this connection
|
||||
// we should check/compare it with the current primary signature label from signature mapping
|
||||
// and change it if necessary
|
||||
if(Init.wormholes.hasOwnProperty(primLabel)){
|
||||
// connection size from mapped signature
|
||||
sizeLockedBySignature = true;
|
||||
|
||||
let wormholeData = Object.assign({}, Init.wormholes[primLabel]);
|
||||
// get 'connection mass type' from wormholeData
|
||||
let massType = Util.getObjVal(wormholeData, 'size.type');
|
||||
|
||||
if(massType && !connection.hasType(massType)){
|
||||
MapOverlayUtil.getMapOverlay(connection.canvas, 'timer').startMapUpdateCounter();
|
||||
MapUtil.setConnectionJumpMassType(connection, wormholeData.size.type);
|
||||
MapUtil.markAsChanged(connection);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// connection is not 'wh' scope
|
||||
if(connection.hasType(type)){
|
||||
connection.removeType(type);
|
||||
primeLabel = sourceLabel.find(label => label !== 'K162');
|
||||
}
|
||||
}
|
||||
|
||||
// lock/unlock connection for manual size changes (from contextmenu)
|
||||
connection.setParameter('sizeLocked', sizeLockedBySignature);
|
||||
});
|
||||
// class changes must be done on "connection" itself not on "overlayArrow"
|
||||
// -> because Arrow might not be rendered to map at this point (if it does not exist already)
|
||||
if(overlayType === 'arrow'){
|
||||
connection.updateClasses(
|
||||
MapOverlayUtil.config.connectionArrowOverlaySuccessClass,
|
||||
MapOverlayUtil.config.connectionArrowOverlayDangerClass
|
||||
);
|
||||
}else{
|
||||
connection.updateClasses(
|
||||
MapOverlayUtil.config.connectionArrowOverlayDangerClass,
|
||||
MapOverlayUtil.config.connectionArrowOverlaySuccessClass
|
||||
);
|
||||
}
|
||||
|
||||
overlayArrow.updateFrom(getConnectionArrowOverlayParams(overlayType, arrowDirection));
|
||||
|
||||
// update/add endpoint overlays -------------------------------------------------------------------
|
||||
updateEndpointOverlaySignatureLabel(sourceEndpoint, signatureTypeData.source);
|
||||
updateEndpointOverlaySignatureLabel(targetEndpoint, signatureTypeData.target);
|
||||
|
||||
// fix/overwrite existing jump mass connection type -----------------------------------------------
|
||||
// if a connection type for "jump mass" (e.g. S, M, L, XL) is set for this connection
|
||||
// we should check/compare it with the current primary signature label from signature mapping
|
||||
// and change it if necessary
|
||||
if(Init.wormholes.hasOwnProperty(primeLabel)){
|
||||
// connection size from mapped signature
|
||||
sizeLockedBySignature = true;
|
||||
|
||||
// get 'connection mass type' from wormholeData
|
||||
let massType = Util.getObjVal(Object.assign({}, Init.wormholes[primeLabel]), 'size.type');
|
||||
|
||||
if(massType && !connection.hasType(massType)){
|
||||
MapOverlayUtil.getMapOverlay(connection.canvas, 'timer').startMapUpdateCounter();
|
||||
MapUtil.setConnectionJumpMassType(connection, massType);
|
||||
MapUtil.markAsChanged(connection);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// connection is not 'wh' scope
|
||||
if(connection.hasType(type)){
|
||||
connection.removeType(type);
|
||||
}
|
||||
}
|
||||
|
||||
// lock/unlock connection for manual size changes (from contextmenu)
|
||||
connection.setParameter('sizeLocked', sizeLockedBySignature);
|
||||
});
|
||||
|
||||
map.setSuspendDrawing(false, true);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -291,21 +293,23 @@ define([
|
||||
let map = MapUtil.getMapInstance(mapId);
|
||||
let type = 'info_signature';
|
||||
|
||||
map.batch(() => {
|
||||
map.getAllConnections().forEach(connection => {
|
||||
let overlayArrow = connection.getOverlay(MapOverlayUtil.config.connectionOverlayArrowId);
|
||||
map.setSuspendDrawing(true);
|
||||
|
||||
if(overlayArrow){
|
||||
overlayArrow.cleanup();
|
||||
}
|
||||
map.getAllConnections().forEach(connection => {
|
||||
let overlayArrow = connection.getOverlay(MapOverlayUtil.config.connectionOverlayArrowId);
|
||||
|
||||
if(connection.hasType(type)){
|
||||
connection.removeType(type, {}, true);
|
||||
}
|
||||
});
|
||||
if(overlayArrow){
|
||||
overlayArrow.cleanup();
|
||||
}
|
||||
|
||||
map.selectEndpoints().removeOverlay(MapOverlayUtil.config.endpointOverlayId);
|
||||
if(connection.hasType(type)){
|
||||
connection.removeType(type, {}, true);
|
||||
}
|
||||
});
|
||||
|
||||
map.selectEndpoints().removeOverlay(MapOverlayUtil.config.endpointOverlayId);
|
||||
|
||||
map.setSuspendDrawing(false, true);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -321,7 +325,7 @@ define([
|
||||
trigger: 'active',
|
||||
class: 'pf-map-overlay-filter',
|
||||
iconClass: ['fas', 'fa-fw', 'fa-filter'],
|
||||
onClick: function(e){
|
||||
onClick: function(e){
|
||||
// clear all filter
|
||||
let mapElement = MapOverlayUtil.getMapElementFromOverlay(this);
|
||||
let map = getMapObjectFromOverlayIcon(this);
|
||||
@@ -484,108 +488,96 @@ define([
|
||||
* @param mapOverlayTimer
|
||||
* @param percent
|
||||
* @param value
|
||||
* @returns {*}
|
||||
*/
|
||||
let setMapUpdateCounter = (mapOverlayTimer, percent, value) => {
|
||||
let setMapUpdateCounter = (mapOverlayTimer, percent, value = '') => {
|
||||
// check if counter already exists
|
||||
let counterChart = MapOverlayUtil.getMapCounter(mapOverlayTimer);
|
||||
|
||||
if(counterChart.length === 0){
|
||||
if(!MapOverlayUtil.getMapCounter(mapOverlayTimer)){
|
||||
// create new counter
|
||||
let chartEl = Object.assign(document.createElement('div'), {
|
||||
className: `${Init.classes.pieChart.class} ${Init.classes.pieChart.pieChartMapCounterClass}`
|
||||
});
|
||||
|
||||
counterChart = $('<div>', {
|
||||
class: [Init.classes.pieChart.class, Init.classes.pieChart.pieChartMapCounterClass].join(' ')
|
||||
}).attr('data-percent', percent).append(
|
||||
$('<span>', {
|
||||
text: value
|
||||
})
|
||||
);
|
||||
let chartInnerEl = Object.assign(document.createElement('span'), {
|
||||
textContent: value
|
||||
});
|
||||
let iconEl = Object.assign(document.createElement('i'), {
|
||||
className: ['fas', 'fa-fw', 'fa-lock'].join(' ')
|
||||
});
|
||||
|
||||
mapOverlayTimer.append(counterChart);
|
||||
chartInnerEl.append(iconEl);
|
||||
chartEl.append(chartInnerEl);
|
||||
mapOverlayTimer.append(chartEl);
|
||||
|
||||
// init counter
|
||||
counterChart.initMapUpdateCounter();
|
||||
$(chartEl).initMapUpdateCounter();
|
||||
|
||||
// set tooltip
|
||||
mapOverlayTimer.attr('data-placement', 'left');
|
||||
mapOverlayTimer.attr('title', 'update counter');
|
||||
mapOverlayTimer.tooltip();
|
||||
mapOverlayTimer.dataset.placement = 'left';
|
||||
mapOverlayTimer.setAttribute('title', 'update counter');
|
||||
$(mapOverlayTimer).tooltip();
|
||||
}
|
||||
|
||||
return counterChart;
|
||||
};
|
||||
|
||||
/**
|
||||
* start the map update counter or reset
|
||||
*/
|
||||
$.fn.startMapUpdateCounter = function(){
|
||||
let mapOverlayTimer = $(this);
|
||||
let counterChart = MapOverlayUtil.getMapCounter(mapOverlayTimer);
|
||||
|
||||
let maxSeconds = MapOverlayUtil.config.logTimerCount;
|
||||
|
||||
let counterChartLabel = counterChart.find('span');
|
||||
|
||||
let percentPerCount = 100 / maxSeconds;
|
||||
|
||||
// update counter
|
||||
let updateChart = tempSeconds => {
|
||||
let pieChart = counterChart.data('easyPieChart');
|
||||
|
||||
if(pieChart !== undefined){
|
||||
counterChart.data('easyPieChart').update( percentPerCount * tempSeconds);
|
||||
}
|
||||
counterChartLabel.text(tempSeconds);
|
||||
};
|
||||
|
||||
// main timer function is called on any counter update
|
||||
let timer = mapUpdateCounter => {
|
||||
// decrease timer
|
||||
let currentSeconds = counterChart.data('currentSeconds');
|
||||
currentSeconds--;
|
||||
counterChart.data('currentSeconds', currentSeconds);
|
||||
|
||||
if(currentSeconds >= 0){
|
||||
// update counter
|
||||
updateChart(currentSeconds);
|
||||
}else{
|
||||
// hide counter and reset
|
||||
clearInterval(mapUpdateCounter);
|
||||
|
||||
mapOverlayTimer.velocity('transition.whirlOut', {
|
||||
duration: Init.animationSpeed.mapOverlay,
|
||||
complete: function(){
|
||||
counterChart.data('interval', false);
|
||||
MapOverlayUtil.getMapElementFromOverlay(mapOverlayTimer).trigger('pf:unlocked');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// get current seconds (in case the timer is already running)
|
||||
let currentSeconds = counterChart.data('currentSeconds');
|
||||
|
||||
// start values for timer and chart
|
||||
counterChart.data('currentSeconds', maxSeconds);
|
||||
updateChart(maxSeconds);
|
||||
|
||||
if(
|
||||
currentSeconds === undefined ||
|
||||
currentSeconds < 0
|
||||
){
|
||||
// start timer
|
||||
let mapUpdateCounter = setInterval(() => {
|
||||
timer(mapUpdateCounter);
|
||||
}, 1000);
|
||||
|
||||
// store counter interval
|
||||
counterChart.data('interval', mapUpdateCounter);
|
||||
|
||||
// show overlay
|
||||
if(mapOverlayTimer.is(':hidden')){
|
||||
mapOverlayTimer.velocity('stop').velocity('transition.whirlIn', { duration: Init.animationSpeed.mapOverlay });
|
||||
}
|
||||
if(!this.length){
|
||||
console.warn('startMapUpdateCounter() failed. Missing DOM node');
|
||||
return;
|
||||
}
|
||||
let mapOverlayTimer = this[0];
|
||||
let counterChart = MapOverlayUtil.getMapCounter(mapOverlayTimer);
|
||||
let pieChart = $(counterChart).data('easyPieChart');
|
||||
|
||||
if(!pieChart){
|
||||
console.warn('startMapUpdateCounter() failed. easyPieChart not initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
let updateChart = (percent = 0) => {
|
||||
if(pieChart){
|
||||
pieChart.update(percent);
|
||||
}
|
||||
};
|
||||
|
||||
let task = counterChart.getData('counterTask');
|
||||
if(!task){
|
||||
let tabContentEl = mapOverlayTimer.closest(`.${Util.config.mapTabContentClass}`);
|
||||
let mapId = parseInt(tabContentEl.dataset.mapId) || 0;
|
||||
task = Cron.new(`mapUpdateCounter_${mapId}`, {
|
||||
precision: 'secondTenths',
|
||||
isParallel: true,
|
||||
targetRunCount: 10 * MapOverlayUtil.config.logTimerCount
|
||||
});
|
||||
|
||||
task.task = (timer, task) => {
|
||||
// debounce 80% (reduce repaint)
|
||||
if(task.runCount % 5 === 0){
|
||||
let progress = Math.round(task.targetProgress);
|
||||
updateChart(100 - progress);
|
||||
}
|
||||
|
||||
if(task.targetAchieved){
|
||||
$(mapOverlayTimer).velocity('transition.whirlOut', {
|
||||
duration: Init.animationSpeed.mapOverlay,
|
||||
complete: function(){
|
||||
MapOverlayUtil.getMapElementFromOverlay(mapOverlayTimer).trigger('pf:unlocked');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
counterChart.setData('counterTask', task);
|
||||
}
|
||||
|
||||
// task is not connected if: 'targetAchieved' or not started
|
||||
if(!task.isConnected()){
|
||||
$(mapOverlayTimer).velocity('stop').velocity('transition.whirlIn', { duration: Init.animationSpeed.mapOverlay });
|
||||
}
|
||||
updateChart(100);
|
||||
task.reset();
|
||||
task.start();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -836,36 +828,35 @@ define([
|
||||
});
|
||||
|
||||
// add all overlay elements
|
||||
for(let prop in options){
|
||||
if(options.hasOwnProperty(prop)){
|
||||
let icon = $('<i>', {
|
||||
class: options[prop].iconClass.concat( ['pull-right', options[prop].class] ).join(' ')
|
||||
}).attr('title', options[prop].title).tooltip({
|
||||
placement: 'bottom',
|
||||
container: 'body',
|
||||
delay: 150
|
||||
});
|
||||
Object.entries(options).forEach(([key, option]) => {
|
||||
let icon = $('<i>', {
|
||||
class: option.iconClass.concat(['pull-right', option.class]).join(' ')
|
||||
}).attr('title', option.title).tooltip({
|
||||
placement: 'bottom',
|
||||
container: 'body',
|
||||
delay: 150
|
||||
});
|
||||
|
||||
// add "hover" action for some icons
|
||||
if(
|
||||
options[prop].trigger === 'hover' ||
|
||||
options[prop].trigger === 'refresh'
|
||||
){
|
||||
icon.hoverIntent(options[prop].hoverIntent);
|
||||
}
|
||||
|
||||
// add "click" handler for some icons
|
||||
if(options[prop].hasOwnProperty('onClick')){
|
||||
icon.on('click', options[prop].onClick);
|
||||
}
|
||||
|
||||
mapOverlayInfo.append(icon);
|
||||
// add "hover" action for some icons
|
||||
if(
|
||||
option.trigger === 'hover' ||
|
||||
option.trigger === 'refresh'
|
||||
){
|
||||
icon.hoverIntent(option.hoverIntent);
|
||||
}
|
||||
}
|
||||
|
||||
// add "click" handler for some icons
|
||||
if(option.hasOwnProperty('onClick')){
|
||||
icon.on('click', option.onClick);
|
||||
}
|
||||
|
||||
mapOverlayInfo.append(icon);
|
||||
});
|
||||
|
||||
parentElement.append(mapOverlayInfo);
|
||||
|
||||
// reset map update timer
|
||||
setMapUpdateCounter(mapOverlayTimer, 100, MapOverlayUtil.config.logTimerCount);
|
||||
setMapUpdateCounter(mapOverlayTimer[0], 100);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -84,22 +84,32 @@ define([
|
||||
/**
|
||||
* get the map counter chart from overlay
|
||||
* @param element
|
||||
* @returns {jQuery}
|
||||
* @returns {Element}
|
||||
*/
|
||||
let getMapCounter = element => $(element).find('.' + Init.classes.pieChart.pieChartMapCounterClass);
|
||||
let getMapCounter = element => element.querySelector(`.${Init.classes.pieChart.pieChartMapCounterClass}`);
|
||||
|
||||
/**
|
||||
* get interval value from map timer overlay
|
||||
* @param element
|
||||
* @returns {*}
|
||||
* if there is an "active" (connected) counter task
|
||||
* -> lock overlay
|
||||
* @param {HTMLElement} element
|
||||
* @returns {boolean}
|
||||
*/
|
||||
let getMapOverlayInterval = element => getMapCounter(getMapOverlay(element, 'timer')).data('interval');
|
||||
let isMapCounterOverlayActive = element => {
|
||||
let mapOverlay = getMapOverlay(element, 'timer');
|
||||
if(mapOverlay){
|
||||
let mapCounter = getMapCounter(mapOverlay[0]);
|
||||
if(mapCounter && mapCounter.getData('counterTask')){
|
||||
return mapCounter.getData('counterTask').isConnected();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
return {
|
||||
config: config,
|
||||
getMapOverlay: getMapOverlay,
|
||||
getMapElementFromOverlay: getMapElementFromOverlay,
|
||||
getMapCounter: getMapCounter,
|
||||
getMapOverlayInterval: getMapOverlayInterval
|
||||
isMapCounterOverlayActive: isMapCounterOverlayActive
|
||||
};
|
||||
});
|
||||
@@ -23,7 +23,6 @@ define([
|
||||
systemHeadInfoLeftClass: 'pf-system-head-info-left', // class for left system info
|
||||
systemHeadInfoRightClass: 'pf-system-head-info-right', // class for right system info
|
||||
|
||||
systemActiveClass: 'pf-system-active', // class for an active system on a map
|
||||
systemTooltipInnerIdPrefix: 'pf-system-tooltip-inner-', // id prefix for system tooltip content
|
||||
systemTooltipInnerClass: 'pf-system-tooltip-inner', // class for system tooltip content
|
||||
|
||||
@@ -231,24 +230,26 @@ define([
|
||||
if(formValid === false) return false;
|
||||
|
||||
// calculate new system position ----------------------------------------------------------
|
||||
let newPosition = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
let newPosition;
|
||||
|
||||
// add new position
|
||||
let sourceSystem = null;
|
||||
let connectionData = null;
|
||||
if(options.sourceSystem !== undefined){
|
||||
// new position based on sourceSystem´s position
|
||||
sourceSystem = options.sourceSystem;
|
||||
connectionData = options.connectionData || null;
|
||||
|
||||
// get new position
|
||||
newPosition = newSystemPositionBySystem(sourceSystem);
|
||||
}else if(options.position){
|
||||
// check mouse cursor position (add system to map)
|
||||
// new position based on coordinated (e.g. mouse event)
|
||||
newPosition = {
|
||||
x: options.position.x,
|
||||
y: options.position.y
|
||||
};
|
||||
}else{
|
||||
// new position based on current map scroll offset
|
||||
newPosition = MapUtil.newSystemPositionsByMapOffset(mapContainer)[0];
|
||||
}
|
||||
|
||||
formData.position = newPosition;
|
||||
@@ -262,7 +263,8 @@ define([
|
||||
systemDialog: systemDialog,
|
||||
formElement: form,
|
||||
map: map,
|
||||
sourceSystem: sourceSystem
|
||||
sourceSystem: sourceSystem,
|
||||
connectionData: connectionData
|
||||
}, context => {
|
||||
// always do
|
||||
context.systemDialog.find('.modal-content').hideLoadingAnimation();
|
||||
@@ -270,7 +272,7 @@ define([
|
||||
payload => {
|
||||
Util.showNotify({title: 'New system', text: payload.data.name, type: 'success'});
|
||||
|
||||
callback(payload.context.map, payload.data, payload.context.sourceSystem);
|
||||
callback(payload.context.map, payload.data, payload.context.sourceSystem, payload.context.connectionData);
|
||||
bootbox.hideAll();
|
||||
},
|
||||
Util.handleAjaxErrorResponse
|
||||
@@ -699,10 +701,12 @@ define([
|
||||
|
||||
for(let system of systems){
|
||||
system = $(system);
|
||||
let mapId = parseInt(system.data('mapid')) || 0;
|
||||
|
||||
// check if system is "active"
|
||||
if(system.hasClass(config.systemActiveClass)){
|
||||
delete Init.currentSystemData;
|
||||
if(system.hasClass(MapUtil.config.systemActiveClass)){
|
||||
Util.deleteCurrentSystemData(mapId);
|
||||
|
||||
// get parent Tab Content and fire clear modules event
|
||||
let tabContentElement = MapUtil.getTabContentElementByMapElement(system);
|
||||
$(tabContentElement).trigger('pf:removeSystemModules');
|
||||
@@ -712,7 +716,7 @@ define([
|
||||
map.deleteConnectionsForElement(system, {fireEvent: false});
|
||||
|
||||
// unregister from "magnetizer"
|
||||
Magnetizer.removeElement(system.data('mapid'), system[0]);
|
||||
Magnetizer.removeElement(mapId, system[0]);
|
||||
|
||||
// destroy tooltip/popover
|
||||
system.toggleSystemTooltip('destroy', {});
|
||||
|
||||
@@ -186,25 +186,50 @@ define([
|
||||
* @param mapData
|
||||
* @param value
|
||||
* @param key
|
||||
* @returns {any}
|
||||
* @returns {{}|boolean}
|
||||
*/
|
||||
let getSystemDataFromMapData = (mapData, value, key = 'id') => {
|
||||
return mapData ? mapData.data.systems.find(system => system[key] === value) || false : false;
|
||||
return (Util.getObjVal(mapData, `data.systems`) || [])
|
||||
.find(systemData => systemData[key] === value) || false;
|
||||
};
|
||||
|
||||
/**
|
||||
* get system data by mapId system data selector
|
||||
* get system data by mapId + system data selector
|
||||
* -> e.g. value = 2 and key = 'id'
|
||||
* -> e.g. value = 30002187 and key = 'systemId' => looks for 'Amarr' CCP systemId
|
||||
* @param mapId
|
||||
* @param value
|
||||
* @param key
|
||||
* @returns {any}
|
||||
* @returns {{}|boolean}
|
||||
*/
|
||||
let getSystemData = (mapId, value, key = 'id') => {
|
||||
return getSystemDataFromMapData(Util.getCurrentMapData(mapId), value, key);
|
||||
};
|
||||
|
||||
/**
|
||||
* get connection data from mapData
|
||||
* @see getConnectionData
|
||||
* @param mapData
|
||||
* @param value
|
||||
* @param key
|
||||
* @returns {{}|boolean}
|
||||
*/
|
||||
let getConnectionDataFromMapData = (mapData, value, key = 'id') => {
|
||||
return (Util.getObjVal(mapData, `data.connections`) || [])
|
||||
.find(connectionData => connectionData[key] === value) || false;
|
||||
};
|
||||
|
||||
/**
|
||||
* get connection data by mapId + connection data selector
|
||||
* @param mapId
|
||||
* @param value
|
||||
* @param key
|
||||
* @returns {{}|boolean}
|
||||
*/
|
||||
let getConnectionData = (mapId, value, key = 'id') => {
|
||||
return getConnectionDataFromMapData(Util.getCurrentMapData(mapId), value, key);
|
||||
};
|
||||
|
||||
/**
|
||||
* get system type information
|
||||
* @param {number} systemTypeId
|
||||
@@ -212,14 +237,7 @@ define([
|
||||
* @returns {string}
|
||||
*/
|
||||
let getSystemTypeInfo = (systemTypeId, option) => {
|
||||
let systemTypeInfo = '';
|
||||
$.each(Init.systemType, function(prop, data){
|
||||
if(systemTypeId === data.id){
|
||||
systemTypeInfo = data[option];
|
||||
return;
|
||||
}
|
||||
});
|
||||
return systemTypeInfo;
|
||||
return (Object.values(Init.systemType).find(data => data.id === systemTypeId) || {})[option] || '';
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -229,11 +247,7 @@ define([
|
||||
* @returns {string}
|
||||
*/
|
||||
let getEffectInfoForSystem = (effect, option) => {
|
||||
let effectInfo = '';
|
||||
if( Init.classes.systemEffects.hasOwnProperty(effect) ){
|
||||
effectInfo = Init.classes.systemEffects[effect][option];
|
||||
}
|
||||
return effectInfo;
|
||||
return Util.getObjVal(Init.classes.systemEffects, `${effect}.${option}`) || '';
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -478,13 +492,16 @@ define([
|
||||
let getConnectionDataFromSignatures = (connection, connectionData) => {
|
||||
let signatureTypeData = {
|
||||
source: {
|
||||
ids: [],
|
||||
names: [],
|
||||
labels: []
|
||||
},
|
||||
target: {
|
||||
ids: [],
|
||||
names: [],
|
||||
labels: []
|
||||
}
|
||||
},
|
||||
hash: false // unique hash key build from all relevant signature for connection
|
||||
};
|
||||
|
||||
if(
|
||||
@@ -501,41 +518,50 @@ define([
|
||||
let sourceId = sourceSystem.data('id');
|
||||
let targetId = targetSystem.data('id');
|
||||
|
||||
// in case connection is currently "dragged" between systems, sourceId and/or targetId is undefined
|
||||
if(!sourceId || !targetId){
|
||||
return signatureTypeData;
|
||||
}
|
||||
|
||||
let hash = [];
|
||||
// ... collect overlay/label data from signatures
|
||||
for(let signatureData of connectionData.signatures){
|
||||
// ... typeId is required to get a valid name
|
||||
if(signatureData.typeId > 0){
|
||||
hash.push(Util.getObjVal(signatureData, 'updated.updated'));
|
||||
|
||||
// whether "source" or "target" system is relevant for current connection and current signature...
|
||||
let tmpSystem = null;
|
||||
let tmpSystemType = null;
|
||||
// whether "source" or "target" system is relevant for current connection and current signature...
|
||||
let tmpSystem = null;
|
||||
let tmpSystemType = null;
|
||||
|
||||
if(signatureData.system.id === sourceId){
|
||||
// relates to "source" endpoint
|
||||
tmpSystemType = 'source';
|
||||
tmpSystem = sourceSystem;
|
||||
}else if(signatureData.system.id === targetId){
|
||||
// relates to "target" endpoint
|
||||
tmpSystemType = 'target';
|
||||
tmpSystem = targetSystem;
|
||||
}
|
||||
if(signatureData.system.id === sourceId){
|
||||
// relates to "source" endpoint
|
||||
tmpSystemType = 'source';
|
||||
tmpSystem = sourceSystem;
|
||||
}else if(signatureData.system.id === targetId){
|
||||
// relates to "target" endpoint
|
||||
tmpSystemType = 'target';
|
||||
tmpSystem = targetSystem;
|
||||
}
|
||||
|
||||
// ... get endpoint label for source || target system
|
||||
if(tmpSystem && tmpSystem){
|
||||
// ... get all available signature type (wormholes) names
|
||||
let availableSigTypeNames = SystemSignatureModule.getSignatureTypeOptionsBySystem(tmpSystem, 5);
|
||||
let flattenSigTypeNames = Util.flattenXEditableSelectArray(availableSigTypeNames);
|
||||
signatureTypeData[tmpSystemType].ids.push(signatureData.id);
|
||||
signatureTypeData[tmpSystemType].names.push(signatureData.name.toUpperCase());
|
||||
|
||||
if(flattenSigTypeNames.hasOwnProperty(signatureData.typeId)){
|
||||
let label = flattenSigTypeNames[signatureData.typeId];
|
||||
// shorten label, just take the ingame name
|
||||
label = label.substr(0, label.indexOf(' '));
|
||||
signatureTypeData[tmpSystemType].names.push(signatureData.name);
|
||||
signatureTypeData[tmpSystemType].labels.push(label);
|
||||
}
|
||||
// ... typeId is required to get a valid labels
|
||||
// ... get endpoint label for source || target system
|
||||
if(signatureData.typeId > 0 && tmpSystem && tmpSystem){
|
||||
// ... get all available signature type (wormholes) names
|
||||
let availableSigTypeNames = SystemSignatureModule.getSignatureTypeOptionsBySystem(tmpSystem, 5);
|
||||
let flattenSigTypeNames = Util.flattenXEditableSelectArray(availableSigTypeNames);
|
||||
|
||||
if(flattenSigTypeNames.hasOwnProperty(signatureData.typeId)){
|
||||
let label = flattenSigTypeNames[signatureData.typeId];
|
||||
// shorten label, just take the ingame name
|
||||
label = label.substr(0, label.indexOf(' '));
|
||||
signatureTypeData[tmpSystemType].labels.push(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ... build unique hash
|
||||
signatureTypeData.hash = hash.join().hashCode();
|
||||
}
|
||||
|
||||
return signatureTypeData;
|
||||
@@ -621,64 +647,66 @@ define([
|
||||
*/
|
||||
let filterMapByScopes = (map, scopes) => {
|
||||
if(map){
|
||||
map.batch(() => {
|
||||
let mapElement = $(map.getContainer());
|
||||
let allSystems = mapElement.getSystems();
|
||||
let allConnections = map.getAllConnections();
|
||||
map.setSuspendDrawing(true);
|
||||
|
||||
if(scopes && scopes.length){
|
||||
// filter connections -------------------------------------------------------------------------------------
|
||||
let visibleSystems = [];
|
||||
let visibleConnections = searchConnectionsByScopeAndType(map, scopes);
|
||||
let mapElement = $(map.getContainer());
|
||||
let allSystems = mapElement.getSystems();
|
||||
let allConnections = map.getAllConnections();
|
||||
|
||||
for(let connection of allConnections){
|
||||
if(visibleConnections.indexOf(connection) >= 0){
|
||||
setConnectionVisible(connection, true);
|
||||
// source/target system should always be visible -> even if filter scope not matches system type
|
||||
if(visibleSystems.indexOf(connection.endpoints[0].element) < 0){
|
||||
visibleSystems.push(connection.endpoints[0].element);
|
||||
}
|
||||
if(visibleSystems.indexOf(connection.endpoints[1].element) < 0){
|
||||
visibleSystems.push(connection.endpoints[1].element);
|
||||
}
|
||||
}else{
|
||||
setConnectionVisible(connection, false);
|
||||
}
|
||||
}
|
||||
if(scopes && scopes.length){
|
||||
// filter connections -------------------------------------------------------------------------------------
|
||||
let visibleSystems = [];
|
||||
let visibleConnections = searchConnectionsByScopeAndType(map, scopes);
|
||||
|
||||
// filter systems -----------------------------------------------------------------------------------------
|
||||
let visibleTypeIds = [];
|
||||
if(scopes.indexOf('wh') >= 0){
|
||||
visibleTypeIds.push(1);
|
||||
}
|
||||
if(scopes.indexOf('abyssal') >= 0){
|
||||
visibleTypeIds.push(4);
|
||||
}
|
||||
|
||||
for(let system of allSystems){
|
||||
if(
|
||||
visibleTypeIds.indexOf($(system).data('typeId')) >= 0 ||
|
||||
visibleSystems.indexOf(system) >= 0
|
||||
){
|
||||
setSystemVisible(system, map, true);
|
||||
}else{
|
||||
setSystemVisible(system, map, false);
|
||||
}
|
||||
}
|
||||
|
||||
MapOverlayUtil.getMapOverlay(mapElement, 'info').updateOverlayIcon('filter', 'show');
|
||||
}else{
|
||||
// clear filter
|
||||
for(let system of allSystems){
|
||||
setSystemVisible(system, map, true);
|
||||
}
|
||||
for(let connection of allConnections){
|
||||
for(let connection of allConnections){
|
||||
if(visibleConnections.indexOf(connection) >= 0){
|
||||
setConnectionVisible(connection, true);
|
||||
// source/target system should always be visible -> even if filter scope not matches system type
|
||||
if(visibleSystems.indexOf(connection.endpoints[0].element) < 0){
|
||||
visibleSystems.push(connection.endpoints[0].element);
|
||||
}
|
||||
if(visibleSystems.indexOf(connection.endpoints[1].element) < 0){
|
||||
visibleSystems.push(connection.endpoints[1].element);
|
||||
}
|
||||
}else{
|
||||
setConnectionVisible(connection, false);
|
||||
}
|
||||
|
||||
MapOverlayUtil.getMapOverlay(mapElement, 'info').updateOverlayIcon('filter', 'hide');
|
||||
}
|
||||
});
|
||||
|
||||
// filter systems -----------------------------------------------------------------------------------------
|
||||
let visibleTypeIds = [];
|
||||
if(scopes.indexOf('wh') >= 0){
|
||||
visibleTypeIds.push(1);
|
||||
}
|
||||
if(scopes.indexOf('abyssal') >= 0){
|
||||
visibleTypeIds.push(4);
|
||||
}
|
||||
|
||||
for(let system of allSystems){
|
||||
if(
|
||||
visibleTypeIds.indexOf($(system).data('typeId')) >= 0 ||
|
||||
visibleSystems.indexOf(system) >= 0
|
||||
){
|
||||
setSystemVisible(system, map, true);
|
||||
}else{
|
||||
setSystemVisible(system, map, false);
|
||||
}
|
||||
}
|
||||
|
||||
MapOverlayUtil.getMapOverlay(mapElement, 'info').updateOverlayIcon('filter', 'show');
|
||||
}else{
|
||||
// clear filter
|
||||
for(let system of allSystems){
|
||||
setSystemVisible(system, map, true);
|
||||
}
|
||||
for(let connection of allConnections){
|
||||
setConnectionVisible(connection, true);
|
||||
}
|
||||
|
||||
MapOverlayUtil.getMapOverlay(mapElement, 'info').updateOverlayIcon('filter', 'hide');
|
||||
}
|
||||
|
||||
map.setSuspendDrawing(false, true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -792,17 +820,19 @@ define([
|
||||
*/
|
||||
let setSystemActive = (map, system) => {
|
||||
// deselect all selected systems on map
|
||||
let mapContainer = $( map.getContainer() );
|
||||
mapContainer.find('.' + config.systemClass).removeClass(config.systemActiveClass);
|
||||
let mapContainer = map.getContainer();
|
||||
[...mapContainer.getElementsByClassName(config.systemClass)]
|
||||
.forEach(systemEl =>
|
||||
systemEl.classList.remove(config.systemActiveClass)
|
||||
);
|
||||
|
||||
// set current system active
|
||||
system.addClass(config.systemActiveClass);
|
||||
|
||||
// collect all required data from map module to update the info element
|
||||
// store them global and assessable for each module
|
||||
// collect all required systemData from map module -> cache
|
||||
let systemData = system.getSystemData();
|
||||
systemData.mapId = parseInt(system.attr('data-mapid')) || 0;
|
||||
Util.setCurrentSystemData(systemData);
|
||||
Util.setCurrentSystemData(systemData.mapId, systemData);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -913,20 +943,22 @@ define([
|
||||
* @param connections
|
||||
*/
|
||||
let setConnectionsActive = (map, connections) => {
|
||||
map.batch(() => {
|
||||
// set all inactive
|
||||
for(let connection of getConnectionsByType(map, 'state_active')){
|
||||
if(!connections.includes(connection)){
|
||||
removeConnectionType(connection, 'state_active');
|
||||
}
|
||||
}
|
||||
map.setSuspendDrawing(true);
|
||||
|
||||
for(let connection of connections){
|
||||
if(!connection.hasType('state_active')){
|
||||
addConnectionType(connection, 'state_active');
|
||||
}
|
||||
// set all inactive
|
||||
for(let connection of getConnectionsByType(map, 'state_active')){
|
||||
if(!connections.includes(connection)){
|
||||
removeConnectionType(connection, 'state_active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for(let connection of connections){
|
||||
if(!connection.hasType('state_active')){
|
||||
addConnectionType(connection, 'state_active');
|
||||
}
|
||||
}
|
||||
|
||||
map.setSuspendDrawing(false, true);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -969,21 +1001,38 @@ define([
|
||||
let toggleConnectionActive = (map, connections) => {
|
||||
let selectedConnections = [];
|
||||
let deselectedConnections = [];
|
||||
map.batch(() => {
|
||||
for(let connection of connections){
|
||||
if(connection.hasType('state_active')){
|
||||
removeConnectionType(connection, 'state_active');
|
||||
deselectedConnections.push(connection);
|
||||
}else{
|
||||
addConnectionType(connection, 'state_active');
|
||||
selectedConnections.push(connection);
|
||||
}
|
||||
|
||||
map.setSuspendDrawing(true);
|
||||
|
||||
for(let connection of connections){
|
||||
if(connection.hasType('state_active')){
|
||||
removeConnectionType(connection, 'state_active');
|
||||
deselectedConnections.push(connection);
|
||||
}else{
|
||||
addConnectionType(connection, 'state_active');
|
||||
selectedConnections.push(connection);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
map.setSuspendDrawing(false, true);
|
||||
|
||||
updateConnectionInfo(map, selectedConnections, deselectedConnections);
|
||||
};
|
||||
|
||||
/**
|
||||
* show global map info panels
|
||||
* @param map
|
||||
*/
|
||||
let showMapInfo = map => {
|
||||
// get parent Tab Content and fire update event
|
||||
let mapContainer = $(map.getContainer());
|
||||
|
||||
getTabContentElementByMapElement(mapContainer).trigger('pf:renderGlobalModules', {
|
||||
mapId: parseInt(mapContainer.data('id')),
|
||||
payload: null
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* show system info panels
|
||||
* @param map
|
||||
@@ -994,10 +1043,11 @@ define([
|
||||
|
||||
// get parent Tab Content and fire update event
|
||||
let mapContainer = $(map.getContainer());
|
||||
let mapId = parseInt(mapContainer.data('id')) || 0;
|
||||
|
||||
getTabContentElementByMapElement(mapContainer).trigger('pf:renderSystemModules', {
|
||||
mapId: parseInt(mapContainer.data('id')),
|
||||
payload: Util.getCurrentSystemData()
|
||||
mapId: mapId,
|
||||
payload: Util.getCurrentSystemData(mapId)
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1238,10 +1288,12 @@ define([
|
||||
let setUniqueConnectionType = (connection, type, types) => {
|
||||
type = types.includes(type) ? [type] : [];
|
||||
|
||||
connection._jsPlumb.instance.batch(() => {
|
||||
removeConnectionTypes(connection, types.diff(type));
|
||||
addConnectionTypes(connection, type);
|
||||
});
|
||||
connection._jsPlumb.instance.setSuspendDrawing(true);
|
||||
|
||||
removeConnectionTypes(connection, types.diff(type));
|
||||
addConnectionTypes(connection, type);
|
||||
|
||||
connection._jsPlumb.instance.setSuspendDrawing(false, true);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -2074,6 +2126,40 @@ define([
|
||||
return findNonOverlappingDimensions(options, maxResults, findChain);
|
||||
};
|
||||
|
||||
/**
|
||||
* calculate the x/y coordinates for a new system - relative to current map scroll offset
|
||||
* @param mapContainer
|
||||
* @param maxResults
|
||||
* @returns {[{x: number, y: number}]}
|
||||
*/
|
||||
let newSystemPositionsByMapOffset = (mapContainer, maxResults = 1) => {
|
||||
let scrollPosition = {
|
||||
x: Math.abs(parseInt(mapContainer.attr('data-scroll-left')) || 0),
|
||||
y: Math.abs(parseInt(mapContainer.attr('data-scroll-top')) || 0)
|
||||
};
|
||||
|
||||
// space new positions from map top (e.g. used for tooltips)
|
||||
scrollPosition.y = Math.max(scrollPosition.y, 30);
|
||||
|
||||
// default position -> current map section top/left
|
||||
let positions = [scrollPosition];
|
||||
|
||||
// check default position for overlapping
|
||||
let dimensions = newSystemPositionByCoordinates(mapContainer, {
|
||||
center: [scrollPosition.x, scrollPosition.y],
|
||||
minX: scrollPosition.x,
|
||||
minY: scrollPosition.y
|
||||
}, maxResults, true);
|
||||
|
||||
if(dimensions.length){
|
||||
positions = dimensions.map(dim => ({
|
||||
x: parseInt(dim.left) || 0,
|
||||
y: parseInt(dim.top) || 0
|
||||
}));
|
||||
}
|
||||
return positions;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mapContainer
|
||||
@@ -2083,30 +2169,8 @@ define([
|
||||
|
||||
if(mapContainer){
|
||||
let mapId = mapContainer.data('id');
|
||||
let scrollPosition = {
|
||||
x: Math.abs(parseInt(mapContainer.attr('data-scroll-left')) || 0),
|
||||
y: Math.abs(parseInt(mapContainer.attr('data-scroll-top')) || 0)
|
||||
};
|
||||
|
||||
// space new positions from map top (e.g. used for tooltips)
|
||||
scrollPosition.y = Math.max(scrollPosition.y, 30);
|
||||
|
||||
// default position -> current map section top/left -------------------------------------------------------
|
||||
positions.defaults = [scrollPosition];
|
||||
|
||||
// check default position for overlapping -----------------------------------------------------------------
|
||||
let dimensions = newSystemPositionByCoordinates(mapContainer, {
|
||||
center: [scrollPosition.x, scrollPosition.y],
|
||||
minX: scrollPosition.x,
|
||||
minY: scrollPosition.y
|
||||
}, 2, true);
|
||||
|
||||
if(dimensions.length){
|
||||
positions.defaults = dimensions.map(dim => ({
|
||||
x: parseInt(dim.left) || 0,
|
||||
y: parseInt(dim.top) || 0
|
||||
}));
|
||||
}
|
||||
positions.defaults = newSystemPositionsByMapOffset(mapContainer, 2);
|
||||
|
||||
// -> calc possible coordinates for new system that should be used based on current user location ---------
|
||||
let currentLocationData = Util.getCurrentLocationData();
|
||||
@@ -2162,6 +2226,8 @@ define([
|
||||
getInfoForSystem: getInfoForSystem,
|
||||
getSystemDataFromMapData: getSystemDataFromMapData,
|
||||
getSystemData: getSystemData,
|
||||
getConnectionDataFromMapData: getConnectionDataFromMapData,
|
||||
getConnectionData: getConnectionData,
|
||||
getSystemTypeInfo: getSystemTypeInfo,
|
||||
getEffectInfoForSystem: getEffectInfoForSystem,
|
||||
markAsChanged: markAsChanged,
|
||||
@@ -2172,6 +2238,7 @@ define([
|
||||
toggleConnectionType: toggleConnectionType,
|
||||
toggleConnectionActive: toggleConnectionActive,
|
||||
setSystemActive: setSystemActive,
|
||||
showMapInfo: showMapInfo,
|
||||
showSystemInfo: showSystemInfo,
|
||||
showConnectionInfo: showConnectionInfo,
|
||||
showFindRouteDialog: showFindRouteDialog,
|
||||
@@ -2180,6 +2247,7 @@ define([
|
||||
getConnectionsByType: getConnectionsByType,
|
||||
getEndpointsDataByConnection: getEndpointsDataByConnection,
|
||||
getDataByConnection: getDataByConnection,
|
||||
getDataByConnections: getDataByConnections,
|
||||
searchConnectionsBySystems: searchConnectionsBySystems,
|
||||
searchConnectionsByScopeAndType: searchConnectionsByScopeAndType,
|
||||
getConnectionInfo: getConnectionInfo,
|
||||
@@ -2191,7 +2259,6 @@ define([
|
||||
setConnectionMassStatusType: setConnectionMassStatusType,
|
||||
setConnectionJumpMassType: setConnectionJumpMassType,
|
||||
getScopeInfoForConnection: getScopeInfoForConnection,
|
||||
getDataByConnections: getDataByConnections,
|
||||
deleteConnections: deleteConnections,
|
||||
getConnectionDataFromSignatures: getConnectionDataFromSignatures,
|
||||
getEndpointOverlaySignatureLocation: getEndpointOverlaySignatureLocation,
|
||||
@@ -2212,6 +2279,7 @@ define([
|
||||
checkRight: checkRight,
|
||||
newSystemPositionBySystem: newSystemPositionBySystem,
|
||||
newSystemPositionByCoordinates: newSystemPositionByCoordinates,
|
||||
newSystemPositionsByMapOffset: newSystemPositionsByMapOffset,
|
||||
newSystemPositionsByMap: newSystemPositionsByMap,
|
||||
getMapDeeplinkUrl: getMapDeeplinkUrl
|
||||
};
|
||||
|
||||
@@ -308,15 +308,14 @@ define([
|
||||
|
||||
|
||||
/**
|
||||
* clear both main update timeouts
|
||||
* clear both main update timeouts, and reset values
|
||||
* -> stop program from working -> shutdown
|
||||
*/
|
||||
let clearUpdateTimeouts = () => {
|
||||
for(let intervalKey in updateTimeouts){
|
||||
if(updateTimeouts.hasOwnProperty(intervalKey)){
|
||||
clearTimeout(updateTimeouts[intervalKey]);
|
||||
}
|
||||
}
|
||||
Object.keys(updateTimeouts).forEach(intervalKey => {
|
||||
clearTimeout(updateTimeouts[intervalKey]);
|
||||
updateTimeouts[intervalKey] = 0;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -417,20 +416,20 @@ define([
|
||||
|
||||
// IMPORTANT: Get user data for ONE map that is currently visible
|
||||
// On later releases this can be easy changed to "full update" all maps for a user
|
||||
let mapIds = [];
|
||||
let mapId;
|
||||
let newSystemPositions = null;
|
||||
let activeMap = Util.getMapModule().getActiveMap();
|
||||
|
||||
if(activeMap){
|
||||
mapIds = [activeMap.data('id')];
|
||||
mapId = activeMap.data('id');
|
||||
newSystemPositions = MapUtil.newSystemPositionsByMap(activeMap);
|
||||
}
|
||||
|
||||
let updatedUserData = {
|
||||
mapIds: mapIds,
|
||||
mapIds: mapId ? [mapId] : [],
|
||||
getMapUserData: Util.getSyncType() === 'webSocket' ? 0 : 1,
|
||||
mapTracking: locationToggle.is(':checked') ? 1 : 0, // location tracking
|
||||
systemData: Util.getCurrentSystemData()
|
||||
systemData: Util.getCurrentSystemData(mapId)
|
||||
};
|
||||
|
||||
if(newSystemPositions){
|
||||
|
||||
@@ -13,6 +13,7 @@ define([
|
||||
'module/system_route',
|
||||
'module/system_intel',
|
||||
'module/system_killboard',
|
||||
'module/global_thera',
|
||||
'module/connection_info',
|
||||
'app/counter'
|
||||
], (
|
||||
@@ -30,6 +31,7 @@ define([
|
||||
SystemRouteModule,
|
||||
SystemIntelModule,
|
||||
SystemKillboardModule,
|
||||
TheraModule,
|
||||
ConnectionInfoModule
|
||||
) => {
|
||||
'use strict';
|
||||
@@ -56,6 +58,7 @@ define([
|
||||
|
||||
// editable 'settings' popover
|
||||
editableSettingsClass: 'pf-editable-settings',
|
||||
editableHeadlineClass: 'pf-editable-headline',
|
||||
editableToggleClass: 'pf-editable-toggle',
|
||||
editableToggleItemClass: 'pf-editable-toggle-item',
|
||||
|
||||
@@ -65,13 +68,6 @@ define([
|
||||
|
||||
let mapTabChangeBlocked = false; // flag for preventing map tab switch
|
||||
|
||||
/**
|
||||
* get all maps for a maps module
|
||||
* @param mapModule
|
||||
* @returns {jQuery}
|
||||
*/
|
||||
let getMaps = mapModule => $(mapModule).find('.' + Util.config.mapClass);
|
||||
|
||||
/**
|
||||
* get the current active mapElement
|
||||
* @returns {bool|jQuery}
|
||||
@@ -90,6 +86,12 @@ define([
|
||||
* @param tabContentWrapperEl
|
||||
*/
|
||||
let setMapTabContentWrapperObserver = tabContentWrapperEl => {
|
||||
$(tabContentWrapperEl).on('pf:renderGlobalModules', `.${Util.config.mapTabContentClass}`, function(e, data){
|
||||
getModules()
|
||||
.then(modules => filterModules(modules, 'global'))
|
||||
.then(modules => renderModules(modules, e.target, data));
|
||||
});
|
||||
|
||||
$(tabContentWrapperEl).on('pf:renderSystemModules', `.${Util.config.mapTabContentClass}`, function(e, data){
|
||||
getModules()
|
||||
.then(modules => filterModules(modules, 'system'))
|
||||
@@ -114,6 +116,12 @@ define([
|
||||
.then(modules => removeModules(modules, e.target));
|
||||
});
|
||||
|
||||
$(tabContentWrapperEl).on('pf:updateGlobalModules', `.${Util.config.mapTabContentClass}`, (e, data) => {
|
||||
getModules()
|
||||
.then(modules => filterModules(modules, 'global'))
|
||||
.then(modules => updateModules(modules, e.target, data));
|
||||
});
|
||||
|
||||
$(tabContentWrapperEl).on('pf:updateSystemModules', `.${Util.config.mapTabContentClass}`, (e, data) => {
|
||||
getModules()
|
||||
.then(modules => filterModules(modules, true, 'fullDataUpdate'))
|
||||
@@ -141,6 +149,7 @@ define([
|
||||
SystemRouteModule,
|
||||
SystemIntelModule,
|
||||
SystemKillboardModule,
|
||||
TheraModule,
|
||||
ConnectionInfoModule
|
||||
];
|
||||
|
||||
@@ -361,7 +370,7 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
removeModule(Module, gridArea, true).then(abc => render(Module, gridArea, defaultPosition, mapId, payload));
|
||||
removeModule(Module, gridArea, false).then(abc => render(Module, gridArea, defaultPosition, mapId, payload));
|
||||
};
|
||||
|
||||
return new Promise(renderModuleExecutor);
|
||||
@@ -533,7 +542,7 @@ define([
|
||||
let updateSystemModulesData = (mapModule, systemData) => {
|
||||
if(systemData){
|
||||
// check if current open system is still the requested info system
|
||||
let currentSystemData = Util.getCurrentSystemData();
|
||||
let currentSystemData = Util.getCurrentSystemData(systemData.mapId);
|
||||
|
||||
if(
|
||||
currentSystemData &&
|
||||
@@ -556,6 +565,7 @@ define([
|
||||
let setTabContentObserver = (tabContent, mapId) => {
|
||||
|
||||
let defaultSortableOptions = {
|
||||
invertSwap: true,
|
||||
animation: Init.animationSpeed.mapModule,
|
||||
handle: '.' + config.sortableHandleClass,
|
||||
draggable: '.' + config.moduleClass,
|
||||
@@ -926,10 +936,11 @@ define([
|
||||
let mapId = parseInt(linkEl.dataset.mapId) || 0;
|
||||
let defaultSystemId = parseInt(linkEl.dataset.defaultSystemId) || 0;
|
||||
let tabMapData = Util.getCurrentMapData(mapId);
|
||||
let tabContentEl = document.getElementById(config.mapTabIdPrefix + mapId);
|
||||
|
||||
if(tabMapData !== false){
|
||||
// tabContentEl does not exist in case of error where all map elements got removed
|
||||
if(tabMapData !== false && tabContentEl){
|
||||
// load map
|
||||
let tabContentEl = document.getElementById(config.mapTabIdPrefix + mapId);
|
||||
let areaMap = tabContentEl.querySelector(`.${Util.getMapTabContentAreaClass('map')}`);
|
||||
Map.loadMap(areaMap, tabMapData, {showAnimation: true}).then(payload => {
|
||||
// "wake up" scrollbar for map and get previous state back
|
||||
@@ -938,6 +949,11 @@ define([
|
||||
let areaMap = mapElement.closest('.mCustomScrollbar');
|
||||
$(areaMap).mCustomScrollbar('update');
|
||||
|
||||
// show "global" map panels of map was initial loaded
|
||||
if(payload.isFirstLoad){
|
||||
MapUtil.showMapInfo(mapConfig.map);
|
||||
}
|
||||
|
||||
// if there is an already an "active" system -> setCurrentSystemData for that again
|
||||
let activeSystemEl = mapElement.querySelector(`.${MapUtil.config.systemActiveClass}`);
|
||||
if(activeSystemEl){
|
||||
@@ -973,9 +989,6 @@ define([
|
||||
|
||||
// skip "add button"
|
||||
if(newMapId > 0){
|
||||
// delete currentSystemData -> will be set for new map (if there is is an active system)
|
||||
delete Init.currentSystemData;
|
||||
|
||||
let currentTabContentEl = document.getElementById(config.mapTabIdPrefix + oldMapId);
|
||||
|
||||
// disable scrollbar for map that will be hidden. "freeze" current state
|
||||
@@ -991,90 +1004,81 @@ define([
|
||||
* @param options
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let updateTabData = (tabLinkEl, options) => {
|
||||
let updateTabData = (tabLinkEl, options) => new Promise(resolve => {
|
||||
// set "main" data
|
||||
tabLinkEl.dataset.mapId = options.id;
|
||||
|
||||
/**
|
||||
* update tab promise
|
||||
* @param resolve
|
||||
*/
|
||||
let updateTabExecutor = resolve => {
|
||||
// set "main" data
|
||||
tabLinkEl.dataset.mapId = options.id;
|
||||
// add updated timestamp (not available for "add" tab
|
||||
if(Util.getObjVal(options, 'updated.updated')){
|
||||
tabLinkEl.dataset.updated = options.updated.updated;
|
||||
}
|
||||
|
||||
// add updated timestamp (not available for "add" tab
|
||||
if(Util.getObjVal(options, 'updated.updated')){
|
||||
tabLinkEl.dataset.updated = options.updated.updated;
|
||||
// change "tab" link
|
||||
tabLinkEl.setAttribute('href', `#${config.mapTabIdPrefix}${options.id}`);
|
||||
|
||||
// change "map" icon
|
||||
let mapIconEl = tabLinkEl.querySelector(`.${config.mapTabIconClass}`);
|
||||
mapIconEl.classList.remove(...mapIconEl.classList);
|
||||
mapIconEl.classList.add(config.mapTabIconClass, 'fas', 'fa-fw', options.icon);
|
||||
|
||||
// change "shared" icon
|
||||
let mapSharedIconEl = tabLinkEl.querySelector(`.${config.mapTabSharedIconClass}`);
|
||||
mapSharedIconEl.style.display = 'none';
|
||||
|
||||
// check if the map is a "shared" map
|
||||
if(options.access){
|
||||
if(
|
||||
options.access.character.length > 1 ||
|
||||
options.access.corporation.length > 1 ||
|
||||
options.access.alliance.length > 1
|
||||
){
|
||||
mapSharedIconEl.style.display = 'initial';
|
||||
}
|
||||
}
|
||||
|
||||
// change "tab" link
|
||||
tabLinkEl.setAttribute('href', `#${config.mapTabIdPrefix}${options.id}`);
|
||||
// change map name label
|
||||
let textEl = tabLinkEl.querySelector(`.${config.mapTabLinkTextClass}`);
|
||||
textEl.textContent = options.name;
|
||||
|
||||
// change "map" icon
|
||||
let mapIconEl = tabLinkEl.querySelector(`.${config.mapTabIconClass}`);
|
||||
mapIconEl.classList.remove(...mapIconEl.classList);
|
||||
mapIconEl.classList.add(config.mapTabIconClass, 'fas', 'fa-fw', options.icon);
|
||||
// change tabClass
|
||||
let listEl = tabLinkEl.parentNode;
|
||||
|
||||
// change "shared" icon
|
||||
let mapSharedIconEl = tabLinkEl.querySelector(`.${config.mapTabSharedIconClass}`);
|
||||
mapSharedIconEl.style.display = 'none';
|
||||
// new tab classes
|
||||
let tabClasses = [config.mapTabClass, options.type.classTab];
|
||||
|
||||
// check if the map is a "shared" map
|
||||
if(options.access){
|
||||
if(
|
||||
options.access.character.length > 1 ||
|
||||
options.access.corporation.length > 1 ||
|
||||
options.access.alliance.length > 1
|
||||
){
|
||||
mapSharedIconEl.style.display = 'initial';
|
||||
}
|
||||
}
|
||||
if(options.draggable === false){
|
||||
tabClasses.push('noSort');
|
||||
}
|
||||
|
||||
// change map name label
|
||||
let textEl = tabLinkEl.querySelector(`.${config.mapTabLinkTextClass}`);
|
||||
textEl.textContent = options.name;
|
||||
// check if tab was "active" before
|
||||
if(listEl.classList.contains('active')){
|
||||
tabClasses.push('active');
|
||||
}
|
||||
listEl.classList.remove(...listEl.classList);
|
||||
listEl.classList.add(...tabClasses);
|
||||
|
||||
// change tabClass
|
||||
let listEl = tabLinkEl.parentNode;
|
||||
// set title for tooltip
|
||||
if(options.type.name !== undefined){
|
||||
textEl.setAttribute('title', `${options.type.name} map`);
|
||||
}
|
||||
|
||||
// new tab classes
|
||||
let tabClasses = [config.mapTabClass, options.type.classTab];
|
||||
|
||||
if(options.draggable === false){
|
||||
tabClasses.push('noSort');
|
||||
}
|
||||
|
||||
// check if tab was "active" before
|
||||
if(listEl.classList.contains('active')){
|
||||
tabClasses.push('active');
|
||||
}
|
||||
listEl.classList.remove(...listEl.classList);
|
||||
listEl.classList.add(...tabClasses);
|
||||
|
||||
// set title for tooltip
|
||||
if(options.type.name !== undefined){
|
||||
textEl.setAttribute('title', `${options.type.name} map`);
|
||||
}
|
||||
|
||||
let mapTooltipOptions = {
|
||||
placement: 'bottom',
|
||||
container: 'body',
|
||||
trigger: 'hover',
|
||||
delay: 150
|
||||
};
|
||||
|
||||
$(listEl.querySelector('[title]')).tooltip(mapTooltipOptions).tooltip('fixTitle');
|
||||
|
||||
resolve({
|
||||
action: 'update',
|
||||
data: {
|
||||
mapId: options.id,
|
||||
mapName: options.name
|
||||
}
|
||||
});
|
||||
let mapTooltipOptions = {
|
||||
placement: 'bottom',
|
||||
container: 'body',
|
||||
trigger: 'hover',
|
||||
delay: 150
|
||||
};
|
||||
|
||||
return new Promise(updateTabExecutor);
|
||||
};
|
||||
$(listEl.querySelector('[title]')).tooltip(mapTooltipOptions).tooltip('fixTitle');
|
||||
|
||||
resolve({
|
||||
action: 'update',
|
||||
data: {
|
||||
mapId: options.id,
|
||||
mapName: options.name
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* add a new tab to tab-map-module end return promise
|
||||
@@ -1545,10 +1549,14 @@ define([
|
||||
setMapTabLayout(tabEl, layoutCurrent);
|
||||
|
||||
// prepare select options for modules
|
||||
let sourceOptions = modules.sort((a, b) => a.isPlugin - b.isPlugin).map(Module => ({
|
||||
let modulePrioCounts = Array(BaseModule.scopeOrder.length).fill(0);
|
||||
let sourceOptions = modules.sort((a, b) => a.getOrderPrio() - b.getOrderPrio()).map(Module => ({
|
||||
value: Module.name,
|
||||
text: `(${Module.scope.substring(0, 3)}) ${Module.label}`,
|
||||
text: Module.label,
|
||||
metaData: {
|
||||
scope: Module.scope,
|
||||
orderPrio: Module.getOrderPrio(),
|
||||
prioCount: ++modulePrioCounts[Module.getOrderPrio()],
|
||||
isPlugin: Module.isPlugin
|
||||
}
|
||||
}));
|
||||
@@ -1628,6 +1636,19 @@ define([
|
||||
}
|
||||
}
|
||||
}, {passive: false});
|
||||
|
||||
// add "headlines" to Modules checklist -------------------------------------------------------
|
||||
anchorEl.childNodes.forEach((gridItem, i) => {
|
||||
if(sourceOptions[i].metaData.prioCount === 1){
|
||||
gridItem.classList.add(config.editableHeadlineClass);
|
||||
gridItem.setAttribute('data-count',
|
||||
modulePrioCounts[sourceOptions[i].metaData.orderPrio]
|
||||
);
|
||||
gridItem.setAttribute('data-headline',
|
||||
BaseModule.scopeOrder[sourceOptions[i].metaData.orderPrio]
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
settingsLinkEl.on('save', {sourceOptions: sourceOptions}, (e, params) => {
|
||||
@@ -1644,15 +1665,23 @@ define([
|
||||
let showModules = filterModules(modules, params.newValue.diff(oldValue), 'name');
|
||||
|
||||
removeModules(hideModules, tabContentEl).then(payload => {
|
||||
let showGlobalModules = showModules.filter(Module => Module.scope === 'global');
|
||||
let showSystemModules = showModules.filter(Module => Module.scope === 'system');
|
||||
let showConnectionModules = showModules.filter(Module => Module.scope === 'connection');
|
||||
if(showGlobalModules.length){
|
||||
renderModules(showGlobalModules, tabContentEl, {
|
||||
mapId: activeMapId,
|
||||
payload: null
|
||||
});
|
||||
}
|
||||
|
||||
if(
|
||||
showSystemModules.length &&
|
||||
Util.getCurrentSystemData()
|
||||
Util.getCurrentSystemData(activeMapId)
|
||||
){
|
||||
renderModules(showSystemModules, tabContentEl, {
|
||||
mapId: activeMapId,
|
||||
payload: Util.getCurrentSystemData()
|
||||
payload: Util.getCurrentSystemData(activeMapId)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1706,28 +1735,24 @@ define([
|
||||
/**
|
||||
* collect all data (systems/connections) for export/save from each active map in the map module
|
||||
* if no change detected -> do not attach map data to return array
|
||||
* @param mapModule
|
||||
* @param {HTMLElement} mapModule
|
||||
* @param filter
|
||||
* @returns {Array}
|
||||
* @returns {[]}
|
||||
*/
|
||||
let getMapModuleDataForUpdate = (mapModule, filter = ['hasId', 'hasChanged']) => {
|
||||
// get all active map elements for module
|
||||
let mapElements = getMaps(mapModule);
|
||||
|
||||
let data = [];
|
||||
for(let i = 0; i < mapElements.length; i++){
|
||||
[...mapModule.getElementsByClassName(Util.config.mapClass)].forEach(mapElement => {
|
||||
// get all changed (system / connection) data from this map
|
||||
let mapData = Map.getMapDataForSync($(mapElements[i]), filter);
|
||||
if(mapData !== false){
|
||||
if(
|
||||
mapData.data.systems.length > 0 ||
|
||||
mapData.data.connections.length > 0
|
||||
){
|
||||
data.push(mapData);
|
||||
}
|
||||
let mapData = Map.getMapDataForSync(mapElement, filter);
|
||||
if(
|
||||
mapData && (
|
||||
(Util.getObjVal(mapData, 'data.systems') || []).length ||
|
||||
(Util.getObjVal(mapData, 'data.connections') || []).length
|
||||
)
|
||||
){
|
||||
data.push(mapData);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
return data;
|
||||
};
|
||||
|
||||
|
||||
@@ -1293,47 +1293,35 @@ define([
|
||||
let mapUserUpdateKey = 'UPDATE_SERVER_USER_DATA';
|
||||
|
||||
// Set the name of the hidden property and the change event for visibility
|
||||
let hidden, visibilityChange;
|
||||
if(typeof document.hidden !== 'undefined'){ // Opera 12.10 and Firefox 18 and later support
|
||||
hidden = 'hidden';
|
||||
let visibilityState, visibilityChange;
|
||||
if(typeof document.visibilityState !== 'undefined'){ // Opera 12.10 and Firefox 18 and later support
|
||||
visibilityState = 'visibilityState';
|
||||
visibilityChange = 'visibilitychange';
|
||||
}else if(typeof document.mozHidden !== 'undefined'){
|
||||
hidden = 'mozHidden';
|
||||
visibilityChange = 'mozvisibilitychange';
|
||||
}else if(typeof document.msHidden !== 'undefined'){
|
||||
hidden = 'msHidden';
|
||||
visibilityChange = 'msvisibilitychange';
|
||||
}else if(typeof document.webkitHidden !== 'undefined'){
|
||||
hidden = 'webkitHidden';
|
||||
visibilityChange = 'webkitvisibilitychange';
|
||||
}
|
||||
|
||||
// function is called if the tab becomes active/inactive
|
||||
let handleVisibilityChange = () => {
|
||||
if(document[hidden]){
|
||||
// tab is invisible
|
||||
// globally store current visibility status
|
||||
window.isVisible = false;
|
||||
|
||||
Util.getCurrentTriggerDelay( mapUpdateKey, increaseTimer );
|
||||
Util.getCurrentTriggerDelay( mapUserUpdateKey, increaseTimer );
|
||||
}else{
|
||||
if(document[visibilityState] === 'visible'){
|
||||
// tab is visible
|
||||
// globally store current visibility status
|
||||
window.isVisible = true;
|
||||
|
||||
Util.getCurrentTriggerDelay( mapUpdateKey, -increaseTimer );
|
||||
Util.getCurrentTriggerDelay( mapUserUpdateKey, -increaseTimer );
|
||||
Util.getCurrentTriggerDelay(mapUpdateKey, -increaseTimer);
|
||||
Util.getCurrentTriggerDelay(mapUserUpdateKey, -increaseTimer);
|
||||
|
||||
// stop blinking tab from previous notifications
|
||||
Util.stopTabBlink();
|
||||
}else{
|
||||
// tab is invisible
|
||||
// globally store current visibility status
|
||||
window.isVisible = false;
|
||||
|
||||
Util.getCurrentTriggerDelay(mapUpdateKey, increaseTimer);
|
||||
Util.getCurrentTriggerDelay(mapUserUpdateKey, increaseTimer);
|
||||
}
|
||||
};
|
||||
|
||||
if(
|
||||
typeof document.addEventListener !== 'undefined' &&
|
||||
typeof document[hidden] !== 'undefined'
|
||||
){
|
||||
if(visibilityState && visibilityChange){
|
||||
// the current browser supports this feature
|
||||
// Handle page visibility change
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
define([
|
||||
'PNotify',
|
||||
'PNotifyDesktop',
|
||||
'PNotifyButtons',
|
||||
'PNotifyCallbacks',
|
||||
'PNotifyDesktop',
|
||||
'NonBlock'
|
||||
], (PNotify) => {
|
||||
'use strict';
|
||||
@@ -30,6 +31,9 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* default PNotify config
|
||||
*/
|
||||
let initDefaultPNotifyConfig = () => {
|
||||
PNotify.defaults.styling = 'bootstrap3';
|
||||
PNotify.defaults.icons = 'fontawesome5';
|
||||
@@ -54,7 +58,6 @@ define([
|
||||
config.modules = {
|
||||
Desktop: Object.assign({}, {desktop: true}, options.desktop)
|
||||
};
|
||||
startTabBlink(config.title); // make browser tab blink
|
||||
}
|
||||
|
||||
switch(config.type){
|
||||
@@ -99,60 +102,7 @@ define([
|
||||
|
||||
initDefaultPNotifyConfig();
|
||||
|
||||
// browser tab blink ==============================================================================================
|
||||
// initial page title (cached)
|
||||
let initialPageTitle = document.title;
|
||||
|
||||
// global blink timeout cache
|
||||
let blinkTimer;
|
||||
|
||||
/**
|
||||
* change document.title and make the browsers tab blink
|
||||
* @param blinkTitle
|
||||
*/
|
||||
let startTabBlink = blinkTitle => {
|
||||
let initBlink = (function(){
|
||||
// count blinks if tab is currently active
|
||||
let activeTabBlinkCount = 0;
|
||||
|
||||
let blink = (blinkTitle) => {
|
||||
// number of "blinks" should be limited if tab is currently active
|
||||
if(window.isVisible){
|
||||
activeTabBlinkCount++;
|
||||
}
|
||||
|
||||
// toggle page title
|
||||
document.title = (document.title === blinkTitle) ? initialPageTitle : blinkTitle;
|
||||
|
||||
if(activeTabBlinkCount > 10){
|
||||
stopTabBlink();
|
||||
}
|
||||
};
|
||||
|
||||
return () => {
|
||||
if(!blinkTimer){
|
||||
blinkTimer = setInterval(blink, 1000, blinkTitle);
|
||||
}
|
||||
};
|
||||
}(blinkTitle));
|
||||
|
||||
initBlink();
|
||||
};
|
||||
|
||||
/**
|
||||
* stop blinking document.title
|
||||
*/
|
||||
let stopTabBlink = () => {
|
||||
if(blinkTimer){
|
||||
clearInterval(blinkTimer);
|
||||
document.title = initialPageTitle;
|
||||
blinkTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
showNotify: showNotify,
|
||||
startTabBlink: startTabBlink,
|
||||
stopTabBlink: stopTabBlink
|
||||
showNotify: showNotify
|
||||
};
|
||||
});
|
||||
@@ -212,7 +212,7 @@ define([
|
||||
let systemsElement = $(this);
|
||||
|
||||
let systemTable = $('<table>', {
|
||||
id: Util.getTableId(config.tableId, 'systems', mapData.config.id, ''),
|
||||
id: Util.getTableId(config.tableId, 'systems', mapData.config.id),
|
||||
class: ['compact', 'stripe', 'order-column', 'row-border'].join(' ')
|
||||
});
|
||||
systemsElement.append(systemTable);
|
||||
@@ -469,7 +469,7 @@ define([
|
||||
|
||||
let confirmationSettings = {
|
||||
placement: 'left',
|
||||
title: 'Delete system',
|
||||
title: '---',
|
||||
template: Util.getConfirmationTemplate(null, {
|
||||
size: 'small',
|
||||
noTitle: true
|
||||
@@ -535,7 +535,7 @@ define([
|
||||
let connectionsElement = $(this);
|
||||
|
||||
let connectionTable = $('<table>', {
|
||||
id: Util.getTableId(config.tableId, 'connections', mapData.config.id, ''),
|
||||
id: Util.getTableId(config.tableId, 'connections', mapData.config.id),
|
||||
class: ['compact', 'stripe', 'order-column', 'row-border'].join(' ')
|
||||
});
|
||||
connectionsElement.append(connectionTable);
|
||||
@@ -678,7 +678,7 @@ define([
|
||||
|
||||
let confirmationSettings = {
|
||||
placement: 'left',
|
||||
title: 'Delete connection',
|
||||
title: '---',
|
||||
template: Util.getConfirmationTemplate(null, {
|
||||
size: 'small',
|
||||
noTitle: true
|
||||
@@ -686,9 +686,7 @@ define([
|
||||
onConfirm: function(e, target){
|
||||
let deleteRowElement = $(target).parents('tr');
|
||||
|
||||
// deleteSignatures(row);
|
||||
let connection = $().getConnectionById(mapData.config.id, rowData.id);
|
||||
|
||||
MapUtil.deleteConnections([connection], () => {
|
||||
// callback function after ajax "delete" success
|
||||
// remove table row
|
||||
|
||||
@@ -90,8 +90,7 @@ define([
|
||||
let name = parts[0];
|
||||
let sizeLabel;
|
||||
if(Util.getObjVal(customOptions, 'showWhSizeLabel')){
|
||||
let wormholeSizeData = Util.getObjVal(Init, 'wormholes.' + name + '.size');
|
||||
sizeLabel = Util.getObjVal(wormholeSizeData, 'label') || '';
|
||||
sizeLabel = Util.getObjVal(Init, `wormholes.${name}.size.label`) || '';
|
||||
}
|
||||
|
||||
let securityClass = Util.getSecurityClassForSystem(getSystemSecurityFromLabel(parts[1]));
|
||||
@@ -102,19 +101,17 @@ define([
|
||||
|
||||
let classes = [securityClass, Util.config.popoverTriggerClass, Util.config.helpDefaultClass];
|
||||
|
||||
markup += '<span>' + name + '</span>';
|
||||
markup += `<span>${name}</span>`;
|
||||
if(sizeLabel !== undefined){
|
||||
markup += '<span><kbd>' + sizeLabel + '</kbd></span>';
|
||||
}else{
|
||||
markup += ' ';
|
||||
markup += `<span><kbd>${sizeLabel}</kbd></span>`;
|
||||
}
|
||||
markup += '<i class="fas fa-long-arrow-alt-right txt-color txt-color-grayLight"></i>';
|
||||
markup += '<span class="' + classes.join(' ') + '" data-name="' + name + '"> ' + label + '</span>';
|
||||
markup += `<span class="${classes.join(' ')}" data-name="${name}"> ${label}</span>`;
|
||||
if(suffix.length){
|
||||
markup += ' <span>' + suffix + '</span>';
|
||||
markup += ` <span>${suffix}</span>`;
|
||||
}
|
||||
}else{
|
||||
markup += '<span>' + state.text + '</span>';
|
||||
markup += `<span>${state.text}</span>`;
|
||||
}
|
||||
|
||||
return $(markup);
|
||||
@@ -203,10 +200,10 @@ define([
|
||||
}
|
||||
|
||||
let securityClass = Util.getSecurityClassForSystem(parts[1]);
|
||||
markup += '<span class="' + styleClass.join(' ') + '">' + parts[0] + '</span> ';
|
||||
markup += '<span class="' + securityClass + '">' + parts[1] + '</span>';
|
||||
markup += `<span class="${styleClass.join(' ')}">${parts[0]}</span>`;
|
||||
markup += `<span class="${securityClass}"> ${parts[1]}</span>`;
|
||||
}else{
|
||||
markup += '<span>' + state.text + '</span>';
|
||||
markup += `<span>${state.text}</span>`;
|
||||
}
|
||||
|
||||
return $(markup);
|
||||
|
||||
@@ -2,9 +2,11 @@ define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/map/util',
|
||||
'app/lib/cache',
|
||||
'app/promises/promise.deferred',
|
||||
'app/promises/promise.queue'
|
||||
], ($, Init, Util, DeferredPromise, PromiseQueue) => {
|
||||
], ($, Init, Util, MapUtil, Cache, DeferredPromise, PromiseQueue) => {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
@@ -127,6 +129,34 @@ define([
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* label element
|
||||
* @param text
|
||||
* @param cls
|
||||
* @returns {HTMLSpanElement}
|
||||
*/
|
||||
newLabelElement(text, cls = []){
|
||||
let labelEl = document.createElement('span');
|
||||
labelEl.classList.add('label', 'center-block', ...cls);
|
||||
labelEl.textContent = text || '';
|
||||
return labelEl;
|
||||
}
|
||||
|
||||
/**
|
||||
* control button element
|
||||
* @param text
|
||||
* @param cls
|
||||
* @param iconCls
|
||||
* @returns {HTMLDivElement}
|
||||
*/
|
||||
newControlElement(text, cls = [], iconCls = ['fa-sync']){
|
||||
let controlEl = document.createElement('div');
|
||||
controlEl.classList.add(...[BaseModule.Util.config.dynamicAreaClass, this._config.controlAreaClass, ...cls]);
|
||||
controlEl.insertAdjacentHTML('beforeend', ` ${text}`);
|
||||
controlEl.prepend(this.newIconElement(iconCls));
|
||||
return controlEl;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request handler for internal (Pathfinder) ajax calls
|
||||
* @param args
|
||||
@@ -245,6 +275,188 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get a unique cache key name for "source"/"target"-name
|
||||
* @param sourceName
|
||||
* @param targetName
|
||||
* @returns {string|boolean}
|
||||
*/
|
||||
static getConnectionDataCacheKey(sourceName, targetName){
|
||||
let key = false;
|
||||
if(sourceName && targetName){
|
||||
// names can be "undefined" in case system is currently in drag/drop state
|
||||
// sort() is important -> ignore direction
|
||||
key = `con_` + `${ [String(sourceName).toLowerCase(), String(targetName).toLowerCase()].sort() }`.hashCode();
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a connectionsData object that holds all connections for given mapIds (used as cache for route search)
|
||||
* @param mapIds
|
||||
* @returns {{}}
|
||||
*/
|
||||
static getConnectionsDataFromMaps(mapIds){
|
||||
let data = {};
|
||||
for(let mapId of mapIds){
|
||||
let map = MapUtil.getMapInstance(mapId);
|
||||
if(map){
|
||||
let cacheKey = `map_${mapId}`;
|
||||
let cache = BaseModule.getCache('mapConnections');
|
||||
let mapConnectionsData = cache.get(cacheKey);
|
||||
|
||||
if(!mapConnectionsData){
|
||||
mapConnectionsData = this.getConnectionsDataFromConnections(mapId, map.getAllConnections());
|
||||
// update cache
|
||||
cache.set(cacheKey, mapConnectionsData);
|
||||
}
|
||||
Object.assign(data, mapConnectionsData);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a connectionsData object for all connections
|
||||
* @param mapId
|
||||
* @param connections
|
||||
* @returns {{}}
|
||||
*/
|
||||
static getConnectionsDataFromConnections(mapId = 0, connections = []){
|
||||
let data = {};
|
||||
if(connections.length){
|
||||
let connectionsData = MapUtil.getDataByConnections(connections);
|
||||
for(let connectionData of connectionsData){
|
||||
let connectionDataCacheKey = BaseModule.getConnectionDataCacheKey(connectionData.sourceName, connectionData.targetName);
|
||||
|
||||
// skip double connections between same systems
|
||||
if(connectionDataCacheKey && !Object.keys(data).includes(connectionDataCacheKey)){
|
||||
data[connectionDataCacheKey] = {
|
||||
map: {
|
||||
id: mapId
|
||||
},
|
||||
connection: {
|
||||
id: connectionData.id,
|
||||
type: connectionData.type,
|
||||
scope: connectionData.scope,
|
||||
updated: connectionData.updated
|
||||
},
|
||||
source: {
|
||||
id: connectionData.source,
|
||||
name: connectionData.sourceName,
|
||||
alias: connectionData.sourceAlias
|
||||
},
|
||||
target: {
|
||||
id: connectionData.target,
|
||||
name: connectionData.targetName,
|
||||
alias: connectionData.targetAlias
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* search for a specific connection by "source"/"target"-name inside connectionsData cache
|
||||
* @param connectionsData
|
||||
* @param sourceName
|
||||
* @param targetName
|
||||
* @returns {*}
|
||||
*/
|
||||
static findConnectionsData(connectionsData, sourceName, targetName){
|
||||
return this.Util.getObjVal(connectionsData, this.getConnectionDataCacheKey(sourceName, targetName));
|
||||
}
|
||||
|
||||
/**
|
||||
* get fake connection data (default connection type in case connection was not found on a map)
|
||||
* @param sourceSystemData
|
||||
* @param targetSystemData
|
||||
* @param scope
|
||||
* @param types
|
||||
* @returns {{connection: {scope: string, id: number, type: [*]}, source: {name: number, alias: number, id: number}, target: {name: number, alias: number, id: number}}}
|
||||
*/
|
||||
static getFakeConnectionData(sourceSystemData, targetSystemData, scope = 'stargate', types = []){
|
||||
return {
|
||||
connection: {
|
||||
id: 0,
|
||||
scope: scope,
|
||||
type: types.length ? types : [MapUtil.getDefaultConnectionTypeByScope(scope)],
|
||||
updated: 0
|
||||
},
|
||||
source: {
|
||||
id: 0,
|
||||
name: sourceSystemData.system,
|
||||
alias: sourceSystemData.system
|
||||
},
|
||||
target: {
|
||||
id: 0,
|
||||
name: targetSystemData.system,
|
||||
alias: targetSystemData.system
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* get fake connection Element
|
||||
* @param connectionData
|
||||
* @returns {string}
|
||||
*/
|
||||
static getFakeConnectionElement(connectionData){
|
||||
let mapId = this.Util.getObjVal(connectionData, 'map.id') || 0;
|
||||
let connectionId = this.Util.getObjVal(connectionData, 'connection.id') || 0;
|
||||
let scope = this.Util.getObjVal(connectionData, 'connection.scope') || '';
|
||||
let classes = MapUtil.getConnectionFakeClassesByTypes(this.Util.getObjVal(connectionData, 'connection.type') || []);
|
||||
let disabled = !mapId || !connectionId;
|
||||
|
||||
let connectionElement = '<div data-mapId="' + mapId + '" data-connectionId="' + connectionId + '" ';
|
||||
connectionElement += (disabled ? 'data-disabled' : '');
|
||||
connectionElement += ' class="' + classes.join(' ') + '" ';
|
||||
connectionElement += ' title="' + scope + '" data-placement="bottom"></div>';
|
||||
return connectionElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* get static instance of in-memory Cache() store by 'name'
|
||||
* -> not persistent across page reloads
|
||||
* -> persistent across module instances (different and same maps)
|
||||
* @param name
|
||||
* @returns {Cache}
|
||||
*/
|
||||
static getCache(name){
|
||||
let key = `CACHE-${name}`;
|
||||
if(!this.Util.getObjVal(this, key)){
|
||||
let configKey = `cacheConfig.${name}`;
|
||||
let cacheConfig = this.Util.getObjVal(this, configKey);
|
||||
if(!cacheConfig){
|
||||
console.warn('Missing Cache config for %o. Expected at %o. Default config loaded…',
|
||||
name, `${this.name}.${configKey}`
|
||||
);
|
||||
cacheConfig = {};
|
||||
}else{
|
||||
// set cache name
|
||||
cacheConfig.name = name;
|
||||
}
|
||||
|
||||
this[key] = new Cache(cacheConfig);
|
||||
}
|
||||
return this[key];
|
||||
}
|
||||
|
||||
static now(){
|
||||
return new Date().getTime() / 1000;
|
||||
}
|
||||
|
||||
static getOrderPrio(){
|
||||
return this.isPlugin ?
|
||||
this.scopeOrder.indexOf('plugin') :
|
||||
(this.scopeOrder.indexOf(this.scope) !== -1 ?
|
||||
this.scopeOrder.indexOf(this.scope) :
|
||||
this.scopeOrder.length - 1
|
||||
);
|
||||
}
|
||||
|
||||
static newDeferredPromise(){
|
||||
return new DeferredPromise();
|
||||
}
|
||||
@@ -259,6 +471,14 @@ define([
|
||||
BaseModule.fullDataUpdate = false; // static module requires additional data (e.g. system description,...)
|
||||
BaseModule.Util = Util; // static access to Pathfinders Util object
|
||||
|
||||
BaseModule.scopeOrder = [
|
||||
'system',
|
||||
'connection',
|
||||
'global',
|
||||
'plugin',
|
||||
'undefined'
|
||||
];
|
||||
|
||||
BaseModule.handler = [
|
||||
'render',
|
||||
'init',
|
||||
@@ -268,6 +488,14 @@ define([
|
||||
'onSortableEvent'
|
||||
];
|
||||
|
||||
BaseModule.cacheConfig = {
|
||||
mapConnections: {
|
||||
ttl: 5,
|
||||
maxSize: 600,
|
||||
debug: false
|
||||
}
|
||||
};
|
||||
|
||||
BaseModule.defaultConfig = {
|
||||
position: 1,
|
||||
className: 'pf-base-module', // class for module
|
||||
@@ -276,6 +504,7 @@ define([
|
||||
sortTargetAreas: ['a', 'b', 'c'], // sortable areas where module can be dragged into
|
||||
headline: 'Base headline', // module headline
|
||||
bodyClassName: 'pf-module-body', // class for module body [optional: can be used]
|
||||
controlAreaClass: 'pf-module-control-area', // class for "control" areas
|
||||
|
||||
moduleHeadlineIconClass: 'pf-module-icon-button' // class for toolbar icons in the head
|
||||
};
|
||||
|
||||
@@ -78,11 +78,9 @@ define([
|
||||
*/
|
||||
newInfoPanelControlEl(mapId){
|
||||
let connectionEl = this.newConnectionElement(mapId);
|
||||
|
||||
let controlEl = document.createElement('div');
|
||||
controlEl.classList.add(Util.config.dynamicAreaClass, this._config.controlAreaClass);
|
||||
controlEl.insertAdjacentHTML('beforeend', '<i class="fas fa-fw fa-plus"></i> add connection <kbd>ctrl</kbd> + <kbd>click</kbd>');
|
||||
connectionEl.append(controlEl);
|
||||
connectionEl.append(
|
||||
this.newControlElement('add connection <kbd>ctrl</kbd> + <kbd>click</kbd>', [], ['fa-plus'])
|
||||
);
|
||||
|
||||
return connectionEl;
|
||||
}
|
||||
@@ -267,9 +265,12 @@ define([
|
||||
}, context => {
|
||||
// hide loading animation
|
||||
for(let contextData of context.connectionsData){
|
||||
let tableEls = this.moduleElement.querySelector('#' + this.getConnectionElementId(contextData.id))
|
||||
.getElementsByTagName('table');
|
||||
$(tableEls).hideLoadingAnimation();
|
||||
let connectionEl = this.moduleElement.querySelector('#' + this.getConnectionElementId(contextData.id));
|
||||
// connectionEl might be removed in meantime ( e.g. module removed)
|
||||
if(connectionEl){
|
||||
let tableEls = connectionEl.getElementsByTagName('table');
|
||||
$(tableEls).hideLoadingAnimation();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -351,7 +352,7 @@ define([
|
||||
let scopeLabel = MapUtil.getScopeInfoForConnection(connectionData.scope, 'label');
|
||||
|
||||
let element = document.createElement('div');
|
||||
element.classList.add(Util.config.dynamicAreaClass, this._config.controlAreaClass);
|
||||
element.classList.add(BaseModule.Util.config.dynamicAreaClass, this._config.controlAreaClass);
|
||||
|
||||
$(element).append(
|
||||
$('<table>', {
|
||||
@@ -990,7 +991,7 @@ define([
|
||||
|
||||
if(rowData.active){
|
||||
let confirmationSettings = {
|
||||
title: 'delete jump log',
|
||||
title: '---',
|
||||
template: Util.getConfirmationTemplate(null, {
|
||||
size: 'small',
|
||||
noTitle: true
|
||||
@@ -1251,7 +1252,6 @@ define([
|
||||
|
||||
// body
|
||||
connectionInfoPanelClass: 'pf-connection-info-panel', // class for connection info panels
|
||||
controlAreaClass: 'pf-module-control-area', // class for "control" areas
|
||||
|
||||
// info table
|
||||
moduleTableClass: 'pf-module-table', // class for module tables
|
||||
|
||||
@@ -249,7 +249,7 @@ define([ // dependencies for this module
|
||||
}
|
||||
};
|
||||
|
||||
DemoModule.isPlugin = true; // module is defined as 'plugin'
|
||||
DemoModule.isPlugin = true; // module is defined as 'plugin'
|
||||
DemoModule.scope = 'system'; // module scope controls how module gets updated and what type of data is injected
|
||||
DemoModule.sortArea = 'a'; // default sortable area
|
||||
DemoModule.position = 10; // default sort/order position within sortable area
|
||||
|
||||
1028
js/app/ui/module/global_thera.js
Normal file
1028
js/app/ui/module/global_thera.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -42,18 +42,16 @@ define([
|
||||
* @returns {*}
|
||||
*/
|
||||
getDataTableInstance(mapId, systemId, tableType){
|
||||
return Util.getDataTableInstance(this._config.intelTableId, mapId, systemId, tableType);
|
||||
return BaseModule.Util.getDataTableInstance(this._config.intelTableId, mapId, systemId, tableType);
|
||||
}
|
||||
|
||||
/**
|
||||
* get dataTable id
|
||||
* @param mapId
|
||||
* @param systemId
|
||||
* @param tableType
|
||||
* @param {...string} parts e.g. 'tableType', 'mapId', 'systemId'
|
||||
* @returns {string}
|
||||
*/
|
||||
getTableId(tableType, mapId, systemId){
|
||||
return Util.getTableId(this._config.intelTableId, tableType, mapId, systemId);
|
||||
getTableId(...parts){
|
||||
return BaseModule.Util.getTableId(this._config.intelTableId, ...parts);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,7 +61,7 @@ define([
|
||||
* @returns {string}
|
||||
*/
|
||||
getRowId(tableType, id){
|
||||
return Util.getTableRowId(this._config.intelTableRowIdPrefix, tableType, id);
|
||||
return BaseModule.Util.getTableRowId(this._config.intelTableRowIdPrefix, tableType, id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,7 +71,7 @@ define([
|
||||
* @returns {*}
|
||||
*/
|
||||
getRowById(tableApi, id){
|
||||
return tableApi.rows().ids().toArray().find(rowId => rowId === this.getRowId(Util.getObjVal(this.getTableMetaData(tableApi), 'type'), id));
|
||||
return tableApi.rows().ids().toArray().find(rowId => rowId === this.getRowId(BaseModule.Util.getObjVal(this.getTableMetaData(tableApi), 'type'), id));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -85,7 +83,6 @@ define([
|
||||
return tableApi ? tableApi.init().pfMeta : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* vormat roman numeric string to int
|
||||
* -> e.g. 'VII' => 7
|
||||
@@ -331,7 +328,7 @@ define([
|
||||
$(cell).find('i').tooltip();
|
||||
}else{
|
||||
let confirmationSettings = {
|
||||
title: 'delete structure',
|
||||
title: '---',
|
||||
template: Util.getConfirmationTemplate(null, {
|
||||
size: 'small',
|
||||
noTitle: true
|
||||
@@ -397,7 +394,6 @@ define([
|
||||
// "Select" Datatables Plugin
|
||||
tableApiStructure.select();
|
||||
|
||||
// "Buttons" Datatables Plugin
|
||||
tableApiStructure.on('user-select', function(e, tableApi, type, cell, originalEvent){
|
||||
let rowData = tableApi.row(cell.index().row).data();
|
||||
if(Util.getObjVal(rowData, 'rowGroupData.id') !== corporationId){
|
||||
@@ -405,6 +401,7 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
// "Buttons" Datatables Plugin
|
||||
let buttons = new $.fn.dataTable.Buttons(tableApiStructure, {
|
||||
dom: {
|
||||
container: {
|
||||
@@ -421,6 +418,18 @@ define([
|
||||
},
|
||||
name: 'tableTools',
|
||||
buttons: [
|
||||
{
|
||||
name: 'add',
|
||||
className: 'fa-plus',
|
||||
titleAttr: 'add',
|
||||
attr: {
|
||||
'data-toggle': 'tooltip',
|
||||
'data-html': true
|
||||
},
|
||||
action: function(e, tableApi, node, config){
|
||||
module.showStructureDialog(tableApi);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'selectToggle',
|
||||
className: ['fa-check-double'].join(' '),
|
||||
@@ -445,18 +454,6 @@ define([
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'add',
|
||||
className: 'fa-plus',
|
||||
titleAttr: 'add',
|
||||
attr: {
|
||||
'data-toggle': 'tooltip',
|
||||
'data-html': true
|
||||
},
|
||||
action: function(e, tableApi, node, config){
|
||||
module.showStructureDialog(tableApi);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'dScan',
|
||||
className: 'fa-paste',
|
||||
@@ -1066,22 +1063,17 @@ define([
|
||||
api.remove();
|
||||
}
|
||||
|
||||
if(
|
||||
notificationCounter.added > 0 ||
|
||||
notificationCounter.changed > 0 ||
|
||||
notificationCounter.deleted > 0
|
||||
){
|
||||
if(Math.max(...Object.values(notificationCounter))){
|
||||
context.tableApi.draw();
|
||||
}
|
||||
|
||||
// show notification ------------------------------------------------------------------------------------------
|
||||
let notification = '';
|
||||
notification += notificationCounter.added > 0 ? notificationCounter.added + ' added<br>' : '';
|
||||
notification += notificationCounter.changed > 0 ? notificationCounter.changed + ' changed<br>' : '';
|
||||
notification += notificationCounter.deleted > 0 ? notificationCounter.deleted + ' deleted<br>' : '';
|
||||
// show notification --------------------------------------------------------------------------------------
|
||||
let notification = Object.keys(notificationCounter).reduce((acc, key) => {
|
||||
return `${acc}${notificationCounter[key] ? `${notificationCounter[key]} ${key}<br>` : ''}`;
|
||||
}, '');
|
||||
|
||||
if(hadData && notification.length){
|
||||
this.showNotify({title: 'Structures updated', text: notification, type: 'success'});
|
||||
this.showNotify({title: 'Structures updated', text: notification, type: 'success', textTrusted: true});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1291,7 +1283,7 @@ define([
|
||||
*/
|
||||
update(systemData){
|
||||
return super.update(systemData).then(systemData => new Promise(resolve => {
|
||||
// update structure table data --------------------------------------------------------------------------------
|
||||
// update structure table data ------------------------------------------------------------------------
|
||||
let structureContext = {
|
||||
tableApi: $(this.moduleElement.querySelector('.' + this._config.systemStructuresTableClass)).DataTable(),
|
||||
removeMissing: true
|
||||
@@ -1299,7 +1291,7 @@ define([
|
||||
|
||||
this.callbackUpdateTableRows(structureContext, Util.getObjVal(systemData, 'structures'));
|
||||
|
||||
// update station table data ----------------------------------------------------------------------------------
|
||||
// update station table data --------------------------------------------------------------------------
|
||||
let stationContext = {
|
||||
tableApi: $(this.moduleElement.querySelector('.' + this._config.systemStationsTableClass)).DataTable(),
|
||||
removeMissing: false
|
||||
|
||||
@@ -7,9 +7,8 @@ define([
|
||||
'app/init',
|
||||
'app/util',
|
||||
'module/base',
|
||||
'app/lib/cache',
|
||||
'app/map/util'
|
||||
], ($, Init, Util, BaseModule, Cache, MapUtil) => {
|
||||
], ($, Init, Util, BaseModule, MapUtil) => {
|
||||
'use strict';
|
||||
|
||||
let SystemKillboardModule = class SystemKillboardModule extends BaseModule {
|
||||
@@ -99,7 +98,7 @@ define([
|
||||
getSystemKillsData(){
|
||||
// check for cached responses "short term cache"
|
||||
let cacheKey = SystemKillboardModule.getCacheKey('systemId', this._systemData.systemId);
|
||||
let result = SystemKillboardModule.zkbCache.get(cacheKey);
|
||||
let result = SystemKillboardModule.getCache('zkb').get(cacheKey);
|
||||
if(result){
|
||||
// could also be an empty array!
|
||||
return Promise.resolve(result);
|
||||
@@ -125,7 +124,7 @@ define([
|
||||
return Promise.reject(result);
|
||||
}else{
|
||||
// zkb result needs to be cached and becomes reduced on "load more"
|
||||
SystemKillboardModule.zkbCache.set(cacheKey, result);
|
||||
SystemKillboardModule.getCache('zkb').set(cacheKey, result);
|
||||
return result;
|
||||
}
|
||||
}).then(result => resolve(result)).catch(e => {
|
||||
@@ -186,15 +185,10 @@ define([
|
||||
this._killboardEl = document.createElement('ul');
|
||||
this._killboardEl.classList.add(this._config.systemKillboardListClass);
|
||||
|
||||
let controlEl = document.createElement('div');
|
||||
controlEl.classList.add(Util.config.dynamicAreaClass, this._config.controlAreaClass, this._config.moduleHeadlineIconClass);
|
||||
controlEl.insertAdjacentHTML('beforeend', ' load more');
|
||||
controlEl.prepend(this.newIconElement(['fa-sync']));
|
||||
|
||||
this._bodyEl.append(
|
||||
this._killboardLabelEl,
|
||||
this._killboardEl,
|
||||
controlEl
|
||||
this.newControlElement('load more', [this._config.moduleHeadlineIconClass])
|
||||
);
|
||||
|
||||
// set a "local" copy of all indexes from cached response
|
||||
@@ -228,7 +222,7 @@ define([
|
||||
showKills(chunkSize){
|
||||
if(chunkSize){
|
||||
let cacheKey = SystemKillboardModule.getCacheKey('systemId', this._systemData.systemId);
|
||||
let result = SystemKillboardModule.zkbCache.get(cacheKey);
|
||||
let result = SystemKillboardModule.getCache('zkb').get(cacheKey);
|
||||
|
||||
if(
|
||||
this._killboardEl.children.length < this._config.maxCountKillHistoric &&
|
||||
@@ -263,7 +257,7 @@ define([
|
||||
*/
|
||||
loadKillmailData(requestData, context, callback){
|
||||
let cacheKey = SystemKillboardModule.getCacheKey('killmail', requestData.killId);
|
||||
let cacheItem = SystemKillboardModule.killmailCache.get(cacheKey);
|
||||
let cacheItem = SystemKillboardModule.getCache('killmail').get(cacheKey);
|
||||
if(cacheItem){
|
||||
// ... already cached -> show cache killmail
|
||||
this[callback](cacheItem.zkb, cacheItem.killmailData, cacheItem.systemData, context.chunkSize)
|
||||
@@ -275,7 +269,7 @@ define([
|
||||
|
||||
this.request(url).then(killmailData => {
|
||||
let systemData = SystemKillboardModule.getSystemDataForCache(this._systemData);
|
||||
SystemKillboardModule.killmailCache.set(cacheKey, {zkb: context.zkb, killmailData: killmailData, systemData: systemData});
|
||||
SystemKillboardModule.getCache('killmail').set(cacheKey, {zkb: context.zkb, killmailData: killmailData, systemData: systemData});
|
||||
|
||||
this[callback](context.zkb, killmailData, systemData, context.chunkSize)
|
||||
.then(payload => this.showKills(payload.data.chunkSize))
|
||||
@@ -445,18 +439,6 @@ define([
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param text
|
||||
* @param cls
|
||||
* @returns {HTMLSpanElement}
|
||||
*/
|
||||
newLabelElement(text, cls = []){
|
||||
let labelEl = document.createElement('span');
|
||||
labelEl.classList.add('label', 'center-block', ...cls);
|
||||
labelEl.textContent = text || '';
|
||||
return labelEl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Li headline (devider)
|
||||
* @param text
|
||||
@@ -668,7 +650,7 @@ define([
|
||||
*/
|
||||
static getWsRelevantSystemsFromMaps(){
|
||||
let cacheKey = SystemKillboardModule.getCacheKey('tempSystemsData', 1);
|
||||
let systemsData = SystemKillboardModule.zkbCache.get(cacheKey);
|
||||
let systemsData = SystemKillboardModule.getCache('zkb').get(cacheKey);
|
||||
|
||||
if(!systemsData){
|
||||
// KB cache ist for all maps (not just the current one)
|
||||
@@ -683,7 +665,7 @@ define([
|
||||
), {})
|
||||
), {});
|
||||
|
||||
SystemKillboardModule.zkbCache.set(cacheKey, systemsData);
|
||||
SystemKillboardModule.getCache('zkb').set(cacheKey, systemsData);
|
||||
}
|
||||
return systemsData;
|
||||
}
|
||||
@@ -705,7 +687,7 @@ define([
|
||||
// system is on map! -> cache
|
||||
systemData = BaseModule.Util.getObjVal(systemsData, String(killmailData.solar_system_id));
|
||||
let cacheKey = SystemKillboardModule.getCacheKey('killmail', killmailData.killmail_id);
|
||||
SystemKillboardModule.killmailCache.set(cacheKey, {
|
||||
SystemKillboardModule.getCache('killmail').set(cacheKey, {
|
||||
zkb: zkbData,
|
||||
killmailData: killmailData,
|
||||
systemData: systemData
|
||||
@@ -800,19 +782,17 @@ define([
|
||||
SystemKillboardModule.label = 'Killboard'; // static module label (e.g. description)
|
||||
SystemKillboardModule.wsStatus = undefined;
|
||||
SystemKillboardModule.serverTime = BaseModule.Util.getServerTime(); // static Date() with current EVE server time
|
||||
SystemKillboardModule.zkbCache = new Cache({ // cache for "zKillboard" responses -> short term cache
|
||||
name: 'zkb',
|
||||
ttl: 60 * 3,
|
||||
maxSize: 50,
|
||||
debug: false
|
||||
});
|
||||
SystemKillboardModule.killmailCache = new Cache({ // cache for "Killmail" data -> long term cache
|
||||
name: 'ccpKillmails',
|
||||
ttl: 60 * 30,
|
||||
maxSize: 500,
|
||||
debug: false
|
||||
});
|
||||
SystemKillboardModule.wsSubscribtions = []; // static container for all KB module instances (from multiple maps) for WS responses
|
||||
SystemKillboardModule.cacheConfig = {
|
||||
zkb: { // cache for "zKillboard" responses -> short term cache
|
||||
ttl: 60 * 3,
|
||||
maxSize: 50
|
||||
},
|
||||
killmail: { // cache for "Killmail" data -> long term cache
|
||||
ttl: 60 * 30,
|
||||
maxSize: 500
|
||||
}
|
||||
};
|
||||
|
||||
SystemKillboardModule.defaultConfig = {
|
||||
className: 'pf-system-killboard-module', // class for module
|
||||
@@ -829,7 +809,6 @@ define([
|
||||
wsStatusWrapperClass: 'pf-system-killboard-wsStatusWrapper', // class for WebSocket "status" wrapper
|
||||
wsStatusClass: 'pf-system-killboard-wsStatus', // class for WebSocket "status" headline
|
||||
labelRecentKillsClass: 'pf-system-killboard-label-recent', // class for "recent kills" label
|
||||
controlAreaClass: 'pf-module-control-area', // class for "control" areas
|
||||
|
||||
minCountKills: 5,
|
||||
chunkCountKills: 5,
|
||||
|
||||
@@ -12,12 +12,6 @@ define([
|
||||
], ($, Init, Util, bootbox, MapUtil, BaseModule) => {
|
||||
'use strict';
|
||||
|
||||
// cache for system routes
|
||||
let cache = {
|
||||
systemRoutes: {}, // jump information between solar systems
|
||||
mapConnections: {} // connection data read from UI
|
||||
};
|
||||
|
||||
let SystemRouteModule = class SystemRouteModule extends BaseModule {
|
||||
constructor(config = {}) {
|
||||
super(Object.assign({}, new.target.defaultConfig, config));
|
||||
@@ -275,7 +269,7 @@ define([
|
||||
let tempTableElement = this;
|
||||
|
||||
let confirmationSettings = {
|
||||
title: 'delete route',
|
||||
title: '---',
|
||||
template: Util.getConfirmationTemplate(null, {
|
||||
size: 'small',
|
||||
noTitle: true
|
||||
@@ -434,7 +428,7 @@ define([
|
||||
if(systemFromData.name !== systemToData.name){
|
||||
// check for cached rowData
|
||||
let cacheKey = this.getRouteDataCacheKey([mapId], systemFromData.name, systemToData.name);
|
||||
let rowData = this.getCacheData('systemRoutes', cacheKey);
|
||||
let rowData = SystemRouteModule.getCache('routes').get(cacheKey);
|
||||
if(rowData){
|
||||
// route data is cached (client side)
|
||||
rowElements.push(this.addRow(rowData));
|
||||
@@ -479,29 +473,7 @@ define([
|
||||
* @returns {string}
|
||||
*/
|
||||
getRouteDataCacheKey(mapIds, sourceName, targetName){
|
||||
return [mapIds.join('_'), sourceName.toLowerCase(), targetName.toLowerCase()].join('###');
|
||||
}
|
||||
|
||||
/**
|
||||
* get cache data
|
||||
* @param cacheType
|
||||
* @param cacheKey
|
||||
* @returns {null}
|
||||
*/
|
||||
getCacheData(cacheType, cacheKey){
|
||||
let cachedData = null;
|
||||
let currentTimestamp = Util.getServerTime().getTime();
|
||||
|
||||
if(
|
||||
cache[cacheType].hasOwnProperty(cacheKey) &&
|
||||
Math.round(
|
||||
( currentTimestamp - (new Date( cache[cacheType][cacheKey].updated * 1000).getTime())) / 1000
|
||||
) <= this._config.routeCacheTTL
|
||||
){
|
||||
cachedData = cache[cacheType][cacheKey].data;
|
||||
}
|
||||
|
||||
return cachedData;
|
||||
return `route_` + `${mapIds.join('_')}${sourceName}${targetName}`.hashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -578,7 +550,7 @@ define([
|
||||
if(rowData.route){
|
||||
// update route cache
|
||||
let cacheKey = this.getRouteDataCacheKey(rowData.mapIds, routeData.systemFromData.name, routeData.systemToData.name);
|
||||
this.setCacheData('systemRoutes', cacheKey, rowData);
|
||||
SystemRouteModule.getCache('routes').set(cacheKey, rowData);
|
||||
|
||||
this.addRow(rowData);
|
||||
}
|
||||
@@ -731,7 +703,7 @@ define([
|
||||
let routeJumpElements = [];
|
||||
let avgSecTemp = 0;
|
||||
|
||||
let connectionsData = this.getConnectionsDataFromMaps(routeData.mapIds);
|
||||
let connectionsData = BaseModule.getConnectionsDataFromMaps(routeData.mapIds);
|
||||
let prevRouteNodeData = null;
|
||||
// loop all systems on this route
|
||||
for(let i = 0; i < routeData.route.length; i++){
|
||||
@@ -740,11 +712,11 @@ define([
|
||||
|
||||
// fake connection elements between systems -----------------------------------------------------------
|
||||
if(prevRouteNodeData){
|
||||
let connectionData = this.findConnectionsData(connectionsData, prevRouteNodeData.system, systemName);
|
||||
if(!connectionData.hasOwnProperty('connection')){
|
||||
connectionData = this.getFakeConnectionData(prevRouteNodeData, routeNodeData, isWormholeSystemName(systemName) ? 'wh' : 'stargate');
|
||||
let connectionData = BaseModule.findConnectionsData(connectionsData, prevRouteNodeData.system, systemName);
|
||||
if(!connectionData){
|
||||
connectionData = BaseModule.getFakeConnectionData(prevRouteNodeData, routeNodeData, isWormholeSystemName(systemName) ? 'wh' : 'stargate');
|
||||
}
|
||||
let connectionElement = this.getFakeConnectionElement(connectionData);
|
||||
let connectionElement = BaseModule.getFakeConnectionElement(connectionData);
|
||||
|
||||
routeJumpElements.push(connectionElement);
|
||||
}
|
||||
@@ -809,153 +781,6 @@ define([
|
||||
return tableRowData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a connectionsData object that holds all connections for given mapIds (used as cache for route search)
|
||||
* @param mapIds
|
||||
* @returns {{}}
|
||||
*/
|
||||
getConnectionsDataFromMaps(mapIds){
|
||||
let connectionsData = {};
|
||||
for(let mapId of mapIds){
|
||||
let map = MapUtil.getMapInstance(mapId);
|
||||
if(map){
|
||||
let cacheKey = 'map_' + mapId;
|
||||
let mapConnectionsData = this.getCacheData('mapConnections', cacheKey);
|
||||
|
||||
if(!mapConnectionsData){
|
||||
mapConnectionsData = {};
|
||||
let connections = map.getAllConnections();
|
||||
if(connections.length){
|
||||
let connectionsData = MapUtil.getDataByConnections(connections);
|
||||
for(let connectionData of connectionsData){
|
||||
let connectionDataCacheKey = this.getConnectionDataCacheKey(connectionData.sourceName, connectionData.targetName);
|
||||
|
||||
// skip double connections between same systems
|
||||
if(!mapConnectionsData.hasOwnProperty(connectionDataCacheKey)){
|
||||
mapConnectionsData[connectionDataCacheKey] = {
|
||||
map: {
|
||||
id: mapId
|
||||
},
|
||||
connection: {
|
||||
id: connectionData.id,
|
||||
type: connectionData.type,
|
||||
scope: connectionData.scope
|
||||
},
|
||||
source: {
|
||||
id: connectionData.source,
|
||||
name: connectionData.sourceName,
|
||||
alias: connectionData.sourceAlias
|
||||
},
|
||||
target: {
|
||||
id: connectionData.target,
|
||||
name: connectionData.targetName,
|
||||
alias: connectionData.targetAlias
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update cache
|
||||
this.setCacheData('mapConnections', cacheKey, mapConnectionsData);
|
||||
}
|
||||
|
||||
if(connectionsData !== null){
|
||||
connectionsData = Object.assign({}, mapConnectionsData, connectionsData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return connectionsData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get fake connection data (default connection type in case connection was not found on a map)
|
||||
* @param sourceRouteNodeData
|
||||
* @param targetRouteNodeData
|
||||
* @param scope
|
||||
* @returns {{connection: {id: number, type: string[], scope: string}, source: {id: number, name, alias}, target: {id: number, name, alias}}}
|
||||
*/
|
||||
getFakeConnectionData(sourceRouteNodeData, targetRouteNodeData, scope = 'stargate'){
|
||||
return {
|
||||
connection: {
|
||||
id: 0,
|
||||
type: [MapUtil.getDefaultConnectionTypeByScope(scope)],
|
||||
scope: scope
|
||||
},
|
||||
source: {
|
||||
id: 0,
|
||||
name: sourceRouteNodeData.system,
|
||||
alias: sourceRouteNodeData.system
|
||||
},
|
||||
target: {
|
||||
id: 0,
|
||||
name: targetRouteNodeData.system,
|
||||
alias: targetRouteNodeData.system
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* get fake connection Element
|
||||
* @param connectionData
|
||||
* @returns {string}
|
||||
*/
|
||||
getFakeConnectionElement(connectionData){
|
||||
let mapId = Util.getObjVal(connectionData, 'map.id') | 0;
|
||||
let connectionId = Util.getObjVal(connectionData, 'connection.id') | 0;
|
||||
let scope = Util.getObjVal(connectionData, 'connection.scope');
|
||||
let classes = MapUtil.getConnectionFakeClassesByTypes(connectionData.connection.type);
|
||||
let disabled = !mapId || !connectionId;
|
||||
|
||||
let connectionElement = '<div data-mapId="' + mapId + '" data-connectionId="' + connectionId + '" ';
|
||||
connectionElement += (disabled ? 'data-disabled' : '');
|
||||
connectionElement += ' class="' + classes.join(' ') + '" ';
|
||||
connectionElement += ' title="' + scope + '" data-placement="bottom"></div>';
|
||||
return connectionElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* search for a specific connection by "source"/"target"-name inside connectionsData cache
|
||||
* @param connectionsData
|
||||
* @param sourceName
|
||||
* @param targetName
|
||||
* @returns {{}}
|
||||
*/
|
||||
findConnectionsData(connectionsData, sourceName, targetName){
|
||||
let connectionDataCacheKey = this.getConnectionDataCacheKey(sourceName, targetName);
|
||||
return connectionsData.hasOwnProperty(connectionDataCacheKey) ?
|
||||
connectionsData[connectionDataCacheKey] : {};
|
||||
}
|
||||
|
||||
/**
|
||||
* get a unique cache key name for "source"/"target"-name
|
||||
* @param sourceName
|
||||
* @param targetName
|
||||
* @returns {*}
|
||||
*/
|
||||
getConnectionDataCacheKey(sourceName, targetName){
|
||||
let key = false;
|
||||
if(sourceName && targetName){
|
||||
// names can be "undefined" in case system is currently on drag/drop
|
||||
key = [sourceName.toLowerCase(), targetName.toLowerCase()].sort().join('###');
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* set cache data
|
||||
* @param cacheType
|
||||
* @param cacheKey
|
||||
* @param data
|
||||
*/
|
||||
setCacheData(cacheType, cacheKey, data){
|
||||
cache[cacheType][cacheKey] = {
|
||||
data: data,
|
||||
updated: Util.getServerTime().getTime() / 1000
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mapId
|
||||
@@ -1351,6 +1176,12 @@ define([
|
||||
SystemRouteModule.sortArea = 'b'; // default sortable area
|
||||
SystemRouteModule.position = 1; // default sort/order position within sortable area
|
||||
SystemRouteModule.label = 'Routes'; // static module label (e.g. description)
|
||||
SystemRouteModule.cacheConfig = {
|
||||
routes: {
|
||||
ttl: 5,
|
||||
maxSize: 100
|
||||
}
|
||||
};
|
||||
|
||||
SystemRouteModule.defaultConfig = {
|
||||
className: 'pf-system-route-module', // class for module
|
||||
@@ -1373,8 +1204,6 @@ define([
|
||||
|
||||
systemSecurityClassPrefix: 'pf-system-security-', // prefix class for system security level (color)
|
||||
rallyClass: 'pf-rally', // class for "rally point" style
|
||||
|
||||
routeCacheTTL: 5 // route cache timer (client) in seconds
|
||||
};
|
||||
|
||||
return SystemRouteModule;
|
||||
|
||||
@@ -11,9 +11,8 @@ define([
|
||||
'app/counter',
|
||||
'app/map/map',
|
||||
'app/map/util',
|
||||
'app/lib/cache',
|
||||
'app/ui/form_element'
|
||||
], ($, Init, Util, BaseModule, bootbox, Counter, Map, MapUtil, Cache, FormElement) => {
|
||||
], ($, Init, Util, BaseModule, bootbox, Counter, Map, MapUtil, FormElement) => {
|
||||
'use strict';
|
||||
|
||||
let SystemSignatureModule = class SystemSignatureModule extends BaseModule {
|
||||
@@ -32,13 +31,11 @@ define([
|
||||
|
||||
/**
|
||||
* get dataTable id
|
||||
* @param mapId
|
||||
* @param systemId
|
||||
* @param tableType
|
||||
* @param {...string} parts e.g. 'tableType', 'mapId', 'systemId'
|
||||
* @returns {string}
|
||||
*/
|
||||
getTableId(tableType, mapId, systemId){
|
||||
return Util.getTableId(this._config.sigTableId, tableType, mapId, systemId);
|
||||
getTableId(...parts){
|
||||
return Util.getTableId(this._config.sigTableId, ...parts);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1006,8 +1003,14 @@ define([
|
||||
if(rowData.id){
|
||||
// delete signature -----------------------------------------------------------------------
|
||||
let confirmationSettings = {
|
||||
title: 'Delete signature',
|
||||
template: Util.getConfirmationTemplate(module.getConfirmationContent(), {
|
||||
title: '---',
|
||||
template: Util.getConfirmationTemplate(Util.getConfirmationContent([{
|
||||
name: 'deleteConnection',
|
||||
value: '1',
|
||||
label: 'delete connection',
|
||||
class: 'pf-editable-warn',
|
||||
checked: true
|
||||
}]), {
|
||||
size: 'small',
|
||||
noTitle: true
|
||||
}),
|
||||
@@ -1882,47 +1885,6 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get HTML for "delete connection" confirmation popover
|
||||
* @returns {string}
|
||||
*/
|
||||
getConfirmationContent(){
|
||||
let checkOptions = [{
|
||||
name: 'deleteConnection',
|
||||
value: '1',
|
||||
label: 'delete connection',
|
||||
class: 'pf-editable-warn',
|
||||
checked: true
|
||||
}];
|
||||
|
||||
let getChecklist = checkOptions => {
|
||||
let html = '<form class="form-inline editableform popover-content-inner">';
|
||||
html += '<div class="control-group form-group">';
|
||||
html += '<div class="editable-input">';
|
||||
html += '<div class="editable-checklist">';
|
||||
|
||||
for(let option of checkOptions){
|
||||
html += '<div><label>';
|
||||
html += '<input type="checkbox" name="' + option.name + '" value="' + option.value + '" ';
|
||||
html += 'class="' + option.class + '" ' + (option.checked ? 'checked' : '') + '>';
|
||||
html += '<span>' + option.label + '</span>';
|
||||
html += '</label></div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
html += '</form>';
|
||||
|
||||
return html;
|
||||
};
|
||||
|
||||
let html = '';
|
||||
html += getChecklist(checkOptions);
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
/**
|
||||
* open xEditable input field in "new Signature" table
|
||||
*/
|
||||
@@ -2723,18 +2685,12 @@ define([
|
||||
return acc;
|
||||
}, Object.assign({}, SystemSignatureModule.emptySignatureReaderCounterData));
|
||||
|
||||
let notification = '';
|
||||
if(notificationCounter.added > 0){
|
||||
notification += notificationCounter.added + ' added<br>';
|
||||
}
|
||||
if(notificationCounter.changed > 0){
|
||||
notification += notificationCounter.changed + ' updated<br>';
|
||||
}
|
||||
if(notificationCounter.deleted > 0){
|
||||
notification += notificationCounter.deleted + ' deleted<br>';
|
||||
}
|
||||
let notification = Object.keys(notificationCounter).reduce((acc, key) => {
|
||||
return `${acc}${notificationCounter[key] ? `${notificationCounter[key]} ${key}<br>` : ''}`;
|
||||
}, '');
|
||||
|
||||
if(notification.length){
|
||||
Util.showNotify({title: 'Signatures updated', text: notification, type: 'success'});
|
||||
Util.showNotify({title: 'Signatures updated', text: notification, type: 'success', textTrusted: true});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2917,7 +2873,7 @@ define([
|
||||
|
||||
let cacheKey = [systemTypeId, ...areaIds, groupId].join('_');
|
||||
|
||||
let newSelectOptions = SystemSignatureModule.sigTypeOptionsCache.get(cacheKey);
|
||||
let newSelectOptions = SystemSignatureModule.getCache('sigTypeOptions').get(cacheKey);
|
||||
|
||||
// check for cached signature names
|
||||
if(Array.isArray(newSelectOptions)){
|
||||
@@ -3014,7 +2970,7 @@ define([
|
||||
}
|
||||
|
||||
// update cache (clone array) -> further manipulation to this array, should not be cached
|
||||
SystemSignatureModule.sigTypeOptionsCache.set(cacheKey, newSelectOptions.slice(0));
|
||||
SystemSignatureModule.getCache('sigTypeOptions').set(cacheKey, newSelectOptions.slice(0));
|
||||
}
|
||||
|
||||
// static wormholes (DO NOT CACHE) (not all C2 WHs have the same statics..)
|
||||
@@ -3120,13 +3076,12 @@ define([
|
||||
SystemSignatureModule.position = 4; // default sort/order position within sortable area
|
||||
SystemSignatureModule.label = 'Signatures'; // static module label (e.g. description)
|
||||
SystemSignatureModule.fullDataUpdate = true; // static module requires additional data (e.g. system description,...)
|
||||
|
||||
SystemSignatureModule.sigTypeOptionsCache = new Cache({ // cache signature names
|
||||
name: 'sigTypeOptions',
|
||||
ttl: 60 * 5,
|
||||
maxSize: 100,
|
||||
debug: false
|
||||
});
|
||||
SystemSignatureModule.cacheConfig = {
|
||||
sigTypeOptions: { // cache signature names
|
||||
ttl: 60 * 5,
|
||||
maxSize: 100
|
||||
}
|
||||
};
|
||||
|
||||
SystemSignatureModule.validSignatureNames = [ // allowed signature type/names
|
||||
'Cosmic Anomaly',
|
||||
|
||||
257
js/app/util.js
257
js/app/util.js
@@ -6,6 +6,7 @@ define([
|
||||
'app/init',
|
||||
'app/lib/prototypes',
|
||||
'app/lib/console',
|
||||
'app/lib/cache',
|
||||
'app/lib/localStore',
|
||||
'conf/system_effect',
|
||||
'conf/signature_type',
|
||||
@@ -20,7 +21,7 @@ define([
|
||||
'bootstrapConfirmation',
|
||||
'bootstrapToggle',
|
||||
'select2'
|
||||
], ($, Init, Proto, Con, LocalStoreManager, SystemEffect, SignatureType, bootbox) => {
|
||||
], ($, Init, Proto, Con, Cache, LocalStoreManager, SystemEffect, SignatureType, bootbox) => {
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -102,8 +103,17 @@ define([
|
||||
localStoreNames: ['default', 'character', 'map', 'module'] // Allowed name identifiers for DB names
|
||||
};
|
||||
|
||||
let stopTimerCache = {}; // cache for stopwatch timer
|
||||
let currentSystemDataCache = new Cache({
|
||||
name: 'currentSystemData',
|
||||
ttl: -1,
|
||||
maxSize: 20
|
||||
});
|
||||
|
||||
// browser tab blink
|
||||
let initialPageTitle = document.title; // initial page title (cached)
|
||||
let blinkTimer; // global blink timeout cache
|
||||
|
||||
let stopTimerCache = {}; // cache for stopwatch timer
|
||||
let animationTimerCache = {}; // cache for table row animation timeout
|
||||
|
||||
/*
|
||||
@@ -402,22 +412,57 @@ define([
|
||||
$.fn.initMapUpdateCounter = function(){
|
||||
let counterChart = $(this);
|
||||
|
||||
counterChart.easyPieChart({
|
||||
barColor: function(percent){
|
||||
let color = '#568a89';
|
||||
if(percent <= 30){
|
||||
color = '#d9534f';
|
||||
}else if(percent <= 50){
|
||||
color = '#f0ad4e';
|
||||
}
|
||||
let gradient = [
|
||||
[0, [217,83,79]],
|
||||
[10, [217,83,79]],
|
||||
[50, [240, 173, 78]],
|
||||
[75, [79,158,79]],
|
||||
[100, [86, 138, 137]]
|
||||
];
|
||||
|
||||
return color;
|
||||
},
|
||||
let gradientWidth = 500;
|
||||
|
||||
let getColor = percent => {
|
||||
percent = percent || 1;
|
||||
let colorRangeEnd = gradient.findIndex(value => percent <= value[0]);
|
||||
let colorRange = [colorRangeEnd - 1, colorRangeEnd];
|
||||
|
||||
//Get the two closest colors
|
||||
let colorFirst = gradient[colorRange[0]][1];
|
||||
let colorSecond = gradient[colorRange[1]][1];
|
||||
|
||||
//Calculate ratio between the two closest colors
|
||||
let colorFirstX = gradientWidth * (gradient[colorRange[0]][0] / 100);
|
||||
let colorSecondX = gradientWidth * (gradient[colorRange[1]][0] / 100) - colorFirstX;
|
||||
let weightX = gradientWidth * (percent / 100) - colorFirstX;
|
||||
let weight = weightX / colorSecondX;
|
||||
|
||||
//Get the color with pickHex(thx, less.js's mix function!)
|
||||
let result = pickHex(colorSecond, colorFirst, weight);
|
||||
return `rgb(${result.join()})`;
|
||||
};
|
||||
|
||||
let pickHex = (color1, color2, weight) => {
|
||||
let w1 = weight;
|
||||
let w2 = 1 - w1;
|
||||
return [Math.round(color1[0] * w1 + color2[0] * w2),
|
||||
Math.round(color1[1] * w1 + color2[1] * w2),
|
||||
Math.round(color1[2] * w1 + color2[2] * w2)];
|
||||
};
|
||||
|
||||
counterChart.easyPieChart({
|
||||
barColor: percent => getColor(Number(Number(percent).toFixed(1))),
|
||||
trackColor: '#2b2b2b',
|
||||
size: 30,
|
||||
scaleColor: false,
|
||||
lineWidth: 2,
|
||||
animate: 1000
|
||||
animate: {
|
||||
duration: 550,
|
||||
enabled: true
|
||||
},
|
||||
easing: function (x, t, b, c, d) { // easeInOutSine - jQuery Easing
|
||||
return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1172,6 +1217,39 @@ define([
|
||||
return html;
|
||||
};
|
||||
|
||||
/**
|
||||
* get HTML for "delete connection" confirmation popover
|
||||
* @returns {string}
|
||||
*/
|
||||
let getConfirmationContent = checkOptions => {
|
||||
let getChecklist = checkOptions => {
|
||||
let html = '<form class="form-inline editableform popover-content-inner">';
|
||||
html += '<div class="control-group form-group">';
|
||||
html += '<div class="editable-input">';
|
||||
html += '<div class="editable-checklist">';
|
||||
|
||||
for(let option of checkOptions){
|
||||
html += '<div><label>';
|
||||
html += '<input type="checkbox" name="' + option.name + '" value="' + option.value + '" ';
|
||||
html += 'class="' + option.class + '" ' + (option.checked ? 'checked' : '') + '>';
|
||||
html += '<span>' + option.label + '</span>';
|
||||
html += '</label></div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
html += '</form>';
|
||||
|
||||
return html;
|
||||
};
|
||||
|
||||
let html = '';
|
||||
html += getChecklist(checkOptions);
|
||||
|
||||
return html;
|
||||
};
|
||||
|
||||
/**
|
||||
* convert XEditable Select <option> data into Select2 data format
|
||||
* -> "prepend" (empty) options get added, too
|
||||
@@ -1547,15 +1625,7 @@ define([
|
||||
let parts = {};
|
||||
let time1 = date1.getTime();
|
||||
let time2 = date2.getTime();
|
||||
let diff = 0;
|
||||
|
||||
if(
|
||||
time1 >= 0 &&
|
||||
time2 >= 0
|
||||
){
|
||||
diff = (date2.getTime() - date1.getTime()) / 1000;
|
||||
}
|
||||
|
||||
let diff = (time1 >= 0 && time2 >= 0) ? (time2 - time1) / 1000 : 0;
|
||||
diff = Math.abs(Math.floor(diff));
|
||||
|
||||
parts.days = Math.floor(diff/(24*60*60));
|
||||
@@ -1664,21 +1734,62 @@ define([
|
||||
|
||||
/**
|
||||
* trigger a notification (on screen or desktop)
|
||||
* @param args
|
||||
* @param config
|
||||
* @param options
|
||||
*/
|
||||
let showNotify = (...args) => {
|
||||
requirejs(['PNotify.loader'], Notification => {
|
||||
Notification.showNotify(...args);
|
||||
let showNotify = (config = {}, options = {}) => {
|
||||
requirejs(['pnotify.loader'], Notification => {
|
||||
// if notification is a "desktio" notification -> blink browser tab
|
||||
if(options.desktop && config.title){
|
||||
startTabBlink(config.title);
|
||||
}
|
||||
|
||||
Notification.showNotify(config, options);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* change document.title and make the browsers tab blink
|
||||
* @param blinkTitle
|
||||
*/
|
||||
let startTabBlink = blinkTitle => {
|
||||
let initBlink = (function(){
|
||||
// count blinks if tab is currently active
|
||||
let activeTabBlinkCount = 0;
|
||||
|
||||
let blink = (blinkTitle) => {
|
||||
// number of "blinks" should be limited if tab is currently active
|
||||
if(window.isVisible){
|
||||
activeTabBlinkCount++;
|
||||
}
|
||||
|
||||
// toggle page title
|
||||
document.title = (document.title === blinkTitle) ? initialPageTitle : blinkTitle;
|
||||
|
||||
if(activeTabBlinkCount > 10){
|
||||
stopTabBlink();
|
||||
}
|
||||
};
|
||||
|
||||
return () => {
|
||||
if(!blinkTimer){
|
||||
blinkTimer = setInterval(blink, 1000, blinkTitle);
|
||||
}
|
||||
};
|
||||
}(blinkTitle));
|
||||
|
||||
initBlink();
|
||||
};
|
||||
|
||||
/**
|
||||
* stop browser tab title "blinking"
|
||||
*/
|
||||
let stopTabBlink = () => {
|
||||
requirejs(['PNotify.loader'], Notification => {
|
||||
Notification.stopTabBlink();
|
||||
});
|
||||
if(blinkTimer){
|
||||
clearInterval(blinkTimer);
|
||||
document.title = initialPageTitle;
|
||||
blinkTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -2707,9 +2818,7 @@ define([
|
||||
* @param mapId
|
||||
*/
|
||||
let deleteCurrentMapData = mapId => {
|
||||
Init.currentMapData = Init.currentMapData.filter(mapData => {
|
||||
return (mapData.config.id !== mapId);
|
||||
});
|
||||
Init.currentMapData = Init.currentMapData.filter(mapData => mapData.config.id !== mapId);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -3036,19 +3145,45 @@ define([
|
||||
};
|
||||
|
||||
/**
|
||||
* set currentSystemData as "global" variable
|
||||
* set currentSystemData (active system)
|
||||
* @param mapId
|
||||
* @param systemData
|
||||
*/
|
||||
let setCurrentSystemData = (systemData) => {
|
||||
Init.currentSystemData = systemData;
|
||||
let setCurrentSystemData = (mapId, systemData) => {
|
||||
mapId = parseInt(mapId) || 0;
|
||||
if(mapId && typeof systemData === 'object'){
|
||||
currentSystemDataCache.set(`mapId_${mapId}`, systemData);
|
||||
}else{
|
||||
console.error('Invalid mapId %o or systemData %o');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* get currentSystemData from "global" variables
|
||||
* get currentSystemData (active system)
|
||||
* @param mapId
|
||||
* @returns {*}
|
||||
*/
|
||||
let getCurrentSystemData = () => {
|
||||
return Init.currentSystemData;
|
||||
let getCurrentSystemData = mapId => {
|
||||
mapId = parseInt(mapId) || 0;
|
||||
if(mapId){
|
||||
return currentSystemDataCache.get(`mapId_${mapId}`);
|
||||
}else{
|
||||
console.error('Invalid mapId %o');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* delete currentSystemData (active system)
|
||||
* @param mapId
|
||||
* @returns {*}
|
||||
*/
|
||||
let deleteCurrentSystemData = mapId => {
|
||||
mapId = parseInt(mapId) || 0;
|
||||
if(mapId){
|
||||
return currentSystemDataCache.delete(`mapId_${mapId}`);
|
||||
}else{
|
||||
console.error('Invalid mapId %o');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -3217,40 +3352,32 @@ define([
|
||||
* @param doubleClickCallback
|
||||
* @param timeout
|
||||
*/
|
||||
let singleDoubleClick = (element, singleClickCallback, doubleClickCallback, timeout) => {
|
||||
let eventName = 'mouseup.singleDouble';
|
||||
if(!hasEvent(element, eventName)){
|
||||
let clicks = 0;
|
||||
// prevent default behaviour (e.g. open <a>-tag link)
|
||||
element.off('click').on('click', function(e){
|
||||
e.preventDefault();
|
||||
});
|
||||
let singleDoubleClick = (element, singleClickCallback, doubleClickCallback, timeout = Init.timer.DBL_CLICK) => {
|
||||
element.addEventListener('click', e => {
|
||||
if(e.detail === 1){
|
||||
// single click -> setTimeout and check if there is a 2nd click incoming before timeout
|
||||
let clickTimeoutId = setTimeout(element => {
|
||||
singleClickCallback.call(element, e);
|
||||
element.removeData('clickTimeoutId');
|
||||
}, timeout, e.currentTarget);
|
||||
|
||||
element.off(eventName).on(eventName, function(e){
|
||||
clicks++;
|
||||
if(clicks === 1){
|
||||
setTimeout(element => {
|
||||
if(clicks === 1){
|
||||
singleClickCallback.call(element, e);
|
||||
}else{
|
||||
doubleClickCallback.call(element, e);
|
||||
}
|
||||
clicks = 0;
|
||||
}, timeout || Init.timer.DBL_CLICK, this);
|
||||
}
|
||||
});
|
||||
}
|
||||
e.currentTarget.setData('clickTimeoutId', clickTimeoutId);
|
||||
}else if(e.detail === 2 ){
|
||||
// double click -> clearTimeout, (triple, quadruple, etc. clicks are ignored)
|
||||
doubleClickCallback.call(element, e);
|
||||
clearTimeout(e.currentTarget.getData('clickTimeoutId'));
|
||||
e.currentTarget.removeData('clickTimeoutId');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* get dataTable id
|
||||
* @param prefix
|
||||
* @param mapId
|
||||
* @param systemId
|
||||
* @param tableType
|
||||
* @param {...string} parts e.g. 'tableType', 'mapId', 'systemId'
|
||||
* @returns {string}
|
||||
*/
|
||||
let getTableId = (prefix, tableType, mapId, systemId) => prefix + [tableType, mapId, systemId].join('-');
|
||||
let getTableId = (prefix, ...parts) => prefix + parts.filter(Boolean).join('-');
|
||||
|
||||
/**
|
||||
* get dataTable row id
|
||||
@@ -3523,12 +3650,14 @@ define([
|
||||
getCurrentCharacterId: getCurrentCharacterId,
|
||||
setCurrentSystemData: setCurrentSystemData,
|
||||
getCurrentSystemData: getCurrentSystemData,
|
||||
deleteCurrentSystemData:deleteCurrentSystemData,
|
||||
getCurrentLocationData: getCurrentLocationData,
|
||||
getCurrentUserInfo: getCurrentUserInfo,
|
||||
getCurrentCharacterLog: getCurrentCharacterLog,
|
||||
findInViewport: findInViewport,
|
||||
initScrollSpy: initScrollSpy,
|
||||
getConfirmationTemplate: getConfirmationTemplate,
|
||||
getConfirmationContent: getConfirmationContent,
|
||||
convertXEditableOptionsToSelect2: convertXEditableOptionsToSelect2,
|
||||
flattenXEditableSelectArray: flattenXEditableSelectArray,
|
||||
getCharacterDataBySystemId: getCharacterDataBySystemId,
|
||||
|
||||
25
js/lib/datatables/RowGroup-1.1.1/js/dataTables.rowGroup.min.js
vendored
Normal file
25
js/lib/datatables/RowGroup-1.1.1/js/dataTables.rowGroup.min.js
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
/*!
|
||||
Copyright 2017-2019 SpryMedia Ltd.
|
||||
|
||||
This source file is free software, available under the following license:
|
||||
MIT license - http://datatables.net/license/mit
|
||||
|
||||
This source file is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
|
||||
|
||||
For details please refer to: http://www.datatables.net
|
||||
RowGroup 1.1.1
|
||||
©2017-2019 SpryMedia Ltd - datatables.net/license
|
||||
*/
|
||||
var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(a,d,c){a instanceof String&&(a=String(a));for(var e=a.length,f=0;f<e;f++){var h=a[f];if(d.call(c,h,f,a))return{i:f,v:h}}return{i:-1,v:void 0}};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.SIMPLE_FROUND_POLYFILL=!1;
|
||||
$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(a,d,c){a!=Array.prototype&&a!=Object.prototype&&(a[d]=c.value)};$jscomp.getGlobal=function(a){return"undefined"!=typeof window&&window===a?a:"undefined"!=typeof global&&null!=global?global:a};$jscomp.global=$jscomp.getGlobal(this);
|
||||
$jscomp.polyfill=function(a,d,c,e){if(d){c=$jscomp.global;a=a.split(".");for(e=0;e<a.length-1;e++){var f=a[e];f in c||(c[f]={});c=c[f]}a=a[a.length-1];e=c[a];d=d(e);d!=e&&null!=d&&$jscomp.defineProperty(c,a,{configurable:!0,writable:!0,value:d})}};$jscomp.polyfill("Array.prototype.find",function(a){return a?a:function(a,c){return $jscomp.findInternal(this,a,c).v}},"es6","es3");
|
||||
(function(a){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(d){return a(d,window,document)}):"object"===typeof exports?module.exports=function(d,c){d||(d=window);c&&c.fn.dataTable||(c=require("datatables.net")(d,c).$);return a(c,d,d.document)}:a(jQuery,window,document)})(function(a,d,c,e){var f=a.fn.dataTable,h=function(b,g){if(!f.versionCheck||!f.versionCheck("1.10.8"))throw"RowGroup requires DataTables 1.10.8 or newer";this.c=a.extend(!0,{},f.defaults.rowGroup,
|
||||
h.defaults,g);this.s={dt:new f.Api(b)};this.dom={};b=this.s.dt.settings()[0];if(g=b.rowGroup)return g;b.rowGroup=this;this._constructor()};a.extend(h.prototype,{dataSrc:function(b){if(b===e)return this.c.dataSrc;var g=this.s.dt;this.c.dataSrc=b;a(g.table().node()).triggerHandler("rowgroup-datasrc.dt",[g,b]);return this},disable:function(){this.c.enable=!1;return this},enable:function(b){if(!1===b)return this.disable();this.c.enable=!0;return this},_constructor:function(){var b=this,a=this.s.dt;a.on("draw.dtrg",
|
||||
function(){b.c.enable&&b._draw()});a.on("column-visibility.dt.dtrg responsive-resize.dt.dtrg",function(){b._adjustColspan()});a.on("destroy",function(){a.off(".dtrg")});a.on("responsive-resize.dt",function(){b._adjustColspan()})},_adjustColspan:function(){a("tr."+this.c.className,this.s.dt.table().body()).find("td").attr("colspan",this._colspan())},_colspan:function(){return this.s.dt.columns().visible().reduce(function(b,a){return b+a},0)},_draw:function(){var b=this._group(0,this.s.dt.rows({page:"current"}).indexes());
|
||||
this._groupDisplay(0,b)},_group:function(b,g){for(var c=a.isArray(this.c.dataSrc)?this.c.dataSrc:[this.c.dataSrc],d=f.ext.oApi._fnGetObjectDataFn(c[b]),h=this.s.dt,l,n,m=[],k=0,p=g.length;k<p;k++){var q=g[k];l=h.row(q).data();l=d(l);if(null===l||l===e)l=this.c.emptyDataGroup;if(n===e||l!==n)m.push({dataPoint:l,rows:[]}),n=l;m[m.length-1].rows.push(q)}if(c[b+1]!==e)for(k=0,p=m.length;k<p;k++)m[k].children=this._group(b+1,m[k].rows);return m},_groupDisplay:function(b,a){for(var c=this.s.dt,g,d=0,f=
|
||||
a.length;d<f;d++){var e=a[d],h=e.dataPoint,k=e.rows;this.c.startRender&&(g=this.c.startRender.call(this,c.rows(k),h,b),(g=this._rowWrap(g,this.c.startClassName,b))&&g.insertBefore(c.row(k[0]).node()));this.c.endRender&&(g=this.c.endRender.call(this,c.rows(k),h,b),(g=this._rowWrap(g,this.c.endClassName,b))&&g.insertAfter(c.row(k[k.length-1]).node()));e.children&&this._groupDisplay(b+1,e.children)}},_rowWrap:function(b,g,c){if(null===b||""===b)b=this.c.emptyDataGroup;return b===e||null===b?null:("object"===
|
||||
typeof b&&b.nodeName&&"tr"===b.nodeName.toLowerCase()?a(b):b instanceof a&&b.length&&"tr"===b[0].nodeName.toLowerCase()?b:a("<tr/>").append(a("<td/>").attr("colspan",this._colspan()).append(b))).addClass(this.c.className).addClass(g).addClass("dtrg-level-"+c)}});h.defaults={className:"dtrg-group",dataSrc:0,emptyDataGroup:"No group",enable:!0,endClassName:"dtrg-end",endRender:null,startClassName:"dtrg-start",startRender:function(b,a){return a}};h.version="1.1.1";a.fn.dataTable.RowGroup=h;a.fn.DataTable.RowGroup=
|
||||
h;f.Api.register("rowGroup()",function(){return this});f.Api.register("rowGroup().disable()",function(){return this.iterator("table",function(a){a.rowGroup&&a.rowGroup.enable(!1)})});f.Api.register("rowGroup().enable()",function(a){return this.iterator("table",function(b){b.rowGroup&&b.rowGroup.enable(a===e?!0:a)})});f.Api.register("rowGroup().dataSrc()",function(a){return a===e?this.context[0].rowGroup.dataSrc():this.iterator("table",function(b){b.rowGroup&&b.rowGroup.dataSrc(a)})});a(c).on("preInit.dt.dtrg",
|
||||
function(b,c,d){"dt"===b.namespace&&(b=c.oInit.rowGroup,d=f.defaults.rowGroup,b||d)&&(d=a.extend({},d,b),!1!==b&&new h(c,d))});return h});
|
||||
@@ -2036,5 +2036,4 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
||||
function noop() {}
|
||||
|
||||
return PNotify_1;
|
||||
});
|
||||
//# sourceMappingURL=PNotify.js.map
|
||||
});
|
||||
@@ -557,5 +557,4 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
||||
function noop() {}
|
||||
|
||||
return PNotifyButtons;
|
||||
});
|
||||
//# sourceMappingURL=PNotifyButtons.js.map
|
||||
});
|
||||
@@ -253,5 +253,4 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
||||
}
|
||||
|
||||
return PNotifyCallbacks;
|
||||
});
|
||||
//# sourceMappingURL=PNotifyCallbacks.js.map
|
||||
});
|
||||
@@ -460,5 +460,4 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
||||
}
|
||||
|
||||
return PNotifyDesktop;
|
||||
});
|
||||
//# sourceMappingURL=PNotifyDesktop.js.map
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -70,16 +70,16 @@ requirejs.config({
|
||||
'datatables.net-buttons': 'lib/datatables/Buttons-1.5.6/js/dataTables.buttons.min',
|
||||
'datatables.net-buttons-html': 'lib/datatables/Buttons-1.5.6/js/buttons.html5.min',
|
||||
'datatables.net-responsive': 'lib/datatables/Responsive-2.2.2/js/dataTables.responsive.min',
|
||||
'datatables.net-rowgroup': 'lib/datatables/RowGroup-1.1.1/js/dataTables.rowGroup.min',
|
||||
'datatables.net-select': 'lib/datatables/Select-1.3.0/js/dataTables.select.min',
|
||||
'datatables.plugins.render.ellipsis': 'lib/datatables/plugins/render/ellipsis',
|
||||
|
||||
// PNotify // v4.0.0 PNotify - notification core file - https://sciactive.com/pnotify
|
||||
'PNotify.loader': './app/pnotify.loader',
|
||||
'pnotify.loader': './app/pnotify.loader',
|
||||
'PNotify': 'lib/pnotify/PNotify',
|
||||
'PNotifyButtons': 'lib/pnotify/PNotifyButtons',
|
||||
'PNotifyNonBlock': 'lib/pnotify/PNotifyNonBlock',
|
||||
'PNotifyDesktop': 'lib/pnotify/PNotifyDesktop',
|
||||
'PNotifyCallbacks': 'lib/pnotify/PNotifyCallbacks',
|
||||
'PNotifyDesktop': 'lib/pnotify/PNotifyDesktop',
|
||||
'NonBlock': 'lib/pnotify/NonBlock' // v1.0.8 NonBlock.js - for PNotify "nonblock" feature
|
||||
},
|
||||
shim: {
|
||||
@@ -116,6 +116,9 @@ requirejs.config({
|
||||
'datatables.net-responsive': {
|
||||
deps: ['datatables.net']
|
||||
},
|
||||
'datatables.net-rowgroup': {
|
||||
deps: ['datatables.net']
|
||||
},
|
||||
'datatables.net-select': {
|
||||
deps: ['datatables.net']
|
||||
},
|
||||
|
||||
@@ -107,7 +107,7 @@ define([
|
||||
updateDateDiff(element, date, round);
|
||||
}
|
||||
};
|
||||
Cron.set(counterTask);
|
||||
counterTask.start();
|
||||
|
||||
element.attr(config.counterTaskAttr, taskName);
|
||||
}
|
||||
@@ -138,7 +138,7 @@ define([
|
||||
counterTask.task = timer => {
|
||||
tableApi.cells(null, columnSelector).every(cellUpdate);
|
||||
};
|
||||
Cron.set(counterTask);
|
||||
counterTask.start();
|
||||
|
||||
tableElement.attr(config.counterTaskAttr, taskName);
|
||||
};
|
||||
|
||||
@@ -8,7 +8,8 @@ define([
|
||||
'datatables.net-select',
|
||||
'datatables.net-buttons',
|
||||
'datatables.net-buttons-html',
|
||||
'datatables.net-responsive'
|
||||
'datatables.net-responsive',
|
||||
'datatables.net-rowgroup'
|
||||
], ($, Init, Counter, DeferredPromise, TimeoutPromise) => {
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -5,7 +5,7 @@ define([], () => {
|
||||
* Abstract Cache Strategy class
|
||||
* @type {AbstractStrategy}
|
||||
*/
|
||||
let AbstractStrategy = class AbstractStrategy {
|
||||
class AbstractStrategy {
|
||||
constructor(){
|
||||
if(new.target === AbstractStrategy){
|
||||
throw new TypeError('Cannot construct AbstractStrategy instances directly');
|
||||
@@ -19,7 +19,7 @@ define([], () => {
|
||||
static create(){
|
||||
return new this();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* LIFO Cache Strategy - First In First Out
|
||||
@@ -27,7 +27,7 @@ define([], () => {
|
||||
* without any regard to how often or how many times they were accessed before.
|
||||
* @type {StrategyFIFO}
|
||||
*/
|
||||
let StrategyFIFO = class StrategyFIFO extends AbstractStrategy {
|
||||
class StrategyFIFO extends AbstractStrategy {
|
||||
valueToCompare(metaData){
|
||||
return metaData.age();
|
||||
}
|
||||
@@ -35,7 +35,7 @@ define([], () => {
|
||||
compare(a, b){
|
||||
return b - a;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* LFU Cache Strategy - Least Frequently Used
|
||||
@@ -43,7 +43,7 @@ define([], () => {
|
||||
* Those that are used least often are discarded first
|
||||
* @type {StrategyLFU}
|
||||
*/
|
||||
let StrategyLFU = class StrategyLFU extends AbstractStrategy {
|
||||
class StrategyLFU extends AbstractStrategy {
|
||||
valueToCompare(metaData){
|
||||
return metaData.hitCount;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ define([], () => {
|
||||
compare(a, b){
|
||||
return a - b;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* LRU Cache Strategy - Least Recently Used
|
||||
@@ -59,7 +59,7 @@ define([], () => {
|
||||
* No matter how often they have been accessed.
|
||||
* @type {StrategyLRU}
|
||||
*/
|
||||
let StrategyLRU = class StrategyLRU extends AbstractStrategy {
|
||||
class StrategyLRU extends AbstractStrategy {
|
||||
valueToCompare(metaData){
|
||||
return metaData.hits[metaData.hits.length - 1] || metaData.set;
|
||||
}
|
||||
@@ -67,26 +67,26 @@ define([], () => {
|
||||
compare(a, b){
|
||||
return a - b;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Each entry in cache also has its own instance of CacheEntryMeta
|
||||
* -> The configured Cache Strategy use this meta data for eviction policy
|
||||
* @type {CacheEntryMeta}
|
||||
*/
|
||||
let CacheEntryMeta = class CacheEntryMeta {
|
||||
class CacheEntryMeta {
|
||||
constructor(ttl, tSet){
|
||||
this.ttl = ttl;
|
||||
this.tSet = tSet || this.constructor.now();
|
||||
this.tHits = [];
|
||||
this._ttl = ttl; // ttl < 0 => no expire
|
||||
this._tSet = tSet || this.constructor.now();
|
||||
this._tHits = [];
|
||||
}
|
||||
|
||||
get set(){
|
||||
return this.tSet;
|
||||
return this._tSet;
|
||||
}
|
||||
|
||||
get hits(){
|
||||
return this.tHits;
|
||||
return this._tHits;
|
||||
}
|
||||
|
||||
get hitCount(){
|
||||
@@ -94,15 +94,15 @@ define([], () => {
|
||||
}
|
||||
|
||||
newHit(current){
|
||||
this.tHits.push(current || this.constructor.now());
|
||||
this._tHits.push(current || this.constructor.now());
|
||||
}
|
||||
|
||||
age(current){
|
||||
return (current || this.constructor.now()) - this.tSet;
|
||||
return (current || this.constructor.now()) - this._tSet;
|
||||
}
|
||||
|
||||
expired(current){
|
||||
return this.ttl < this.age(current);
|
||||
return this._ttl < 0 ? false : this._ttl < this.age(current);
|
||||
}
|
||||
|
||||
static now(){
|
||||
@@ -112,7 +112,7 @@ define([], () => {
|
||||
static create(ttl, tSet){
|
||||
return new this(ttl, tSet);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Each instance of Cache represents a key value in memory data store
|
||||
@@ -123,26 +123,18 @@ define([], () => {
|
||||
* if cache reaches maxSize limit, to increase performance.
|
||||
* @type {Cache}
|
||||
*/
|
||||
let Cache = class Cache {
|
||||
class Cache {
|
||||
|
||||
constructor(config){
|
||||
this.config = Object.assign({},{
|
||||
name: 'Default', // custom unique name for identification
|
||||
ttl: 3600, // default ttl for cache entries
|
||||
maxSize: 600, // max cache entries
|
||||
bufferSize: 10, // cache entry count in percent to be removed if maxSize reached
|
||||
strategy: 'FIFO', // cache strategy policy
|
||||
debug: false // debug output in console
|
||||
}, config);
|
||||
|
||||
this.store = new Map();
|
||||
this.metaStore = new WeakMap();
|
||||
this.strategy = this.constructor.setStrategy(this.config.strategy);
|
||||
constructor(config = {}){
|
||||
this._config = Object.assign({}, Cache.defaultConfig, config);
|
||||
this._store = new Map();
|
||||
this._metaStore = new WeakMap();
|
||||
this._strategy = this.constructor.setStrategy(this._config.strategy);
|
||||
|
||||
this.debug = (msg,...data) => {
|
||||
if(this.config.debug){
|
||||
if(this._config.debug){
|
||||
data = (data || []);
|
||||
data.unshift(this.config.name);
|
||||
data.unshift(this._config.name);
|
||||
console.debug('debug: CACHE %o | ' + msg, ...data);
|
||||
}
|
||||
};
|
||||
@@ -151,34 +143,34 @@ define([], () => {
|
||||
}
|
||||
|
||||
get size(){
|
||||
return this.store.size;
|
||||
return this._store.size;
|
||||
}
|
||||
|
||||
isFull(){
|
||||
return this.size>= this.config.maxSize;
|
||||
return this.size>= this._config.maxSize;
|
||||
}
|
||||
|
||||
set(key, value, ttl){
|
||||
if(this.store.has(key)){
|
||||
if(this._store.has(key)){
|
||||
this.debug('SET key %o, UPDATE value %o', key, value);
|
||||
this.store.set(key, value);
|
||||
this._store.set(key, value);
|
||||
}else{
|
||||
this.debug('SET key %o, NEW value %o', key, value);
|
||||
if(this.isFull()){
|
||||
this.debug(' ↪ FULL trim cache…');
|
||||
this.trim(this.trimCount(1));
|
||||
}
|
||||
this.store.set(key, value);
|
||||
this._store.set(key, value);
|
||||
}
|
||||
|
||||
this.metaStore.set(value, CacheEntryMeta.create(ttl || this.config.ttl));
|
||||
this._metaStore.set(value, CacheEntryMeta.create(ttl || this._config.ttl));
|
||||
}
|
||||
|
||||
get(key){
|
||||
if(this.store.has(key)){
|
||||
let value = this.store.get(key);
|
||||
if(this._store.has(key)){
|
||||
let value = this._store.get(key);
|
||||
if(value){
|
||||
let metaData = this.metaStore.get(value);
|
||||
let metaData = this._metaStore.get(value);
|
||||
if(metaData.expired()){
|
||||
this.debug('EXPIRED key %o delete', key);
|
||||
this.delete(key);
|
||||
@@ -199,8 +191,8 @@ define([], () => {
|
||||
keysForTrim(count){
|
||||
let trimKeys = [];
|
||||
let compare = [];
|
||||
for(let [key, value] of this.store){
|
||||
let metaData = this.metaStore.get(value);
|
||||
for(let [key, value] of this._store){
|
||||
let metaData = this._metaStore.get(value);
|
||||
if(metaData.expired()){
|
||||
trimKeys.push(key);
|
||||
if(count === trimKeys.length){
|
||||
@@ -209,14 +201,14 @@ define([], () => {
|
||||
}else{
|
||||
compare.push({
|
||||
key: key,
|
||||
value: this.strategy.valueToCompare(metaData)
|
||||
value: this._strategy.valueToCompare(metaData)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let countLeft = count - trimKeys.length;
|
||||
if(countLeft > 0){
|
||||
compare = compare.sort((a, b) => this.strategy.compare(a.value, b.value));
|
||||
compare = compare.sort((a, b) => this._strategy.compare(a.value, b.value));
|
||||
trimKeys = trimKeys.concat(compare.splice(0, countLeft).map(a => a.key));
|
||||
}
|
||||
|
||||
@@ -224,20 +216,20 @@ define([], () => {
|
||||
}
|
||||
|
||||
keys(){
|
||||
return this.store.keys();
|
||||
return this._store.keys();
|
||||
}
|
||||
|
||||
delete(key){
|
||||
return this.store.delete(key);
|
||||
return this._store.delete(key);
|
||||
}
|
||||
|
||||
clear(){
|
||||
this.store.clear();
|
||||
this._store.clear();
|
||||
}
|
||||
|
||||
trimCount(spaceLeft){
|
||||
let bufferSize = Math.max(Math.round(this.config.maxSize / 100 * this.config.bufferSize), spaceLeft);
|
||||
return Math.min(Math.max(this.size - this.config.maxSize + bufferSize, 0), this.size);
|
||||
let bufferSize = Math.max(Math.round(this._config.maxSize / 100 * this._config.bufferSize), spaceLeft);
|
||||
return Math.min(Math.max(this.size - this._config.maxSize + bufferSize, 0), this.size);
|
||||
}
|
||||
|
||||
trim(count){
|
||||
@@ -253,9 +245,9 @@ define([], () => {
|
||||
|
||||
status(){
|
||||
return {
|
||||
config: this.config,
|
||||
store: this.store,
|
||||
metaStore: this.metaStore
|
||||
config: this._config,
|
||||
store: this._store,
|
||||
metaStore: this._metaStore
|
||||
};
|
||||
}
|
||||
|
||||
@@ -269,6 +261,15 @@ define([], () => {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Cache.defaultConfig = {
|
||||
name: 'Default', // custom unique name for identification
|
||||
ttl: 3600, // default ttl for cache entries
|
||||
maxSize: 600, // max cache entries
|
||||
bufferSize: 10, // cache entry count in percent to be removed if maxSize reached
|
||||
strategy: 'FIFO', // cache strategy policy
|
||||
debug: false // debug output in console
|
||||
};
|
||||
|
||||
return Cache;
|
||||
|
||||
@@ -11,7 +11,7 @@ define([
|
||||
console.info('task1 function():', timer.getTotalTimeValues());
|
||||
return 'OK';
|
||||
};
|
||||
Cron.set(task1);
|
||||
task1.start();
|
||||
|
||||
Example2 run task every 3 seconds ---------------------------------------------------------------------------------
|
||||
let task1 = Cron.new('task1', {precision: 'seconds', interval: 3, timeout: 100});
|
||||
@@ -19,7 +19,7 @@ define([
|
||||
console.info('task1 function():', timer.getTotalTimeValues());
|
||||
return 'OK';
|
||||
};
|
||||
Cron.set(task1);
|
||||
task1.start();
|
||||
|
||||
Example3 resolve Promise on run ----------------------------------------------------------------------------------
|
||||
let task1 = Cron.new('task1', {precision: 'seconds', interval: 1, timeout: 100});
|
||||
@@ -35,14 +35,14 @@ define([
|
||||
});
|
||||
});
|
||||
};
|
||||
Cron.set(task1);
|
||||
task1.start();
|
||||
|
||||
Example4 run task once at given Date() --------------------------------------------------------------------------
|
||||
let dueDate = new Date();
|
||||
dueDate.setSeconds(dueDate.getSeconds() + 5);
|
||||
let task2 = Cron.new('task2', {precision: 'seconds', timeout: 100, dueDate: dueDate});
|
||||
task2.task = () => 'OK task2';
|
||||
Cron.set(task2);
|
||||
task2.start();
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -51,35 +51,42 @@ define([
|
||||
* @type {Task}
|
||||
*/
|
||||
let Task = class Task {
|
||||
constructor(name, config){
|
||||
/**
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {{}} config
|
||||
* @param {CronManager} manager
|
||||
*/
|
||||
constructor(name, config, manager = null){
|
||||
if(typeof name !== 'string'){
|
||||
throw new TypeError('Task "name" must be instance of String, Type of "' + typeof name + '" given');
|
||||
}
|
||||
this._config = Object.assign({}, this.constructor.defaultConfig, config);
|
||||
this._name = name; // unique name for identification
|
||||
this._task = undefined; // task to run, instanceof Function, can also return a Promise
|
||||
this._manager = undefined; // reference to CronManager() that handles this task
|
||||
this._task = (timer, task) => {}; // task to run, instanceof Function, can also return a Promise
|
||||
this._manager = manager; // reference to CronManager() that handles this task
|
||||
this._runCount = 0; // counter for run() calls
|
||||
this._runQueue = new Map(); // current run() processes. > 1 requires config.isParallel: true
|
||||
this._runCount = 0; // total run counter for this task
|
||||
this._lastTotalTimeValues = undefined; // time values of last run()
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
get name(){
|
||||
return this._name;
|
||||
}
|
||||
|
||||
get task(){
|
||||
/**
|
||||
* @returns {(function())} task
|
||||
*/
|
||||
get task() {
|
||||
return this._task;
|
||||
}
|
||||
|
||||
get runCount(){
|
||||
return this._runCount;
|
||||
}
|
||||
|
||||
get precision(){
|
||||
return this._config.precision;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {(function())} task
|
||||
*/
|
||||
set task(task){
|
||||
if(task instanceof Function){
|
||||
this._task = task;
|
||||
@@ -88,34 +95,120 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
get runCount(){
|
||||
return this._runCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
get precision(){
|
||||
return this.get('precision');
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get paused(){
|
||||
return this.get('paused');
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get targetAchieved(){
|
||||
return this.get('targetRunCount') ? this.runCount >= this.get('targetRunCount') : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
get targetProgress(){
|
||||
return parseFloat(
|
||||
parseFloat(
|
||||
(!this.get('targetRunCount') || !this.runCount) ?
|
||||
0 :
|
||||
(100 / this.get('targetRunCount') * this.runCount)
|
||||
).toFixed(2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param option
|
||||
* @returns {*}
|
||||
*/
|
||||
get(option){
|
||||
return this._config[option];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} option
|
||||
* @param {*} value
|
||||
*/
|
||||
set(option, value){
|
||||
this._config[option] = value;
|
||||
}
|
||||
|
||||
setManager(manager){
|
||||
this._manager = manager;
|
||||
/**
|
||||
* connect CronManager with instance
|
||||
* @param {CronManager} manager
|
||||
*/
|
||||
connect(manager = this._manager){
|
||||
if(manager instanceof CronManager){
|
||||
if(manager !== this._manager){
|
||||
// disconnect from current manager (if exists)
|
||||
this.disconnect();
|
||||
this._manager = manager;
|
||||
}
|
||||
this._manager.set(this);
|
||||
}else{
|
||||
throw new TypeError('Parameter must be instance of CronManager. Type of "' + typeof manager + '" given');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* disconnect from CronManager
|
||||
* @param {CronManager} manager
|
||||
*/
|
||||
disconnect(manager = this._manager){
|
||||
if(manager instanceof CronManager){
|
||||
if(this.isConnected(manager)){
|
||||
this._manager.delete(this._name);
|
||||
}
|
||||
}else{
|
||||
throw new TypeError('Parameter must be instance of CronManager. Type of "' + typeof manager + '" given');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if CronManager is connected with instance
|
||||
* @param {CronManager} manager
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isConnected(manager = this._manager){
|
||||
return (manager instanceof CronManager) &&
|
||||
manager === this._manager &&
|
||||
manager.has(this._name);
|
||||
}
|
||||
|
||||
/**
|
||||
* if task is currently running
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isRunning(){
|
||||
return !!this._runQueue.size;
|
||||
}
|
||||
|
||||
delete(){
|
||||
let isDeleted = false;
|
||||
if(this._manager){
|
||||
isDeleted = this._manager.delete(this._name);
|
||||
}
|
||||
return isDeleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timer
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isDue(timer){
|
||||
if(this._config.dueDate instanceof Date){
|
||||
if(this.get('dueDate') instanceof Date){
|
||||
// run once at dueDate
|
||||
if(new Date().getTime() >= this._config.dueDate.getTime()){
|
||||
if(new Date().getTime() >= this.get('dueDate').getTime()){
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
@@ -124,8 +217,8 @@ define([
|
||||
let totalTimeValuePrecision = totalTimeValues[this.precision];
|
||||
totalTimeValuePrecision -= this._lastTotalTimeValues ? this._lastTotalTimeValues[this.precision] : 0;
|
||||
if(
|
||||
this._config.interval === 1 ||
|
||||
totalTimeValuePrecision % this._config.interval === 0
|
||||
this.get('interval') === 1 ||
|
||||
totalTimeValuePrecision % this.get('interval') === 0
|
||||
){
|
||||
return true;
|
||||
}
|
||||
@@ -133,23 +226,30 @@ define([
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timer
|
||||
*/
|
||||
invoke(timer){
|
||||
if(
|
||||
!this.paused &&
|
||||
this.isDue(timer) &&
|
||||
(!this.isRunning() || this._config.isParallel)
|
||||
(!this.isRunning() || this.get('isParallel'))
|
||||
){
|
||||
this.run(timer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param timer
|
||||
*/
|
||||
run(timer){
|
||||
this._lastTotalTimeValues = Object.assign({}, timer.getTotalTimeValues());
|
||||
let runId = 'run_' + (++this._runCount);
|
||||
let runExec = resolve => {
|
||||
resolve(this.task(timer, this));
|
||||
resolve(this._task(timer, this));
|
||||
};
|
||||
|
||||
let myProm = this._config.timeout > 0 ? new TimeoutPromise(runExec, this._config.timeout) : new Promise(runExec);
|
||||
let myProm = this.get('timeout') > 0 ? new TimeoutPromise(runExec, this.get('timeout')) : new Promise(runExec);
|
||||
myProm.then(payload => {
|
||||
// resolved within timeout -> wait for finally() block
|
||||
}).catch(error => {
|
||||
@@ -162,14 +262,37 @@ define([
|
||||
// -> remove from _runQueue
|
||||
this._runQueue.delete(runId);
|
||||
|
||||
// remove this task from store after run
|
||||
if(this._config.dueDate instanceof Date){
|
||||
this.delete();
|
||||
if(this.get('dueDate') instanceof Date){
|
||||
this.disconnect();
|
||||
}
|
||||
|
||||
if(this.targetAchieved){
|
||||
this.stop();
|
||||
}
|
||||
});
|
||||
|
||||
this._runQueue.set(runId, myProm);
|
||||
}
|
||||
|
||||
// Task controls ----------------------------------------------------------------------------------------------
|
||||
|
||||
start(){
|
||||
this.set('paused', false);
|
||||
this.connect();
|
||||
}
|
||||
|
||||
stop(){
|
||||
this.reset();
|
||||
this.disconnect();
|
||||
}
|
||||
|
||||
pause(){
|
||||
this.set('paused', true);
|
||||
}
|
||||
|
||||
reset(){
|
||||
this._runCount = 0;
|
||||
}
|
||||
};
|
||||
|
||||
Task.defaultConfig = {
|
||||
@@ -177,7 +300,9 @@ define([
|
||||
isParallel: false, // if true this task can run parallel, e.g. if prev execution has not finished
|
||||
interval: 1, // relates to 'precision'. 'interval' = 3 and 'precision' = "seconds" -> run every 3 seconds
|
||||
dueDate: undefined, // if Date() instance is set, task only runs once at dueDate
|
||||
timeout: 50 // if > 0, execution time that exceeds timeout (ms) throw error
|
||||
timeout: 50, // if > 0, execution time that exceeds timeout (ms) throw error
|
||||
paused: false, // if true this task will not run() but will be invoce()´ed
|
||||
targetRunCount: 0 // if > 0, task will stop if targetRunCount is reached
|
||||
};
|
||||
|
||||
|
||||
@@ -188,6 +313,9 @@ define([
|
||||
*/
|
||||
let CronManager = class CronManager {
|
||||
|
||||
/**
|
||||
* @param {{}} config
|
||||
*/
|
||||
constructor(config){
|
||||
this._config = Object.assign({}, this.constructor.defaultConfig, config);
|
||||
this._timerConfig = Object.assign({}, this.constructor.defaultTimerConfig);
|
||||
@@ -211,47 +339,75 @@ define([
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {{}} config
|
||||
* @returns {Task}
|
||||
*/
|
||||
new(name, config){
|
||||
return new Task(name, config);
|
||||
return new Task(name, config, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Task} task
|
||||
*/
|
||||
set(task){
|
||||
if(task instanceof Task){
|
||||
// check for unique task name, or update existing task
|
||||
if(!this.has(task.name) || (this.get(task.name) === task)){
|
||||
// set new or update existing task
|
||||
task.setManager(this);
|
||||
// check for unique task name
|
||||
if(!this.has(task.name)){
|
||||
// connect new task
|
||||
// -> must be before connect(this)! (prevents infinite loop)
|
||||
this._tasks.set(task.name, task);
|
||||
task.connect(this);
|
||||
|
||||
this.debug('SET/UPDATE task: %o config: %o', task.name, task);
|
||||
// start timer (if it is not already running)
|
||||
this.auto();
|
||||
}else{
|
||||
console.warn('FAILED to set task. Task name %o already exists', task.name);
|
||||
}
|
||||
}else{
|
||||
throw new TypeError('Parameter must be instance of Task');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {{}} config
|
||||
*/
|
||||
setNew(name, config){
|
||||
this.set(this.new(name, config));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {Task|undefined}
|
||||
*/
|
||||
get(name){
|
||||
return this._tasks.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @returns {boolean}
|
||||
*/
|
||||
has(name){
|
||||
return this._tasks.has(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
delete(name){
|
||||
let isDeleted = this._tasks.delete(name);
|
||||
if(isDeleted){
|
||||
if(this.has(name)){
|
||||
let task = this._tasks.get(name);
|
||||
// disconnect task
|
||||
// -> must be before disconnect(this)! (prevents infinite loop)
|
||||
this._tasks.delete(name);
|
||||
task.disconnect(this);
|
||||
|
||||
this.debug('DELETE task: %o', name);
|
||||
// stop timer (if no more tasks connected)
|
||||
this.auto();
|
||||
}
|
||||
return isDeleted;
|
||||
}
|
||||
|
||||
clear(){
|
||||
@@ -260,6 +416,10 @@ define([
|
||||
this.auto();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} precision
|
||||
* @returns {Task[]}
|
||||
*/
|
||||
tasksByPrecision(precision){
|
||||
let tasks = [];
|
||||
this._tasks.forEach(task => {
|
||||
|
||||
@@ -34,7 +34,7 @@ define([], () => {
|
||||
}
|
||||
|
||||
get(obj, key) {
|
||||
return this._store.has(obj) && this._store.get(obj).get(key);
|
||||
return this._store.has(obj) && (key ? this._store.get(obj).get(key) : this._store.get(obj));
|
||||
}
|
||||
|
||||
has(obj, key) {
|
||||
@@ -45,6 +45,8 @@ define([], () => {
|
||||
let ret = false;
|
||||
if (this._store.has(obj)) {
|
||||
ret = this._store.get(obj).delete(key);
|
||||
// remove obj if store is empty
|
||||
// -> 'size' property is does not exist if valueStore is WeakMap
|
||||
if (!this._store.get(obj).size) {
|
||||
this._store.delete(obj);
|
||||
}
|
||||
|
||||
@@ -193,10 +193,10 @@ define([
|
||||
}
|
||||
|
||||
/**
|
||||
* set LocalStoreManager for this instance
|
||||
* connect LocalStoreManager with instance
|
||||
* @param {LocalStoreManager} manager
|
||||
*/
|
||||
setManager(manager){
|
||||
connect(manager){
|
||||
if(manager instanceof LocalStoreManager){
|
||||
this._manager = manager;
|
||||
}else{
|
||||
@@ -299,7 +299,7 @@ define([
|
||||
/**
|
||||
* check var for Object
|
||||
* @param obj
|
||||
* @returns {boolean|boolean}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
static isObject(obj){
|
||||
return (!!obj) && (obj.constructor === Object);
|
||||
@@ -372,7 +372,7 @@ define([
|
||||
}, {
|
||||
name: LocalStore.buildDbName(name)
|
||||
});
|
||||
store.setManager(this);
|
||||
store.connect(this);
|
||||
this._store.set(name, store);
|
||||
}
|
||||
return this._store.get(name);
|
||||
|
||||
11
public/js/v2.0.0/app/lib/prototypes.js
vendored
11
public/js/v2.0.0/app/lib/prototypes.js
vendored
@@ -103,14 +103,9 @@ define([
|
||||
* @returns {number}
|
||||
*/
|
||||
String.prototype.hashCode = function(){
|
||||
let hash = 0, i, chr;
|
||||
if(this.length === 0) return hash;
|
||||
for(i = 0; i < this.length; i++){
|
||||
chr = this.charCodeAt(i);
|
||||
hash = ((hash << 5) - hash) + chr;
|
||||
hash |= 0; // Convert to 32bit integer
|
||||
}
|
||||
return hash;
|
||||
let hash = this.split('').reduce((a,b) => (((a << 5) - a) + b.charCodeAt(0))|0, 0);
|
||||
// make positive
|
||||
return (hash + 2147483647) + 1;
|
||||
};
|
||||
|
||||
String.prototype.trimLeftChars = function(charList){
|
||||
|
||||
@@ -222,7 +222,7 @@ define([
|
||||
* @param excludeMenu
|
||||
*/
|
||||
let closeMenus = excludeMenu => {
|
||||
let allMenus = $('.' + config.contextMenuClass + '[role="menu"]');
|
||||
let allMenus = $('.' + config.contextMenuClass + '[role="menu"][style*="display: block"]');
|
||||
if(excludeMenu){
|
||||
allMenus = allMenus.not(excludeMenu);
|
||||
}
|
||||
@@ -291,17 +291,15 @@ define([
|
||||
|
||||
/**
|
||||
* default config (skeleton) for valid context menu configuration
|
||||
* @returns {{hidden: Array, active: Array, disabled: Array, id: string, selectCallback: null}}
|
||||
* @returns {{hidden: [], active: [], disabled: [], id: string, selectCallback: null}}
|
||||
*/
|
||||
let defaultMenuOptionConfig = () => {
|
||||
return {
|
||||
'id': '',
|
||||
'selectCallback': null,
|
||||
'hidden': [],
|
||||
'active': [],
|
||||
'disabled': []
|
||||
};
|
||||
};
|
||||
let defaultMenuOptionConfig = () => ({
|
||||
'id': '',
|
||||
'selectCallback': null,
|
||||
'hidden': [],
|
||||
'active': [],
|
||||
'disabled': []
|
||||
});
|
||||
|
||||
return {
|
||||
config: config,
|
||||
|
||||
@@ -29,7 +29,6 @@ define([
|
||||
|
||||
mapIdPrefix: 'pf-map-', // id prefix for all maps
|
||||
systemClass: 'pf-system', // class for all systems
|
||||
systemActiveClass: 'pf-system-active', // class for an active system on a map
|
||||
systemSelectedClass: 'pf-system-selected', // class for selected systems on a map
|
||||
systemHeadClass: 'pf-system-head', // class for system head
|
||||
systemHeadNameClass: 'pf-system-head-name', // class for system name
|
||||
@@ -116,7 +115,7 @@ define([
|
||||
},
|
||||
connectionsDetachable: true, // dragOptions are set -> allow detaching them
|
||||
maxConnections: 10, // due to isTarget is true, this is the max count of !out!-going connections
|
||||
// isSource:true
|
||||
//isSource:true
|
||||
},
|
||||
target: {
|
||||
filter: filterSystemHeadEvent,
|
||||
@@ -125,10 +124,10 @@ define([
|
||||
//allowLoopBack: false, // loopBack connections are not allowed
|
||||
cssClass: config.endpointTargetClass,
|
||||
dropOptions: {
|
||||
hoverClass: config.systemActiveClass,
|
||||
//hoverClass: '',
|
||||
activeClass: 'dragActive'
|
||||
},
|
||||
// uniqueEndpoint: false
|
||||
//uniqueEndpoint: false
|
||||
},
|
||||
endpointTypes: Init.endpointTypes,
|
||||
connectionTypes: Init.connectionTypes
|
||||
@@ -876,23 +875,23 @@ define([
|
||||
* connect two systems
|
||||
* @param map
|
||||
* @param connectionData
|
||||
* @returns new connection
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let drawConnection = (map, connectionData) => {
|
||||
let drawConnection = (map, connectionData) => new Promise((resolve, reject) => {
|
||||
let mapContainer = $(map.getContainer());
|
||||
let mapId = mapContainer.data('id');
|
||||
let connectionId = connectionData.id || 0;
|
||||
let connection;
|
||||
let sourceSystem = $('#' + MapUtil.getSystemId(mapId, connectionData.source));
|
||||
let targetSystem = $('#' + MapUtil.getSystemId(mapId, connectionData.target));
|
||||
|
||||
// check if both systems exists
|
||||
// (If not -> something went wrong e.g. DB-Foreign keys for "ON DELETE",...)
|
||||
if(
|
||||
sourceSystem.length &&
|
||||
targetSystem.length
|
||||
){
|
||||
connection = map.connect({
|
||||
if(!sourceSystem.length){
|
||||
reject(new Error(`drawConnection(): source system (id: ${connectionData.source}) not found`));
|
||||
}else if(!targetSystem.length){
|
||||
reject(new Error(`drawConnection(): target system (id: ${connectionData.target}) not found`));
|
||||
}else{
|
||||
let connection = map.connect({
|
||||
source: sourceSystem[0],
|
||||
target: targetSystem[0],
|
||||
scope: connectionData.scope || map.Defaults.Scope,
|
||||
@@ -948,18 +947,18 @@ define([
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if( !sourceSystem.length ){
|
||||
console.warn('drawConnection(): source system (id: ' + connectionData.source + ') not found');
|
||||
}
|
||||
if( !targetSystem.length ){
|
||||
console.warn('drawConnection(): target system (id: ' + connectionData.target + ') not found');
|
||||
|
||||
resolve({
|
||||
action: 'drawConnection',
|
||||
data: {
|
||||
connection: connection
|
||||
}
|
||||
});
|
||||
}else{
|
||||
reject(new Error(`drawConnection(): connection must be instanceof jsPlumb.Connection`));
|
||||
}
|
||||
}
|
||||
|
||||
return connection;
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* compares the current data and new data of a connection and updates status
|
||||
@@ -1233,168 +1232,178 @@ define([
|
||||
* @param reject
|
||||
*/
|
||||
let updateMapExecutor = (resolve, reject) => {
|
||||
// jsPlumb needs to be initialized. This is not the case when switching between map tabs right after refresh
|
||||
let mapContainer = mapConfig.map ? $(mapConfig.map.getContainer()) : null;
|
||||
if(mapContainer){
|
||||
let mapId = mapConfig.config.id;
|
||||
|
||||
// add additional information for this map
|
||||
if(mapContainer.data('updated') !== mapConfig.config.updated.updated){
|
||||
mapContainer.data('name', mapConfig.config.name);
|
||||
mapContainer.data('scopeId', mapConfig.config.scope.id);
|
||||
mapContainer.data('typeId', mapConfig.config.type.id);
|
||||
mapContainer.data('typeName', mapConfig.config.type.name);
|
||||
mapContainer.data('icon', mapConfig.config.icon);
|
||||
mapContainer.data('created', mapConfig.config.created.created);
|
||||
mapContainer.data('updated', mapConfig.config.updated.updated);
|
||||
}
|
||||
|
||||
// get map data
|
||||
let mapData = getMapDataForSync(mapContainer, [], true);
|
||||
|
||||
|
||||
if(mapData !== false){
|
||||
// map data available -> map not locked by update counter :)
|
||||
let currentSystemData = mapData.data.systems;
|
||||
let currentConnectionData = mapData.data.connections;
|
||||
|
||||
// update systems =================================================================================
|
||||
for(let i = 0; i < mapConfig.data.systems.length; i++){
|
||||
let systemData = mapConfig.data.systems[i];
|
||||
|
||||
// add system
|
||||
let addNewSystem = true;
|
||||
|
||||
for(let 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(let a = 0; a < currentSystemData.length; a++){
|
||||
let deleteThisSystem = true;
|
||||
|
||||
for(let b = 0; b < mapConfig.data.systems.length; b++){
|
||||
let deleteSystemData = mapConfig.data.systems[b];
|
||||
|
||||
if(deleteSystemData.id === currentSystemData[a].id){
|
||||
deleteThisSystem = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(deleteThisSystem === true){
|
||||
let deleteSystem = $('#' + MapUtil.getSystemId(mapContainer.data('id'), currentSystemData[a].id));
|
||||
|
||||
// system not found -> delete system
|
||||
System.removeSystems(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(let j = 0; j < mapConfig.data.connections.length; j++){
|
||||
let connectionData = mapConfig.data.connections[j];
|
||||
|
||||
// add connection
|
||||
let addNewConnection= true;
|
||||
|
||||
for(let 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
|
||||
updateConnection(currentConnectionData[c].connection, connectionData);
|
||||
}
|
||||
|
||||
addNewConnection = false;
|
||||
break;
|
||||
}else if(
|
||||
currentConnectionData[c].id === 0 &&
|
||||
currentConnectionData[c].source === connectionData.source &&
|
||||
currentConnectionData[c].target === connectionData.target
|
||||
){
|
||||
// if ids don´t match -> check for unsaved connection
|
||||
updateConnection(currentConnectionData[c].connection, connectionData);
|
||||
|
||||
addNewConnection = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(addNewConnection === true){
|
||||
drawConnection(mapConfig.map, connectionData);
|
||||
}
|
||||
}
|
||||
|
||||
// check for connections that are gone -> delete connection
|
||||
for(let d = 0; d < currentConnectionData.length; d++){
|
||||
// skip connections with id = 0 -> they might get updated before
|
||||
if(currentConnectionData[d].id === 0){
|
||||
continue;
|
||||
}
|
||||
|
||||
let deleteThisConnection = true;
|
||||
|
||||
for(let e = 0; e < mapConfig.data.connections.length;e++){
|
||||
let deleteConnectionData = mapConfig.data.connections[e];
|
||||
|
||||
if(deleteConnectionData.id === currentConnectionData[d].id){
|
||||
deleteThisConnection = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(deleteThisConnection === true){
|
||||
// connection not found -> delete connection
|
||||
let deleteConnection = currentConnectionData[d].connection;
|
||||
|
||||
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.deleteConnection(deleteConnection, {fireEvent: false});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// update local connection cache
|
||||
updateConnectionsCache(mapConfig.map);
|
||||
}else{
|
||||
// map is currently logged -> queue update for this map until unlock
|
||||
if( mapUpdateQueue.indexOf(mapId) === -1 ){
|
||||
mapUpdateQueue.push(mapId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resolve({
|
||||
let payload = {
|
||||
action: 'updateMap',
|
||||
data: {
|
||||
mapConfig: mapConfig
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// jsPlumb needs to be initialized. This is not the case when switching between map tabs right after refresh
|
||||
let mapContainer = mapConfig.map ? mapConfig.map.getContainer() : null;
|
||||
if(!mapContainer){
|
||||
return resolve(payload);
|
||||
}
|
||||
|
||||
let mapId = mapConfig.config.id;
|
||||
|
||||
// mapData == false -> map locked by update counter. Skip update
|
||||
let mapData = getMapDataForSync(mapContainer, [], true);
|
||||
|
||||
if(!mapData){
|
||||
// map is currently locked -> queue update for this map until unlock
|
||||
if(mapUpdateQueue.indexOf(mapId) === -1){
|
||||
mapUpdateQueue.push(mapId);
|
||||
}
|
||||
return resolve(payload);
|
||||
}
|
||||
|
||||
mapContainer = $(mapContainer);
|
||||
|
||||
// add additional information for this map
|
||||
if(mapContainer.data('updated') !== mapConfig.config.updated.updated){
|
||||
mapContainer.data('name', mapConfig.config.name);
|
||||
mapContainer.data('scopeId', mapConfig.config.scope.id);
|
||||
mapContainer.data('typeId', mapConfig.config.type.id);
|
||||
mapContainer.data('typeName', mapConfig.config.type.name);
|
||||
mapContainer.data('icon', mapConfig.config.icon);
|
||||
mapContainer.data('created', mapConfig.config.created.created);
|
||||
mapContainer.data('updated', mapConfig.config.updated.updated);
|
||||
}
|
||||
|
||||
// map data available -> map not locked by update counter :)
|
||||
let currentSystemData = mapData.data.systems;
|
||||
let currentConnectionData = mapData.data.connections;
|
||||
|
||||
// update systems =========================================================================================
|
||||
for(let i = 0; i < mapConfig.data.systems.length; i++){
|
||||
let systemData = mapConfig.data.systems[i];
|
||||
|
||||
// add system
|
||||
let addNewSystem = true;
|
||||
|
||||
for(let 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).catch(console.warn);
|
||||
}
|
||||
}
|
||||
|
||||
// check for systems that are gone -> delete system
|
||||
for(let a = 0; a < currentSystemData.length; a++){
|
||||
let deleteThisSystem = true;
|
||||
|
||||
for(let b = 0; b < mapConfig.data.systems.length; b++){
|
||||
let deleteSystemData = mapConfig.data.systems[b];
|
||||
|
||||
if(deleteSystemData.id === currentSystemData[a].id){
|
||||
deleteThisSystem = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(deleteThisSystem === true){
|
||||
let deleteSystem = $('#' + MapUtil.getSystemId(mapContainer.data('id'), currentSystemData[a].id));
|
||||
|
||||
// system not found -> delete system
|
||||
System.removeSystems(mapConfig.map, deleteSystem);
|
||||
}
|
||||
}
|
||||
|
||||
// update connections =====================================================================================
|
||||
|
||||
// jsPlumb setSuspendDrawing() (batch() did not work because it async 'scopes' out updates).
|
||||
// -> Otherwise there are some "strange" visual bugs when switching maps (Endpoints are not displayed correctly)
|
||||
// -> needs to be "disabled" later in this method.
|
||||
mapConfig.map.setSuspendDrawing(true);
|
||||
|
||||
for(let j = 0; j < mapConfig.data.connections.length; j++){
|
||||
let connectionData = mapConfig.data.connections[j];
|
||||
|
||||
// add connection
|
||||
let addNewConnection= true;
|
||||
|
||||
for(let 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
|
||||
updateConnection(currentConnectionData[c].connection, connectionData);
|
||||
}
|
||||
|
||||
addNewConnection = false;
|
||||
break;
|
||||
}else if(
|
||||
currentConnectionData[c].id === 0 &&
|
||||
currentConnectionData[c].source === connectionData.source &&
|
||||
currentConnectionData[c].target === connectionData.target
|
||||
){
|
||||
// if ids don´t match -> check for unsaved connection
|
||||
updateConnection(currentConnectionData[c].connection, connectionData);
|
||||
|
||||
addNewConnection = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(addNewConnection === true){
|
||||
drawConnection(mapConfig.map, connectionData).catch(console.warn);
|
||||
}
|
||||
}
|
||||
|
||||
// check for connections that are gone -> delete connection
|
||||
for(let d = 0; d < currentConnectionData.length; d++){
|
||||
// skip connections with id = 0 -> they might get updated before
|
||||
if(currentConnectionData[d].id === 0){
|
||||
continue;
|
||||
}
|
||||
|
||||
let deleteThisConnection = true;
|
||||
|
||||
for(let e = 0; e < mapConfig.data.connections.length;e++){
|
||||
let deleteConnectionData = mapConfig.data.connections[e];
|
||||
|
||||
if(deleteConnectionData.id === currentConnectionData[d].id){
|
||||
deleteThisConnection = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(deleteThisConnection === true){
|
||||
// connection not found -> delete connection
|
||||
let deleteConnection = currentConnectionData[d].connection;
|
||||
|
||||
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.deleteConnection(deleteConnection, {fireEvent: false});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mapConfig.map.setSuspendDrawing(false, true);
|
||||
|
||||
// update local connection cache
|
||||
updateConnectionsCache(mapConfig.map);
|
||||
|
||||
|
||||
|
||||
return resolve(payload);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1402,44 +1411,53 @@ define([
|
||||
* @param payload
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let filterMapByScopes = payload => {
|
||||
let filterMapByScopesExecutor = resolve => {
|
||||
Util.getLocalStore('map').getItem(payload.data.mapConfig.config.id).then(dataStore => {
|
||||
let scopes = [];
|
||||
if(dataStore && dataStore.filterScopes){
|
||||
scopes = dataStore.filterScopes;
|
||||
}
|
||||
|
||||
MapUtil.filterMapByScopes(payload.data.mapConfig.map, scopes);
|
||||
resolve(payload);
|
||||
});
|
||||
};
|
||||
|
||||
return new Promise(filterMapByScopesExecutor);
|
||||
};
|
||||
let filterMapByScopes = payload => new Promise(resolve => {
|
||||
Util.getLocalStore('map').getItem(payload.data.mapConfig.config.id).then(dataStore => {
|
||||
let scopes = [];
|
||||
if(dataStore && dataStore.filterScopes){
|
||||
scopes = dataStore.filterScopes;
|
||||
}
|
||||
MapUtil.filterMapByScopes(payload.data.mapConfig.map, scopes);
|
||||
resolve(payload);
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* show signature overlays
|
||||
* @param payload
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let showInfoSignatureOverlays = payload => {
|
||||
let showInfoSignatureOverlaysExecutor = resolve => {
|
||||
Util.getLocalStore('map').getItem(payload.data.mapConfig.config.id).then(dataStore => {
|
||||
if(dataStore && dataStore.mapSignatureOverlays){
|
||||
MapOverlay.showInfoSignatureOverlays($(payload.data.mapConfig.map.getContainer()));
|
||||
}
|
||||
let showInfoSignatureOverlays = payload => new Promise(resolve => {
|
||||
Util.getLocalStore('map').getItem(payload.data.mapConfig.config.id).then(dataStore => {
|
||||
if(dataStore && dataStore.mapSignatureOverlays){
|
||||
MapOverlay.showInfoSignatureOverlays($(payload.data.mapConfig.map.getContainer()));
|
||||
}
|
||||
resolve(payload);
|
||||
});
|
||||
});
|
||||
|
||||
resolve(payload);
|
||||
/**
|
||||
* after map update is complete
|
||||
* -> trigger update event for 'global' modules
|
||||
* @param payload
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let afterUpdate = payload => new Promise(resolve => {
|
||||
// in rare cases there is a bug where map is undefined (hard to reproduce
|
||||
let map = Util.getObjVal(payload, 'data.mapConfig.map');
|
||||
if(map){
|
||||
let tabContentEl = map.getContainer().closest(`.${Util.config.mapTabContentClass}`);
|
||||
$(tabContentEl).trigger('pf:updateGlobalModules', {
|
||||
payload: Util.getObjVal(payload, 'data.mapConfig.config.id')
|
||||
});
|
||||
};
|
||||
|
||||
return new Promise(showInfoSignatureOverlaysExecutor);
|
||||
};
|
||||
}
|
||||
resolve(payload);
|
||||
});
|
||||
|
||||
return new Promise(updateMapExecutor)
|
||||
.then(showInfoSignatureOverlays)
|
||||
.then(filterMapByScopes);
|
||||
.then(filterMapByScopes)
|
||||
.then(afterUpdate);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1530,28 +1548,22 @@ define([
|
||||
* @param systemData
|
||||
* @returns {boolean}
|
||||
*/
|
||||
let isValidSystem = systemData => {
|
||||
let isValid = true;
|
||||
if(
|
||||
!systemData.hasOwnProperty('name') ||
|
||||
systemData.name.length === 0
|
||||
){
|
||||
return false;
|
||||
}
|
||||
|
||||
return isValid;
|
||||
};
|
||||
let isValidSystem = systemData => (Util.getObjVal(systemData, 'name') || '').length > 0;
|
||||
|
||||
/**
|
||||
* draw a system with its data to a map
|
||||
* @param map
|
||||
* @param systemData
|
||||
* @param connectedSystem
|
||||
* @param connectionData
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let drawSystem = (map, systemData, connectedSystem) => {
|
||||
|
||||
// check if systemData is valid
|
||||
let drawSystem = (map, systemData, connectedSystem, connectionData = null) => new Promise((resolve, reject) => {
|
||||
if(isValidSystem(systemData)){
|
||||
let payloadDrawSystem = {
|
||||
action: 'drawSystem'
|
||||
};
|
||||
|
||||
let mapContainer = $(map.getContainer());
|
||||
|
||||
// get System Element by data
|
||||
@@ -1575,24 +1587,37 @@ define([
|
||||
// register system to "magnetizer"
|
||||
Magnetizer.addElement(systemData.mapId, newSystem[0]);
|
||||
|
||||
payloadDrawSystem.data = {
|
||||
system: newSystem
|
||||
};
|
||||
|
||||
// connect new system (if connection data is given)
|
||||
if(connectedSystem){
|
||||
|
||||
// hint: "scope + type" might be changed automatically when it gets saved
|
||||
// -> based on jump distance,..
|
||||
let connectionData = {
|
||||
connectionData = Object.assign({}, {
|
||||
source: $(connectedSystem).data('id'),
|
||||
target: newSystem.data('id'),
|
||||
scope: map.Defaults.Scope,
|
||||
type: [MapUtil.getDefaultConnectionTypeByScope(map.Defaults.Scope)]
|
||||
};
|
||||
let connection = drawConnection(map, connectionData);
|
||||
}, connectionData);
|
||||
|
||||
// store connection
|
||||
saveConnection(connection);
|
||||
drawConnection(map, connectionData)
|
||||
.then(payload => saveConnection(payload.data.connection, Boolean(connectionData.disableAutoScope)))
|
||||
.then(payload => {
|
||||
payloadDrawSystem.data = {
|
||||
connection: payload.data.connection
|
||||
};
|
||||
resolve(payloadDrawSystem);
|
||||
})
|
||||
.catch(reject);
|
||||
}else{
|
||||
resolve(payloadDrawSystem);
|
||||
}
|
||||
}else{
|
||||
reject(new Error(`drawSystem() failed. Invalid systemData`));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* make a system name/alias editable by x-editable
|
||||
@@ -1656,56 +1681,69 @@ define([
|
||||
/**
|
||||
* stores a connection in database
|
||||
* @param connection
|
||||
* @param disableAutoScope
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let saveConnection = connection => {
|
||||
if(connection instanceof jsPlumb.Connection){
|
||||
connection.addType('state_process');
|
||||
|
||||
let map = connection._jsPlumb.instance;
|
||||
let mapContainer = $(map.getContainer());
|
||||
let mapId = mapContainer.data('id');
|
||||
|
||||
let connectionData = MapUtil.getDataByConnection(connection);
|
||||
connectionData.mapId = mapId;
|
||||
|
||||
Util.request('PUT', 'connection', [], connectionData, {
|
||||
connection: connection,
|
||||
map: map,
|
||||
mapId: mapId,
|
||||
oldConnectionData: connectionData
|
||||
}).then(
|
||||
payload => {
|
||||
let newConnectionData = payload.data;
|
||||
|
||||
if(!$.isEmptyObject(newConnectionData)){
|
||||
// update connection data e.g. "scope" has auto detected
|
||||
connection = updateConnection(payload.context.connection, newConnectionData);
|
||||
|
||||
// new/updated connection should be cached immediately!
|
||||
updateConnectionCache(payload.context.mapId, connection);
|
||||
|
||||
// connection scope
|
||||
let scope = MapUtil.getScopeInfoForConnection(newConnectionData.scope, 'label');
|
||||
|
||||
let title = 'New connection established';
|
||||
if(payload.context.oldConnectionData.id > 0){
|
||||
title = 'Connection switched';
|
||||
}
|
||||
|
||||
Util.showNotify({title: title, text: 'Scope: ' + scope, type: 'success'});
|
||||
}else{
|
||||
// some save errors
|
||||
payload.context.map.deleteConnection(payload.context.connection, {fireEvent: false});
|
||||
}
|
||||
},
|
||||
payload => {
|
||||
// remove this connection from map
|
||||
payload.context.map.deleteConnection(payload.context.connection, {fireEvent: false});
|
||||
Util.handleAjaxErrorResponse(payload);
|
||||
}
|
||||
);
|
||||
let saveConnection = (connection, disableAutoScope = false) => new Promise((resolve, reject) => {
|
||||
if(!(connection instanceof jsPlumb.Connection)){
|
||||
reject(new Error(`saveConnection(): connection must be instanceof jsPlumb.Connection`));
|
||||
}
|
||||
};
|
||||
|
||||
connection.addType('state_process');
|
||||
|
||||
let map = connection._jsPlumb.instance;
|
||||
let mapContainer = $(map.getContainer());
|
||||
let mapId = mapContainer.data('id');
|
||||
|
||||
let connectionData = MapUtil.getDataByConnection(connection);
|
||||
connectionData.mapId = mapId;
|
||||
connectionData.disableAutoScope = disableAutoScope;
|
||||
|
||||
Util.request('PUT', 'connection', [], connectionData, {
|
||||
connection: connection,
|
||||
map: map,
|
||||
mapId: mapId,
|
||||
oldConnectionData: connectionData
|
||||
}).then(
|
||||
payload => {
|
||||
let newConnectionData = payload.data;
|
||||
|
||||
if(!$.isEmptyObject(newConnectionData)){
|
||||
// update connection data e.g. "scope" has auto detected
|
||||
connection = updateConnection(payload.context.connection, newConnectionData);
|
||||
|
||||
// new/updated connection should be cached immediately!
|
||||
updateConnectionCache(payload.context.mapId, connection);
|
||||
|
||||
// connection scope
|
||||
let scope = MapUtil.getScopeInfoForConnection(newConnectionData.scope, 'label');
|
||||
|
||||
let title = 'New connection established';
|
||||
if(payload.context.oldConnectionData.id > 0){
|
||||
title = 'Connection switched';
|
||||
}
|
||||
|
||||
Util.showNotify({title: title, text: 'Scope: ' + scope, type: 'success'});
|
||||
resolve({
|
||||
action: 'saveConnection',
|
||||
data: {
|
||||
connection: connection
|
||||
}
|
||||
});
|
||||
}else{
|
||||
// some save errors
|
||||
payload.context.map.deleteConnection(payload.context.connection, {fireEvent: false});
|
||||
reject(new Error(`saveConnection(): response error`));
|
||||
}
|
||||
},
|
||||
payload => {
|
||||
// remove this connection from map
|
||||
payload.context.map.deleteConnection(payload.context.connection, {fireEvent: false});
|
||||
Util.handleAjaxErrorResponse(payload);
|
||||
reject(new Error(`saveConnection(): request error`));
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* get context menu config for a map component (e.g. system, connection,..)
|
||||
@@ -1742,7 +1780,7 @@ define([
|
||||
options.hidden.push('delete_system');
|
||||
}
|
||||
|
||||
if( !mapContainer.find('.' + config.systemActiveClass).length){
|
||||
if( !mapContainer.find('.' + MapUtil.config.systemActiveClass).length){
|
||||
options.hidden.push('find_route');
|
||||
}
|
||||
|
||||
@@ -1755,7 +1793,7 @@ define([
|
||||
}
|
||||
|
||||
// disabled menu actions
|
||||
if(system.hasClass(config.systemActiveClass)){
|
||||
if(system.hasClass(MapUtil.config.systemActiveClass)){
|
||||
options.disabled.push('find_route');
|
||||
}
|
||||
|
||||
@@ -1898,6 +1936,8 @@ define([
|
||||
// map overlay will be set on "drag" start
|
||||
let mapOverlayTimer = null;
|
||||
|
||||
let debounceDrag = false;
|
||||
|
||||
// make system draggable
|
||||
map.draggable(system, {
|
||||
containment: 'parent',
|
||||
@@ -1907,7 +1947,7 @@ define([
|
||||
snapThreshold: MapUtil.config.mapSnapToGridDimension, // distance for grid snapping "magnet" effect (optional)
|
||||
start: function(params){
|
||||
let dragSystem = $(params.el);
|
||||
|
||||
dragSystem.css('pointer-events','none');
|
||||
mapOverlayTimer = MapOverlayUtil.getMapOverlay(dragSystem, 'timer');
|
||||
|
||||
// start map update timer
|
||||
@@ -1920,9 +1960,6 @@ define([
|
||||
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
|
||||
let selectedSystems = mapContainer.getSelectedSystems().get();
|
||||
selectedSystems = selectedSystems.concat(dragSystem.get());
|
||||
@@ -1938,12 +1975,19 @@ define([
|
||||
$(selectedSystems).updateSystemZIndex();
|
||||
},
|
||||
drag: function(p){
|
||||
// start map update timer
|
||||
mapOverlayTimer.startMapUpdateCounter();
|
||||
if(!debounceDrag) {
|
||||
requestAnimationFrame(() => {
|
||||
// start map update timer
|
||||
mapOverlayTimer.startMapUpdateCounter();
|
||||
|
||||
// update system positions for "all" systems that are effected by drag&drop
|
||||
// this requires "magnet" feature to be active! (optional)
|
||||
Magnetizer.executeAtEvent(map, p.e);
|
||||
// update system positions for "all" systems that are effected by drag&drop
|
||||
// this requires "magnet" feature to be active! (optional)
|
||||
Magnetizer.executeAtEvent(map, p.e);
|
||||
|
||||
debounceDrag = false;
|
||||
});
|
||||
}
|
||||
debounceDrag = true;
|
||||
},
|
||||
stop: function(params){
|
||||
let dragSystem = $(params.el);
|
||||
@@ -1951,10 +1995,6 @@ define([
|
||||
// start map update timer
|
||||
mapOverlayTimer.startMapUpdateCounter();
|
||||
|
||||
setTimeout(function(){
|
||||
dragSystem.removeClass('no-click');
|
||||
}, Init.timer.DBL_CLICK + 50);
|
||||
|
||||
// show tooltip
|
||||
dragSystem.toggleSystemTooltip('show', {show: true});
|
||||
|
||||
@@ -1975,7 +2015,7 @@ define([
|
||||
|
||||
// update all dragged systems -> added to DragSelection
|
||||
params.selection.forEach(elData => {
|
||||
MapUtil.markAsChanged($(elData[0]));
|
||||
MapUtil.markAsChanged($(elData[0]).css('pointer-events','initial'));
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -2016,23 +2056,20 @@ define([
|
||||
if(!popoverClick){
|
||||
let system = $(this);
|
||||
|
||||
// check if system is locked for "click" events
|
||||
if(!system.hasClass('no-click')){
|
||||
// left mouse button
|
||||
if(e.which === 1){
|
||||
if(e.ctrlKey === true){
|
||||
// select system
|
||||
MapUtil.toggleSystemsSelect(map, [system]);
|
||||
}else{
|
||||
MapUtil.showSystemInfo(map, system);
|
||||
}
|
||||
// left mouse button
|
||||
if(e.which === 1){
|
||||
if(e.ctrlKey === true){
|
||||
// select system
|
||||
MapUtil.toggleSystemsSelect(map, [system]);
|
||||
}else{
|
||||
MapUtil.showSystemInfo(map, system);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Util.singleDoubleClick(system, single, double);
|
||||
Util.singleDoubleClick(system[0], single, double);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -2040,10 +2077,10 @@ define([
|
||||
* @param map
|
||||
* @param newSystemData
|
||||
* @param sourceSystem
|
||||
* @param connectionData
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let saveSystemCallback = (map, newSystemData, sourceSystem) => {
|
||||
drawSystem(map, newSystemData, sourceSystem);
|
||||
};
|
||||
let saveSystemCallback = (map, newSystemData, sourceSystem, connectionData = null) => drawSystem(map, newSystemData, sourceSystem, connectionData);
|
||||
|
||||
/**
|
||||
* select all (selectable) systems on a mapElement
|
||||
@@ -2193,17 +2230,8 @@ define([
|
||||
return false;
|
||||
}
|
||||
|
||||
// lock the target system for "click" events
|
||||
// to prevent loading system information
|
||||
let sourceSystem = $('#' + sourceId);
|
||||
let targetSystem = $('#' + targetId);
|
||||
sourceSystem.addClass('no-click');
|
||||
targetSystem.addClass('no-click');
|
||||
|
||||
setTimeout(() => {
|
||||
sourceSystem.removeClass('no-click');
|
||||
targetSystem.removeClass('no-click');
|
||||
}, Init.timer.DBL_CLICK + 50);
|
||||
|
||||
// switch connection type to "abyss" in case source OR target system belongs to "a-space"
|
||||
if(sourceSystem.data('typeId') === 3 || targetSystem.data('typeId') === 3){
|
||||
@@ -2227,7 +2255,7 @@ define([
|
||||
}
|
||||
|
||||
// always save the new connection
|
||||
saveConnection(connection);
|
||||
saveConnection(connection).catch(console.warn);
|
||||
|
||||
return true;
|
||||
});
|
||||
@@ -2721,7 +2749,7 @@ define([
|
||||
selectSystem(mapContainer, data);
|
||||
break;
|
||||
case 'AddSystem':
|
||||
System.showNewSystemDialog(map, data, saveSystemCallback);
|
||||
System.showNewSystemDialog(map, data, typeof data.callback === 'function' ? data.callback : saveSystemCallback);
|
||||
break;
|
||||
default:
|
||||
console.warn('Unknown menuAction %o event name', action);
|
||||
@@ -2938,16 +2966,16 @@ define([
|
||||
|
||||
/**
|
||||
* collect all map data from client for server or client sync
|
||||
* @param mapContainer
|
||||
* @param {HTMLElement} mapContainer
|
||||
* @param filter
|
||||
* @param minimal
|
||||
* @returns {boolean}
|
||||
* @returns {boolean|{}}
|
||||
*/
|
||||
let getMapDataForSync = (mapContainer, filter = [], minimal = false) => {
|
||||
let mapData = false;
|
||||
// check if there is an active map counter that prevents collecting map data (locked map)
|
||||
if(!MapOverlayUtil.getMapOverlayInterval(mapContainer)){
|
||||
mapData = mapContainer.getMapDataFromClient(filter, minimal);
|
||||
if(!MapOverlayUtil.isMapCounterOverlayActive(mapContainer)){
|
||||
mapData = $(mapContainer).getMapDataFromClient(filter, minimal);
|
||||
}
|
||||
return mapData;
|
||||
};
|
||||
@@ -2957,6 +2985,7 @@ define([
|
||||
* this function returns the "client" data NOT the "server" data for a map
|
||||
* @param filter
|
||||
* @param minimal
|
||||
* @returns {{}}
|
||||
*/
|
||||
$.fn.getMapDataFromClient = function(filter = [], minimal = false){
|
||||
let mapContainer = $(this);
|
||||
@@ -3099,34 +3128,29 @@ define([
|
||||
* @param options
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let initMapOptions = (mapConfig, options) => {
|
||||
|
||||
let initMapOptionsExecutor = (resolve, reject) => {
|
||||
let payload = {
|
||||
action: 'initMapOptions',
|
||||
data: {
|
||||
mapConfig: mapConfig
|
||||
}
|
||||
};
|
||||
|
||||
if(options.showAnimation){
|
||||
let mapElement = $(mapConfig.map.getContainer());
|
||||
MapUtil.setMapDefaultOptions(mapElement, mapConfig.config)
|
||||
.then(payload => MapUtil.visualizeMap(mapElement, 'show'))
|
||||
.then(payload => MapUtil.zoomToDefaultScale(mapConfig.map))
|
||||
.then(payload => MapUtil.scrollToDefaultPosition(mapConfig.map))
|
||||
.then(payload => {
|
||||
Util.showNotify({title: 'Map initialized', text: mapConfig.config.name + ' - loaded', type: 'success'});
|
||||
})
|
||||
.then(() => resolve(payload));
|
||||
}else{
|
||||
// nothing to do here...
|
||||
resolve(payload);
|
||||
let initMapOptions = (mapConfig, options) => new Promise((resolve, reject) => {
|
||||
let payload = {
|
||||
action: 'initMapOptions',
|
||||
data: {
|
||||
mapConfig: mapConfig
|
||||
}
|
||||
};
|
||||
|
||||
return new Promise(initMapOptionsExecutor);
|
||||
};
|
||||
if(options.showAnimation){
|
||||
let mapElement = $(mapConfig.map.getContainer());
|
||||
MapUtil.setMapDefaultOptions(mapElement, mapConfig.config)
|
||||
.then(payload => MapUtil.visualizeMap(mapElement, 'show'))
|
||||
.then(payload => MapUtil.zoomToDefaultScale(mapConfig.map))
|
||||
.then(payload => MapUtil.scrollToDefaultPosition(mapConfig.map))
|
||||
.then(payload => {
|
||||
Util.showNotify({title: 'Map initialized', text: mapConfig.config.name + ' - loaded', type: 'success'});
|
||||
})
|
||||
.then(() => resolve(payload));
|
||||
}else{
|
||||
// nothing to do here...
|
||||
resolve(payload);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* load OR updates system map
|
||||
@@ -3136,6 +3160,9 @@ define([
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let loadMap = (areaMap, mapConfig, options) => {
|
||||
// whether map gets loaded (initialized) for the first time
|
||||
// or just updated an existing map
|
||||
let isFirstLoad = false;
|
||||
|
||||
/**
|
||||
* load map promise
|
||||
@@ -3150,6 +3177,7 @@ define([
|
||||
|
||||
if(mapConfig.map.getContainer() === undefined){
|
||||
// map not loaded -> create & update
|
||||
isFirstLoad = true;
|
||||
newMapElement(areaMap, mapConfig)
|
||||
.then(payload => updateMap(payload.data.mapConfig))
|
||||
.then(payload => resolve(payload));
|
||||
@@ -3162,7 +3190,12 @@ define([
|
||||
};
|
||||
|
||||
return new Promise(loadMapExecutor)
|
||||
.then(payload => initMapOptions(payload.data.mapConfig, options));
|
||||
.then(payload => initMapOptions(payload.data.mapConfig, options))
|
||||
.then(payload => ({
|
||||
action: 'loadMap',
|
||||
data: payload.data,
|
||||
isFirstLoad
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -3330,7 +3363,9 @@ define([
|
||||
loadMap: loadMap,
|
||||
updateUserData: updateUserData,
|
||||
getMapDataForSync: getMapDataForSync,
|
||||
saveSystemCallback: saveSystemCallback
|
||||
saveSystemCallback: saveSystemCallback,
|
||||
drawConnection: drawConnection,
|
||||
saveConnection: saveConnection
|
||||
};
|
||||
|
||||
});
|
||||
@@ -7,8 +7,9 @@ define([
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/map/overlay/util',
|
||||
'app/map/util'
|
||||
], ($, Init, Util, MapOverlayUtil, MapUtil) => {
|
||||
'app/map/util',
|
||||
'app/lib/cron'
|
||||
], ($, Init, Util, MapOverlayUtil, MapUtil, Cron) => {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
@@ -107,119 +108,120 @@ define([
|
||||
let type = 'info_signature';
|
||||
connectionsData = Util.arrayToObject(connectionsData);
|
||||
|
||||
map.batch(() => {
|
||||
map.getAllConnections().forEach(connection => {
|
||||
let connectionId = connection.getParameter('connectionId');
|
||||
let sourceEndpoint = connection.endpoints[0];
|
||||
let targetEndpoint = connection.endpoints[1];
|
||||
map.setSuspendDrawing(true);
|
||||
|
||||
let connectionData = connectionsData.hasOwnProperty(connectionId) ? connectionsData[connectionId] : undefined;
|
||||
let signatureTypeData = MapUtil.getConnectionDataFromSignatures(connection, connectionData);
|
||||
map.getAllConnections().forEach(connection => {
|
||||
let connectionId = connection.getParameter('connectionId');
|
||||
let sourceEndpoint = connection.endpoints[0];
|
||||
let targetEndpoint = connection.endpoints[1];
|
||||
|
||||
let sizeLockedBySignature = false;
|
||||
let connectionData = Util.getObjVal(connectionsData, `${connectionId}`);
|
||||
let signatureTypeData = MapUtil.getConnectionDataFromSignatures(connection, connectionData);
|
||||
|
||||
if(connection.scope === 'wh'){
|
||||
if(!connection.hasType(type)){
|
||||
connection.addType(type);
|
||||
}
|
||||
let sizeLockedBySignature = false;
|
||||
|
||||
let overlayArrow = connection.getOverlay(MapOverlayUtil.config.connectionOverlayArrowId);
|
||||
if(connection.scope === 'wh'){
|
||||
if(!connection.hasType(type)){
|
||||
connection.addType(type);
|
||||
}
|
||||
|
||||
// Arrow overlay needs to be cleared() (removed) if 'info_signature' gets removed!
|
||||
// jsPlumb does not handle overlay updates for Arrow overlays... so we need to re-apply the the overlay manually
|
||||
if(overlayArrow.path && !overlayArrow.path.isConnected){
|
||||
connection.canvas.appendChild(overlayArrow.path);
|
||||
}
|
||||
let overlayArrow = connection.getOverlay(MapOverlayUtil.config.connectionOverlayArrowId);
|
||||
|
||||
// since there "could" be multiple sig labels on each endpoint,
|
||||
// there can only one "primary label picked up for wormhole jump mass detection!
|
||||
let primLabel;
|
||||
// Arrow overlay needs to be cleared() (removed) if 'info_signature' gets removed!
|
||||
// jsPlumb does not handle overlay updates for Arrow overlays... so we need to re-apply the the overlay manually
|
||||
if(overlayArrow.path && !overlayArrow.path.isConnected){
|
||||
connection.canvas.appendChild(overlayArrow.path);
|
||||
}
|
||||
|
||||
let overlayType = 'diamond'; // not specified
|
||||
let arrowDirection = 1;
|
||||
// since there "could" be multiple sig labels on each endpoint,
|
||||
// there can only one "primary label picked up for wormhole jump mass detection!
|
||||
let primeLabel;
|
||||
|
||||
if(connectionData && connectionData.signatures){
|
||||
// signature data found for current connection
|
||||
let sourceLabel = signatureTypeData.source.labels;
|
||||
let targetLabel = signatureTypeData.target.labels;
|
||||
let overlayType = 'diamond'; // not specified
|
||||
let arrowDirection = 1;
|
||||
|
||||
// add arrow (connection) overlay that points from "XXX" => "K162" ----------------------------
|
||||
if(
|
||||
(sourceLabel.includes('K162') && targetLabel.includes('K162')) ||
|
||||
(sourceLabel.length === 0 && targetLabel.length === 0) ||
|
||||
(
|
||||
sourceLabel.length > 0 && targetLabel.length > 0 &&
|
||||
!sourceLabel.includes('K162') && !targetLabel.includes('K162')
|
||||
)
|
||||
){
|
||||
// unknown direction -> show default 'diamond' overlay
|
||||
overlayType = 'diamond';
|
||||
}else if(
|
||||
(sourceLabel.includes('K162')) ||
|
||||
(sourceLabel.length === 0 && !targetLabel.includes('K162'))
|
||||
){
|
||||
// convert default arrow direction
|
||||
overlayType = 'arrow';
|
||||
arrowDirection = -1;
|
||||
if(connectionData && connectionData.signatures){
|
||||
// signature data found for current connection
|
||||
let sourceLabel = signatureTypeData.source.labels;
|
||||
let targetLabel = signatureTypeData.target.labels;
|
||||
|
||||
primLabel = targetLabel.find(label => label !== 'K162');
|
||||
}else{
|
||||
// default arrow direction is fine
|
||||
overlayType = 'arrow';
|
||||
// add arrow (connection) overlay that points from "XXX" => "K162" ----------------------------
|
||||
if(
|
||||
(sourceLabel.includes('K162') && targetLabel.includes('K162')) ||
|
||||
(sourceLabel.length === 0 && targetLabel.length === 0) ||
|
||||
(
|
||||
sourceLabel.length > 0 && targetLabel.length > 0 &&
|
||||
!sourceLabel.includes('K162') && !targetLabel.includes('K162')
|
||||
)
|
||||
){
|
||||
// unknown direction -> show default 'diamond' overlay
|
||||
overlayType = 'diamond';
|
||||
}else if(
|
||||
(sourceLabel.includes('K162')) ||
|
||||
(sourceLabel.length === 0 && !targetLabel.includes('K162'))
|
||||
){
|
||||
// convert default arrow direction
|
||||
overlayType = 'arrow';
|
||||
arrowDirection = -1;
|
||||
|
||||
primLabel = sourceLabel.find(label => label !== 'K162');
|
||||
}
|
||||
}
|
||||
|
||||
// class changes must be done on "connection" itself not on "overlayArrow"
|
||||
// -> because Arrow might not be rendered to map at this point (if it does not exist already)
|
||||
if(overlayType === 'arrow'){
|
||||
connection.updateClasses(
|
||||
MapOverlayUtil.config.connectionArrowOverlaySuccessClass,
|
||||
MapOverlayUtil.config.connectionArrowOverlayDangerClass
|
||||
);
|
||||
primeLabel = targetLabel.find(label => label !== 'K162');
|
||||
}else{
|
||||
connection.updateClasses(
|
||||
MapOverlayUtil.config.connectionArrowOverlayDangerClass,
|
||||
MapOverlayUtil.config.connectionArrowOverlaySuccessClass
|
||||
);
|
||||
}
|
||||
// default arrow direction is fine
|
||||
overlayType = 'arrow';
|
||||
|
||||
overlayArrow.updateFrom(getConnectionArrowOverlayParams(overlayType, arrowDirection));
|
||||
|
||||
// update/add endpoint overlays -------------------------------------------------------------------
|
||||
updateEndpointOverlaySignatureLabel(sourceEndpoint, signatureTypeData.source);
|
||||
updateEndpointOverlaySignatureLabel(targetEndpoint, signatureTypeData.target);
|
||||
|
||||
// fix/overwrite existing jump mass connection type -----------------------------------------------
|
||||
// if a connection type for "jump mass" (e.g. S, M, L, XL) is set for this connection
|
||||
// we should check/compare it with the current primary signature label from signature mapping
|
||||
// and change it if necessary
|
||||
if(Init.wormholes.hasOwnProperty(primLabel)){
|
||||
// connection size from mapped signature
|
||||
sizeLockedBySignature = true;
|
||||
|
||||
let wormholeData = Object.assign({}, Init.wormholes[primLabel]);
|
||||
// get 'connection mass type' from wormholeData
|
||||
let massType = Util.getObjVal(wormholeData, 'size.type');
|
||||
|
||||
if(massType && !connection.hasType(massType)){
|
||||
MapOverlayUtil.getMapOverlay(connection.canvas, 'timer').startMapUpdateCounter();
|
||||
MapUtil.setConnectionJumpMassType(connection, wormholeData.size.type);
|
||||
MapUtil.markAsChanged(connection);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// connection is not 'wh' scope
|
||||
if(connection.hasType(type)){
|
||||
connection.removeType(type);
|
||||
primeLabel = sourceLabel.find(label => label !== 'K162');
|
||||
}
|
||||
}
|
||||
|
||||
// lock/unlock connection for manual size changes (from contextmenu)
|
||||
connection.setParameter('sizeLocked', sizeLockedBySignature);
|
||||
});
|
||||
// class changes must be done on "connection" itself not on "overlayArrow"
|
||||
// -> because Arrow might not be rendered to map at this point (if it does not exist already)
|
||||
if(overlayType === 'arrow'){
|
||||
connection.updateClasses(
|
||||
MapOverlayUtil.config.connectionArrowOverlaySuccessClass,
|
||||
MapOverlayUtil.config.connectionArrowOverlayDangerClass
|
||||
);
|
||||
}else{
|
||||
connection.updateClasses(
|
||||
MapOverlayUtil.config.connectionArrowOverlayDangerClass,
|
||||
MapOverlayUtil.config.connectionArrowOverlaySuccessClass
|
||||
);
|
||||
}
|
||||
|
||||
overlayArrow.updateFrom(getConnectionArrowOverlayParams(overlayType, arrowDirection));
|
||||
|
||||
// update/add endpoint overlays -------------------------------------------------------------------
|
||||
updateEndpointOverlaySignatureLabel(sourceEndpoint, signatureTypeData.source);
|
||||
updateEndpointOverlaySignatureLabel(targetEndpoint, signatureTypeData.target);
|
||||
|
||||
// fix/overwrite existing jump mass connection type -----------------------------------------------
|
||||
// if a connection type for "jump mass" (e.g. S, M, L, XL) is set for this connection
|
||||
// we should check/compare it with the current primary signature label from signature mapping
|
||||
// and change it if necessary
|
||||
if(Init.wormholes.hasOwnProperty(primeLabel)){
|
||||
// connection size from mapped signature
|
||||
sizeLockedBySignature = true;
|
||||
|
||||
// get 'connection mass type' from wormholeData
|
||||
let massType = Util.getObjVal(Object.assign({}, Init.wormholes[primeLabel]), 'size.type');
|
||||
|
||||
if(massType && !connection.hasType(massType)){
|
||||
MapOverlayUtil.getMapOverlay(connection.canvas, 'timer').startMapUpdateCounter();
|
||||
MapUtil.setConnectionJumpMassType(connection, massType);
|
||||
MapUtil.markAsChanged(connection);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// connection is not 'wh' scope
|
||||
if(connection.hasType(type)){
|
||||
connection.removeType(type);
|
||||
}
|
||||
}
|
||||
|
||||
// lock/unlock connection for manual size changes (from contextmenu)
|
||||
connection.setParameter('sizeLocked', sizeLockedBySignature);
|
||||
});
|
||||
|
||||
map.setSuspendDrawing(false, true);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -291,21 +293,23 @@ define([
|
||||
let map = MapUtil.getMapInstance(mapId);
|
||||
let type = 'info_signature';
|
||||
|
||||
map.batch(() => {
|
||||
map.getAllConnections().forEach(connection => {
|
||||
let overlayArrow = connection.getOverlay(MapOverlayUtil.config.connectionOverlayArrowId);
|
||||
map.setSuspendDrawing(true);
|
||||
|
||||
if(overlayArrow){
|
||||
overlayArrow.cleanup();
|
||||
}
|
||||
map.getAllConnections().forEach(connection => {
|
||||
let overlayArrow = connection.getOverlay(MapOverlayUtil.config.connectionOverlayArrowId);
|
||||
|
||||
if(connection.hasType(type)){
|
||||
connection.removeType(type, {}, true);
|
||||
}
|
||||
});
|
||||
if(overlayArrow){
|
||||
overlayArrow.cleanup();
|
||||
}
|
||||
|
||||
map.selectEndpoints().removeOverlay(MapOverlayUtil.config.endpointOverlayId);
|
||||
if(connection.hasType(type)){
|
||||
connection.removeType(type, {}, true);
|
||||
}
|
||||
});
|
||||
|
||||
map.selectEndpoints().removeOverlay(MapOverlayUtil.config.endpointOverlayId);
|
||||
|
||||
map.setSuspendDrawing(false, true);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -321,7 +325,7 @@ define([
|
||||
trigger: 'active',
|
||||
class: 'pf-map-overlay-filter',
|
||||
iconClass: ['fas', 'fa-fw', 'fa-filter'],
|
||||
onClick: function(e){
|
||||
onClick: function(e){
|
||||
// clear all filter
|
||||
let mapElement = MapOverlayUtil.getMapElementFromOverlay(this);
|
||||
let map = getMapObjectFromOverlayIcon(this);
|
||||
@@ -484,108 +488,96 @@ define([
|
||||
* @param mapOverlayTimer
|
||||
* @param percent
|
||||
* @param value
|
||||
* @returns {*}
|
||||
*/
|
||||
let setMapUpdateCounter = (mapOverlayTimer, percent, value) => {
|
||||
let setMapUpdateCounter = (mapOverlayTimer, percent, value = '') => {
|
||||
// check if counter already exists
|
||||
let counterChart = MapOverlayUtil.getMapCounter(mapOverlayTimer);
|
||||
|
||||
if(counterChart.length === 0){
|
||||
if(!MapOverlayUtil.getMapCounter(mapOverlayTimer)){
|
||||
// create new counter
|
||||
let chartEl = Object.assign(document.createElement('div'), {
|
||||
className: `${Init.classes.pieChart.class} ${Init.classes.pieChart.pieChartMapCounterClass}`
|
||||
});
|
||||
|
||||
counterChart = $('<div>', {
|
||||
class: [Init.classes.pieChart.class, Init.classes.pieChart.pieChartMapCounterClass].join(' ')
|
||||
}).attr('data-percent', percent).append(
|
||||
$('<span>', {
|
||||
text: value
|
||||
})
|
||||
);
|
||||
let chartInnerEl = Object.assign(document.createElement('span'), {
|
||||
textContent: value
|
||||
});
|
||||
let iconEl = Object.assign(document.createElement('i'), {
|
||||
className: ['fas', 'fa-fw', 'fa-lock'].join(' ')
|
||||
});
|
||||
|
||||
mapOverlayTimer.append(counterChart);
|
||||
chartInnerEl.append(iconEl);
|
||||
chartEl.append(chartInnerEl);
|
||||
mapOverlayTimer.append(chartEl);
|
||||
|
||||
// init counter
|
||||
counterChart.initMapUpdateCounter();
|
||||
$(chartEl).initMapUpdateCounter();
|
||||
|
||||
// set tooltip
|
||||
mapOverlayTimer.attr('data-placement', 'left');
|
||||
mapOverlayTimer.attr('title', 'update counter');
|
||||
mapOverlayTimer.tooltip();
|
||||
mapOverlayTimer.dataset.placement = 'left';
|
||||
mapOverlayTimer.setAttribute('title', 'update counter');
|
||||
$(mapOverlayTimer).tooltip();
|
||||
}
|
||||
|
||||
return counterChart;
|
||||
};
|
||||
|
||||
/**
|
||||
* start the map update counter or reset
|
||||
*/
|
||||
$.fn.startMapUpdateCounter = function(){
|
||||
let mapOverlayTimer = $(this);
|
||||
let counterChart = MapOverlayUtil.getMapCounter(mapOverlayTimer);
|
||||
|
||||
let maxSeconds = MapOverlayUtil.config.logTimerCount;
|
||||
|
||||
let counterChartLabel = counterChart.find('span');
|
||||
|
||||
let percentPerCount = 100 / maxSeconds;
|
||||
|
||||
// update counter
|
||||
let updateChart = tempSeconds => {
|
||||
let pieChart = counterChart.data('easyPieChart');
|
||||
|
||||
if(pieChart !== undefined){
|
||||
counterChart.data('easyPieChart').update( percentPerCount * tempSeconds);
|
||||
}
|
||||
counterChartLabel.text(tempSeconds);
|
||||
};
|
||||
|
||||
// main timer function is called on any counter update
|
||||
let timer = mapUpdateCounter => {
|
||||
// decrease timer
|
||||
let currentSeconds = counterChart.data('currentSeconds');
|
||||
currentSeconds--;
|
||||
counterChart.data('currentSeconds', currentSeconds);
|
||||
|
||||
if(currentSeconds >= 0){
|
||||
// update counter
|
||||
updateChart(currentSeconds);
|
||||
}else{
|
||||
// hide counter and reset
|
||||
clearInterval(mapUpdateCounter);
|
||||
|
||||
mapOverlayTimer.velocity('transition.whirlOut', {
|
||||
duration: Init.animationSpeed.mapOverlay,
|
||||
complete: function(){
|
||||
counterChart.data('interval', false);
|
||||
MapOverlayUtil.getMapElementFromOverlay(mapOverlayTimer).trigger('pf:unlocked');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// get current seconds (in case the timer is already running)
|
||||
let currentSeconds = counterChart.data('currentSeconds');
|
||||
|
||||
// start values for timer and chart
|
||||
counterChart.data('currentSeconds', maxSeconds);
|
||||
updateChart(maxSeconds);
|
||||
|
||||
if(
|
||||
currentSeconds === undefined ||
|
||||
currentSeconds < 0
|
||||
){
|
||||
// start timer
|
||||
let mapUpdateCounter = setInterval(() => {
|
||||
timer(mapUpdateCounter);
|
||||
}, 1000);
|
||||
|
||||
// store counter interval
|
||||
counterChart.data('interval', mapUpdateCounter);
|
||||
|
||||
// show overlay
|
||||
if(mapOverlayTimer.is(':hidden')){
|
||||
mapOverlayTimer.velocity('stop').velocity('transition.whirlIn', { duration: Init.animationSpeed.mapOverlay });
|
||||
}
|
||||
if(!this.length){
|
||||
console.warn('startMapUpdateCounter() failed. Missing DOM node');
|
||||
return;
|
||||
}
|
||||
let mapOverlayTimer = this[0];
|
||||
let counterChart = MapOverlayUtil.getMapCounter(mapOverlayTimer);
|
||||
let pieChart = $(counterChart).data('easyPieChart');
|
||||
|
||||
if(!pieChart){
|
||||
console.warn('startMapUpdateCounter() failed. easyPieChart not initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
let updateChart = (percent = 0) => {
|
||||
if(pieChart){
|
||||
pieChart.update(percent);
|
||||
}
|
||||
};
|
||||
|
||||
let task = counterChart.getData('counterTask');
|
||||
if(!task){
|
||||
let tabContentEl = mapOverlayTimer.closest(`.${Util.config.mapTabContentClass}`);
|
||||
let mapId = parseInt(tabContentEl.dataset.mapId) || 0;
|
||||
task = Cron.new(`mapUpdateCounter_${mapId}`, {
|
||||
precision: 'secondTenths',
|
||||
isParallel: true,
|
||||
targetRunCount: 10 * MapOverlayUtil.config.logTimerCount
|
||||
});
|
||||
|
||||
task.task = (timer, task) => {
|
||||
// debounce 80% (reduce repaint)
|
||||
if(task.runCount % 5 === 0){
|
||||
let progress = Math.round(task.targetProgress);
|
||||
updateChart(100 - progress);
|
||||
}
|
||||
|
||||
if(task.targetAchieved){
|
||||
$(mapOverlayTimer).velocity('transition.whirlOut', {
|
||||
duration: Init.animationSpeed.mapOverlay,
|
||||
complete: function(){
|
||||
MapOverlayUtil.getMapElementFromOverlay(mapOverlayTimer).trigger('pf:unlocked');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
counterChart.setData('counterTask', task);
|
||||
}
|
||||
|
||||
// task is not connected if: 'targetAchieved' or not started
|
||||
if(!task.isConnected()){
|
||||
$(mapOverlayTimer).velocity('stop').velocity('transition.whirlIn', { duration: Init.animationSpeed.mapOverlay });
|
||||
}
|
||||
updateChart(100);
|
||||
task.reset();
|
||||
task.start();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -836,36 +828,35 @@ define([
|
||||
});
|
||||
|
||||
// add all overlay elements
|
||||
for(let prop in options){
|
||||
if(options.hasOwnProperty(prop)){
|
||||
let icon = $('<i>', {
|
||||
class: options[prop].iconClass.concat( ['pull-right', options[prop].class] ).join(' ')
|
||||
}).attr('title', options[prop].title).tooltip({
|
||||
placement: 'bottom',
|
||||
container: 'body',
|
||||
delay: 150
|
||||
});
|
||||
Object.entries(options).forEach(([key, option]) => {
|
||||
let icon = $('<i>', {
|
||||
class: option.iconClass.concat(['pull-right', option.class]).join(' ')
|
||||
}).attr('title', option.title).tooltip({
|
||||
placement: 'bottom',
|
||||
container: 'body',
|
||||
delay: 150
|
||||
});
|
||||
|
||||
// add "hover" action for some icons
|
||||
if(
|
||||
options[prop].trigger === 'hover' ||
|
||||
options[prop].trigger === 'refresh'
|
||||
){
|
||||
icon.hoverIntent(options[prop].hoverIntent);
|
||||
}
|
||||
|
||||
// add "click" handler for some icons
|
||||
if(options[prop].hasOwnProperty('onClick')){
|
||||
icon.on('click', options[prop].onClick);
|
||||
}
|
||||
|
||||
mapOverlayInfo.append(icon);
|
||||
// add "hover" action for some icons
|
||||
if(
|
||||
option.trigger === 'hover' ||
|
||||
option.trigger === 'refresh'
|
||||
){
|
||||
icon.hoverIntent(option.hoverIntent);
|
||||
}
|
||||
}
|
||||
|
||||
// add "click" handler for some icons
|
||||
if(option.hasOwnProperty('onClick')){
|
||||
icon.on('click', option.onClick);
|
||||
}
|
||||
|
||||
mapOverlayInfo.append(icon);
|
||||
});
|
||||
|
||||
parentElement.append(mapOverlayInfo);
|
||||
|
||||
// reset map update timer
|
||||
setMapUpdateCounter(mapOverlayTimer, 100, MapOverlayUtil.config.logTimerCount);
|
||||
setMapUpdateCounter(mapOverlayTimer[0], 100);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -84,22 +84,32 @@ define([
|
||||
/**
|
||||
* get the map counter chart from overlay
|
||||
* @param element
|
||||
* @returns {jQuery}
|
||||
* @returns {Element}
|
||||
*/
|
||||
let getMapCounter = element => $(element).find('.' + Init.classes.pieChart.pieChartMapCounterClass);
|
||||
let getMapCounter = element => element.querySelector(`.${Init.classes.pieChart.pieChartMapCounterClass}`);
|
||||
|
||||
/**
|
||||
* get interval value from map timer overlay
|
||||
* @param element
|
||||
* @returns {*}
|
||||
* if there is an "active" (connected) counter task
|
||||
* -> lock overlay
|
||||
* @param {HTMLElement} element
|
||||
* @returns {boolean}
|
||||
*/
|
||||
let getMapOverlayInterval = element => getMapCounter(getMapOverlay(element, 'timer')).data('interval');
|
||||
let isMapCounterOverlayActive = element => {
|
||||
let mapOverlay = getMapOverlay(element, 'timer');
|
||||
if(mapOverlay){
|
||||
let mapCounter = getMapCounter(mapOverlay[0]);
|
||||
if(mapCounter && mapCounter.getData('counterTask')){
|
||||
return mapCounter.getData('counterTask').isConnected();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
return {
|
||||
config: config,
|
||||
getMapOverlay: getMapOverlay,
|
||||
getMapElementFromOverlay: getMapElementFromOverlay,
|
||||
getMapCounter: getMapCounter,
|
||||
getMapOverlayInterval: getMapOverlayInterval
|
||||
isMapCounterOverlayActive: isMapCounterOverlayActive
|
||||
};
|
||||
});
|
||||
@@ -23,7 +23,6 @@ define([
|
||||
systemHeadInfoLeftClass: 'pf-system-head-info-left', // class for left system info
|
||||
systemHeadInfoRightClass: 'pf-system-head-info-right', // class for right system info
|
||||
|
||||
systemActiveClass: 'pf-system-active', // class for an active system on a map
|
||||
systemTooltipInnerIdPrefix: 'pf-system-tooltip-inner-', // id prefix for system tooltip content
|
||||
systemTooltipInnerClass: 'pf-system-tooltip-inner', // class for system tooltip content
|
||||
|
||||
@@ -231,24 +230,26 @@ define([
|
||||
if(formValid === false) return false;
|
||||
|
||||
// calculate new system position ----------------------------------------------------------
|
||||
let newPosition = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
let newPosition;
|
||||
|
||||
// add new position
|
||||
let sourceSystem = null;
|
||||
let connectionData = null;
|
||||
if(options.sourceSystem !== undefined){
|
||||
// new position based on sourceSystem´s position
|
||||
sourceSystem = options.sourceSystem;
|
||||
connectionData = options.connectionData || null;
|
||||
|
||||
// get new position
|
||||
newPosition = newSystemPositionBySystem(sourceSystem);
|
||||
}else if(options.position){
|
||||
// check mouse cursor position (add system to map)
|
||||
// new position based on coordinated (e.g. mouse event)
|
||||
newPosition = {
|
||||
x: options.position.x,
|
||||
y: options.position.y
|
||||
};
|
||||
}else{
|
||||
// new position based on current map scroll offset
|
||||
newPosition = MapUtil.newSystemPositionsByMapOffset(mapContainer)[0];
|
||||
}
|
||||
|
||||
formData.position = newPosition;
|
||||
@@ -262,7 +263,8 @@ define([
|
||||
systemDialog: systemDialog,
|
||||
formElement: form,
|
||||
map: map,
|
||||
sourceSystem: sourceSystem
|
||||
sourceSystem: sourceSystem,
|
||||
connectionData: connectionData
|
||||
}, context => {
|
||||
// always do
|
||||
context.systemDialog.find('.modal-content').hideLoadingAnimation();
|
||||
@@ -270,7 +272,7 @@ define([
|
||||
payload => {
|
||||
Util.showNotify({title: 'New system', text: payload.data.name, type: 'success'});
|
||||
|
||||
callback(payload.context.map, payload.data, payload.context.sourceSystem);
|
||||
callback(payload.context.map, payload.data, payload.context.sourceSystem, payload.context.connectionData);
|
||||
bootbox.hideAll();
|
||||
},
|
||||
Util.handleAjaxErrorResponse
|
||||
@@ -699,10 +701,12 @@ define([
|
||||
|
||||
for(let system of systems){
|
||||
system = $(system);
|
||||
let mapId = parseInt(system.data('mapid')) || 0;
|
||||
|
||||
// check if system is "active"
|
||||
if(system.hasClass(config.systemActiveClass)){
|
||||
delete Init.currentSystemData;
|
||||
if(system.hasClass(MapUtil.config.systemActiveClass)){
|
||||
Util.deleteCurrentSystemData(mapId);
|
||||
|
||||
// get parent Tab Content and fire clear modules event
|
||||
let tabContentElement = MapUtil.getTabContentElementByMapElement(system);
|
||||
$(tabContentElement).trigger('pf:removeSystemModules');
|
||||
@@ -712,7 +716,7 @@ define([
|
||||
map.deleteConnectionsForElement(system, {fireEvent: false});
|
||||
|
||||
// unregister from "magnetizer"
|
||||
Magnetizer.removeElement(system.data('mapid'), system[0]);
|
||||
Magnetizer.removeElement(mapId, system[0]);
|
||||
|
||||
// destroy tooltip/popover
|
||||
system.toggleSystemTooltip('destroy', {});
|
||||
|
||||
@@ -186,25 +186,50 @@ define([
|
||||
* @param mapData
|
||||
* @param value
|
||||
* @param key
|
||||
* @returns {any}
|
||||
* @returns {{}|boolean}
|
||||
*/
|
||||
let getSystemDataFromMapData = (mapData, value, key = 'id') => {
|
||||
return mapData ? mapData.data.systems.find(system => system[key] === value) || false : false;
|
||||
return (Util.getObjVal(mapData, `data.systems`) || [])
|
||||
.find(systemData => systemData[key] === value) || false;
|
||||
};
|
||||
|
||||
/**
|
||||
* get system data by mapId system data selector
|
||||
* get system data by mapId + system data selector
|
||||
* -> e.g. value = 2 and key = 'id'
|
||||
* -> e.g. value = 30002187 and key = 'systemId' => looks for 'Amarr' CCP systemId
|
||||
* @param mapId
|
||||
* @param value
|
||||
* @param key
|
||||
* @returns {any}
|
||||
* @returns {{}|boolean}
|
||||
*/
|
||||
let getSystemData = (mapId, value, key = 'id') => {
|
||||
return getSystemDataFromMapData(Util.getCurrentMapData(mapId), value, key);
|
||||
};
|
||||
|
||||
/**
|
||||
* get connection data from mapData
|
||||
* @see getConnectionData
|
||||
* @param mapData
|
||||
* @param value
|
||||
* @param key
|
||||
* @returns {{}|boolean}
|
||||
*/
|
||||
let getConnectionDataFromMapData = (mapData, value, key = 'id') => {
|
||||
return (Util.getObjVal(mapData, `data.connections`) || [])
|
||||
.find(connectionData => connectionData[key] === value) || false;
|
||||
};
|
||||
|
||||
/**
|
||||
* get connection data by mapId + connection data selector
|
||||
* @param mapId
|
||||
* @param value
|
||||
* @param key
|
||||
* @returns {{}|boolean}
|
||||
*/
|
||||
let getConnectionData = (mapId, value, key = 'id') => {
|
||||
return getConnectionDataFromMapData(Util.getCurrentMapData(mapId), value, key);
|
||||
};
|
||||
|
||||
/**
|
||||
* get system type information
|
||||
* @param {number} systemTypeId
|
||||
@@ -212,14 +237,7 @@ define([
|
||||
* @returns {string}
|
||||
*/
|
||||
let getSystemTypeInfo = (systemTypeId, option) => {
|
||||
let systemTypeInfo = '';
|
||||
$.each(Init.systemType, function(prop, data){
|
||||
if(systemTypeId === data.id){
|
||||
systemTypeInfo = data[option];
|
||||
return;
|
||||
}
|
||||
});
|
||||
return systemTypeInfo;
|
||||
return (Object.values(Init.systemType).find(data => data.id === systemTypeId) || {})[option] || '';
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -229,11 +247,7 @@ define([
|
||||
* @returns {string}
|
||||
*/
|
||||
let getEffectInfoForSystem = (effect, option) => {
|
||||
let effectInfo = '';
|
||||
if( Init.classes.systemEffects.hasOwnProperty(effect) ){
|
||||
effectInfo = Init.classes.systemEffects[effect][option];
|
||||
}
|
||||
return effectInfo;
|
||||
return Util.getObjVal(Init.classes.systemEffects, `${effect}.${option}`) || '';
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -478,13 +492,16 @@ define([
|
||||
let getConnectionDataFromSignatures = (connection, connectionData) => {
|
||||
let signatureTypeData = {
|
||||
source: {
|
||||
ids: [],
|
||||
names: [],
|
||||
labels: []
|
||||
},
|
||||
target: {
|
||||
ids: [],
|
||||
names: [],
|
||||
labels: []
|
||||
}
|
||||
},
|
||||
hash: false // unique hash key build from all relevant signature for connection
|
||||
};
|
||||
|
||||
if(
|
||||
@@ -501,41 +518,50 @@ define([
|
||||
let sourceId = sourceSystem.data('id');
|
||||
let targetId = targetSystem.data('id');
|
||||
|
||||
// in case connection is currently "dragged" between systems, sourceId and/or targetId is undefined
|
||||
if(!sourceId || !targetId){
|
||||
return signatureTypeData;
|
||||
}
|
||||
|
||||
let hash = [];
|
||||
// ... collect overlay/label data from signatures
|
||||
for(let signatureData of connectionData.signatures){
|
||||
// ... typeId is required to get a valid name
|
||||
if(signatureData.typeId > 0){
|
||||
hash.push(Util.getObjVal(signatureData, 'updated.updated'));
|
||||
|
||||
// whether "source" or "target" system is relevant for current connection and current signature...
|
||||
let tmpSystem = null;
|
||||
let tmpSystemType = null;
|
||||
// whether "source" or "target" system is relevant for current connection and current signature...
|
||||
let tmpSystem = null;
|
||||
let tmpSystemType = null;
|
||||
|
||||
if(signatureData.system.id === sourceId){
|
||||
// relates to "source" endpoint
|
||||
tmpSystemType = 'source';
|
||||
tmpSystem = sourceSystem;
|
||||
}else if(signatureData.system.id === targetId){
|
||||
// relates to "target" endpoint
|
||||
tmpSystemType = 'target';
|
||||
tmpSystem = targetSystem;
|
||||
}
|
||||
if(signatureData.system.id === sourceId){
|
||||
// relates to "source" endpoint
|
||||
tmpSystemType = 'source';
|
||||
tmpSystem = sourceSystem;
|
||||
}else if(signatureData.system.id === targetId){
|
||||
// relates to "target" endpoint
|
||||
tmpSystemType = 'target';
|
||||
tmpSystem = targetSystem;
|
||||
}
|
||||
|
||||
// ... get endpoint label for source || target system
|
||||
if(tmpSystem && tmpSystem){
|
||||
// ... get all available signature type (wormholes) names
|
||||
let availableSigTypeNames = SystemSignatureModule.getSignatureTypeOptionsBySystem(tmpSystem, 5);
|
||||
let flattenSigTypeNames = Util.flattenXEditableSelectArray(availableSigTypeNames);
|
||||
signatureTypeData[tmpSystemType].ids.push(signatureData.id);
|
||||
signatureTypeData[tmpSystemType].names.push(signatureData.name.toUpperCase());
|
||||
|
||||
if(flattenSigTypeNames.hasOwnProperty(signatureData.typeId)){
|
||||
let label = flattenSigTypeNames[signatureData.typeId];
|
||||
// shorten label, just take the ingame name
|
||||
label = label.substr(0, label.indexOf(' '));
|
||||
signatureTypeData[tmpSystemType].names.push(signatureData.name);
|
||||
signatureTypeData[tmpSystemType].labels.push(label);
|
||||
}
|
||||
// ... typeId is required to get a valid labels
|
||||
// ... get endpoint label for source || target system
|
||||
if(signatureData.typeId > 0 && tmpSystem && tmpSystem){
|
||||
// ... get all available signature type (wormholes) names
|
||||
let availableSigTypeNames = SystemSignatureModule.getSignatureTypeOptionsBySystem(tmpSystem, 5);
|
||||
let flattenSigTypeNames = Util.flattenXEditableSelectArray(availableSigTypeNames);
|
||||
|
||||
if(flattenSigTypeNames.hasOwnProperty(signatureData.typeId)){
|
||||
let label = flattenSigTypeNames[signatureData.typeId];
|
||||
// shorten label, just take the ingame name
|
||||
label = label.substr(0, label.indexOf(' '));
|
||||
signatureTypeData[tmpSystemType].labels.push(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
// ... build unique hash
|
||||
signatureTypeData.hash = hash.join().hashCode();
|
||||
}
|
||||
|
||||
return signatureTypeData;
|
||||
@@ -621,64 +647,66 @@ define([
|
||||
*/
|
||||
let filterMapByScopes = (map, scopes) => {
|
||||
if(map){
|
||||
map.batch(() => {
|
||||
let mapElement = $(map.getContainer());
|
||||
let allSystems = mapElement.getSystems();
|
||||
let allConnections = map.getAllConnections();
|
||||
map.setSuspendDrawing(true);
|
||||
|
||||
if(scopes && scopes.length){
|
||||
// filter connections -------------------------------------------------------------------------------------
|
||||
let visibleSystems = [];
|
||||
let visibleConnections = searchConnectionsByScopeAndType(map, scopes);
|
||||
let mapElement = $(map.getContainer());
|
||||
let allSystems = mapElement.getSystems();
|
||||
let allConnections = map.getAllConnections();
|
||||
|
||||
for(let connection of allConnections){
|
||||
if(visibleConnections.indexOf(connection) >= 0){
|
||||
setConnectionVisible(connection, true);
|
||||
// source/target system should always be visible -> even if filter scope not matches system type
|
||||
if(visibleSystems.indexOf(connection.endpoints[0].element) < 0){
|
||||
visibleSystems.push(connection.endpoints[0].element);
|
||||
}
|
||||
if(visibleSystems.indexOf(connection.endpoints[1].element) < 0){
|
||||
visibleSystems.push(connection.endpoints[1].element);
|
||||
}
|
||||
}else{
|
||||
setConnectionVisible(connection, false);
|
||||
}
|
||||
}
|
||||
if(scopes && scopes.length){
|
||||
// filter connections -------------------------------------------------------------------------------------
|
||||
let visibleSystems = [];
|
||||
let visibleConnections = searchConnectionsByScopeAndType(map, scopes);
|
||||
|
||||
// filter systems -----------------------------------------------------------------------------------------
|
||||
let visibleTypeIds = [];
|
||||
if(scopes.indexOf('wh') >= 0){
|
||||
visibleTypeIds.push(1);
|
||||
}
|
||||
if(scopes.indexOf('abyssal') >= 0){
|
||||
visibleTypeIds.push(4);
|
||||
}
|
||||
|
||||
for(let system of allSystems){
|
||||
if(
|
||||
visibleTypeIds.indexOf($(system).data('typeId')) >= 0 ||
|
||||
visibleSystems.indexOf(system) >= 0
|
||||
){
|
||||
setSystemVisible(system, map, true);
|
||||
}else{
|
||||
setSystemVisible(system, map, false);
|
||||
}
|
||||
}
|
||||
|
||||
MapOverlayUtil.getMapOverlay(mapElement, 'info').updateOverlayIcon('filter', 'show');
|
||||
}else{
|
||||
// clear filter
|
||||
for(let system of allSystems){
|
||||
setSystemVisible(system, map, true);
|
||||
}
|
||||
for(let connection of allConnections){
|
||||
for(let connection of allConnections){
|
||||
if(visibleConnections.indexOf(connection) >= 0){
|
||||
setConnectionVisible(connection, true);
|
||||
// source/target system should always be visible -> even if filter scope not matches system type
|
||||
if(visibleSystems.indexOf(connection.endpoints[0].element) < 0){
|
||||
visibleSystems.push(connection.endpoints[0].element);
|
||||
}
|
||||
if(visibleSystems.indexOf(connection.endpoints[1].element) < 0){
|
||||
visibleSystems.push(connection.endpoints[1].element);
|
||||
}
|
||||
}else{
|
||||
setConnectionVisible(connection, false);
|
||||
}
|
||||
|
||||
MapOverlayUtil.getMapOverlay(mapElement, 'info').updateOverlayIcon('filter', 'hide');
|
||||
}
|
||||
});
|
||||
|
||||
// filter systems -----------------------------------------------------------------------------------------
|
||||
let visibleTypeIds = [];
|
||||
if(scopes.indexOf('wh') >= 0){
|
||||
visibleTypeIds.push(1);
|
||||
}
|
||||
if(scopes.indexOf('abyssal') >= 0){
|
||||
visibleTypeIds.push(4);
|
||||
}
|
||||
|
||||
for(let system of allSystems){
|
||||
if(
|
||||
visibleTypeIds.indexOf($(system).data('typeId')) >= 0 ||
|
||||
visibleSystems.indexOf(system) >= 0
|
||||
){
|
||||
setSystemVisible(system, map, true);
|
||||
}else{
|
||||
setSystemVisible(system, map, false);
|
||||
}
|
||||
}
|
||||
|
||||
MapOverlayUtil.getMapOverlay(mapElement, 'info').updateOverlayIcon('filter', 'show');
|
||||
}else{
|
||||
// clear filter
|
||||
for(let system of allSystems){
|
||||
setSystemVisible(system, map, true);
|
||||
}
|
||||
for(let connection of allConnections){
|
||||
setConnectionVisible(connection, true);
|
||||
}
|
||||
|
||||
MapOverlayUtil.getMapOverlay(mapElement, 'info').updateOverlayIcon('filter', 'hide');
|
||||
}
|
||||
|
||||
map.setSuspendDrawing(false, true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -792,17 +820,19 @@ define([
|
||||
*/
|
||||
let setSystemActive = (map, system) => {
|
||||
// deselect all selected systems on map
|
||||
let mapContainer = $( map.getContainer() );
|
||||
mapContainer.find('.' + config.systemClass).removeClass(config.systemActiveClass);
|
||||
let mapContainer = map.getContainer();
|
||||
[...mapContainer.getElementsByClassName(config.systemClass)]
|
||||
.forEach(systemEl =>
|
||||
systemEl.classList.remove(config.systemActiveClass)
|
||||
);
|
||||
|
||||
// set current system active
|
||||
system.addClass(config.systemActiveClass);
|
||||
|
||||
// collect all required data from map module to update the info element
|
||||
// store them global and assessable for each module
|
||||
// collect all required systemData from map module -> cache
|
||||
let systemData = system.getSystemData();
|
||||
systemData.mapId = parseInt(system.attr('data-mapid')) || 0;
|
||||
Util.setCurrentSystemData(systemData);
|
||||
Util.setCurrentSystemData(systemData.mapId, systemData);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -913,20 +943,22 @@ define([
|
||||
* @param connections
|
||||
*/
|
||||
let setConnectionsActive = (map, connections) => {
|
||||
map.batch(() => {
|
||||
// set all inactive
|
||||
for(let connection of getConnectionsByType(map, 'state_active')){
|
||||
if(!connections.includes(connection)){
|
||||
removeConnectionType(connection, 'state_active');
|
||||
}
|
||||
}
|
||||
map.setSuspendDrawing(true);
|
||||
|
||||
for(let connection of connections){
|
||||
if(!connection.hasType('state_active')){
|
||||
addConnectionType(connection, 'state_active');
|
||||
}
|
||||
// set all inactive
|
||||
for(let connection of getConnectionsByType(map, 'state_active')){
|
||||
if(!connections.includes(connection)){
|
||||
removeConnectionType(connection, 'state_active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for(let connection of connections){
|
||||
if(!connection.hasType('state_active')){
|
||||
addConnectionType(connection, 'state_active');
|
||||
}
|
||||
}
|
||||
|
||||
map.setSuspendDrawing(false, true);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -969,21 +1001,38 @@ define([
|
||||
let toggleConnectionActive = (map, connections) => {
|
||||
let selectedConnections = [];
|
||||
let deselectedConnections = [];
|
||||
map.batch(() => {
|
||||
for(let connection of connections){
|
||||
if(connection.hasType('state_active')){
|
||||
removeConnectionType(connection, 'state_active');
|
||||
deselectedConnections.push(connection);
|
||||
}else{
|
||||
addConnectionType(connection, 'state_active');
|
||||
selectedConnections.push(connection);
|
||||
}
|
||||
|
||||
map.setSuspendDrawing(true);
|
||||
|
||||
for(let connection of connections){
|
||||
if(connection.hasType('state_active')){
|
||||
removeConnectionType(connection, 'state_active');
|
||||
deselectedConnections.push(connection);
|
||||
}else{
|
||||
addConnectionType(connection, 'state_active');
|
||||
selectedConnections.push(connection);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
map.setSuspendDrawing(false, true);
|
||||
|
||||
updateConnectionInfo(map, selectedConnections, deselectedConnections);
|
||||
};
|
||||
|
||||
/**
|
||||
* show global map info panels
|
||||
* @param map
|
||||
*/
|
||||
let showMapInfo = map => {
|
||||
// get parent Tab Content and fire update event
|
||||
let mapContainer = $(map.getContainer());
|
||||
|
||||
getTabContentElementByMapElement(mapContainer).trigger('pf:renderGlobalModules', {
|
||||
mapId: parseInt(mapContainer.data('id')),
|
||||
payload: null
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* show system info panels
|
||||
* @param map
|
||||
@@ -994,10 +1043,11 @@ define([
|
||||
|
||||
// get parent Tab Content and fire update event
|
||||
let mapContainer = $(map.getContainer());
|
||||
let mapId = parseInt(mapContainer.data('id')) || 0;
|
||||
|
||||
getTabContentElementByMapElement(mapContainer).trigger('pf:renderSystemModules', {
|
||||
mapId: parseInt(mapContainer.data('id')),
|
||||
payload: Util.getCurrentSystemData()
|
||||
mapId: mapId,
|
||||
payload: Util.getCurrentSystemData(mapId)
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1238,10 +1288,12 @@ define([
|
||||
let setUniqueConnectionType = (connection, type, types) => {
|
||||
type = types.includes(type) ? [type] : [];
|
||||
|
||||
connection._jsPlumb.instance.batch(() => {
|
||||
removeConnectionTypes(connection, types.diff(type));
|
||||
addConnectionTypes(connection, type);
|
||||
});
|
||||
connection._jsPlumb.instance.setSuspendDrawing(true);
|
||||
|
||||
removeConnectionTypes(connection, types.diff(type));
|
||||
addConnectionTypes(connection, type);
|
||||
|
||||
connection._jsPlumb.instance.setSuspendDrawing(false, true);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -2074,6 +2126,40 @@ define([
|
||||
return findNonOverlappingDimensions(options, maxResults, findChain);
|
||||
};
|
||||
|
||||
/**
|
||||
* calculate the x/y coordinates for a new system - relative to current map scroll offset
|
||||
* @param mapContainer
|
||||
* @param maxResults
|
||||
* @returns {[{x: number, y: number}]}
|
||||
*/
|
||||
let newSystemPositionsByMapOffset = (mapContainer, maxResults = 1) => {
|
||||
let scrollPosition = {
|
||||
x: Math.abs(parseInt(mapContainer.attr('data-scroll-left')) || 0),
|
||||
y: Math.abs(parseInt(mapContainer.attr('data-scroll-top')) || 0)
|
||||
};
|
||||
|
||||
// space new positions from map top (e.g. used for tooltips)
|
||||
scrollPosition.y = Math.max(scrollPosition.y, 30);
|
||||
|
||||
// default position -> current map section top/left
|
||||
let positions = [scrollPosition];
|
||||
|
||||
// check default position for overlapping
|
||||
let dimensions = newSystemPositionByCoordinates(mapContainer, {
|
||||
center: [scrollPosition.x, scrollPosition.y],
|
||||
minX: scrollPosition.x,
|
||||
minY: scrollPosition.y
|
||||
}, maxResults, true);
|
||||
|
||||
if(dimensions.length){
|
||||
positions = dimensions.map(dim => ({
|
||||
x: parseInt(dim.left) || 0,
|
||||
y: parseInt(dim.top) || 0
|
||||
}));
|
||||
}
|
||||
return positions;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mapContainer
|
||||
@@ -2083,30 +2169,8 @@ define([
|
||||
|
||||
if(mapContainer){
|
||||
let mapId = mapContainer.data('id');
|
||||
let scrollPosition = {
|
||||
x: Math.abs(parseInt(mapContainer.attr('data-scroll-left')) || 0),
|
||||
y: Math.abs(parseInt(mapContainer.attr('data-scroll-top')) || 0)
|
||||
};
|
||||
|
||||
// space new positions from map top (e.g. used for tooltips)
|
||||
scrollPosition.y = Math.max(scrollPosition.y, 30);
|
||||
|
||||
// default position -> current map section top/left -------------------------------------------------------
|
||||
positions.defaults = [scrollPosition];
|
||||
|
||||
// check default position for overlapping -----------------------------------------------------------------
|
||||
let dimensions = newSystemPositionByCoordinates(mapContainer, {
|
||||
center: [scrollPosition.x, scrollPosition.y],
|
||||
minX: scrollPosition.x,
|
||||
minY: scrollPosition.y
|
||||
}, 2, true);
|
||||
|
||||
if(dimensions.length){
|
||||
positions.defaults = dimensions.map(dim => ({
|
||||
x: parseInt(dim.left) || 0,
|
||||
y: parseInt(dim.top) || 0
|
||||
}));
|
||||
}
|
||||
positions.defaults = newSystemPositionsByMapOffset(mapContainer, 2);
|
||||
|
||||
// -> calc possible coordinates for new system that should be used based on current user location ---------
|
||||
let currentLocationData = Util.getCurrentLocationData();
|
||||
@@ -2162,6 +2226,8 @@ define([
|
||||
getInfoForSystem: getInfoForSystem,
|
||||
getSystemDataFromMapData: getSystemDataFromMapData,
|
||||
getSystemData: getSystemData,
|
||||
getConnectionDataFromMapData: getConnectionDataFromMapData,
|
||||
getConnectionData: getConnectionData,
|
||||
getSystemTypeInfo: getSystemTypeInfo,
|
||||
getEffectInfoForSystem: getEffectInfoForSystem,
|
||||
markAsChanged: markAsChanged,
|
||||
@@ -2172,6 +2238,7 @@ define([
|
||||
toggleConnectionType: toggleConnectionType,
|
||||
toggleConnectionActive: toggleConnectionActive,
|
||||
setSystemActive: setSystemActive,
|
||||
showMapInfo: showMapInfo,
|
||||
showSystemInfo: showSystemInfo,
|
||||
showConnectionInfo: showConnectionInfo,
|
||||
showFindRouteDialog: showFindRouteDialog,
|
||||
@@ -2180,6 +2247,7 @@ define([
|
||||
getConnectionsByType: getConnectionsByType,
|
||||
getEndpointsDataByConnection: getEndpointsDataByConnection,
|
||||
getDataByConnection: getDataByConnection,
|
||||
getDataByConnections: getDataByConnections,
|
||||
searchConnectionsBySystems: searchConnectionsBySystems,
|
||||
searchConnectionsByScopeAndType: searchConnectionsByScopeAndType,
|
||||
getConnectionInfo: getConnectionInfo,
|
||||
@@ -2191,7 +2259,6 @@ define([
|
||||
setConnectionMassStatusType: setConnectionMassStatusType,
|
||||
setConnectionJumpMassType: setConnectionJumpMassType,
|
||||
getScopeInfoForConnection: getScopeInfoForConnection,
|
||||
getDataByConnections: getDataByConnections,
|
||||
deleteConnections: deleteConnections,
|
||||
getConnectionDataFromSignatures: getConnectionDataFromSignatures,
|
||||
getEndpointOverlaySignatureLocation: getEndpointOverlaySignatureLocation,
|
||||
@@ -2212,6 +2279,7 @@ define([
|
||||
checkRight: checkRight,
|
||||
newSystemPositionBySystem: newSystemPositionBySystem,
|
||||
newSystemPositionByCoordinates: newSystemPositionByCoordinates,
|
||||
newSystemPositionsByMapOffset: newSystemPositionsByMapOffset,
|
||||
newSystemPositionsByMap: newSystemPositionsByMap,
|
||||
getMapDeeplinkUrl: getMapDeeplinkUrl
|
||||
};
|
||||
|
||||
@@ -308,15 +308,14 @@ define([
|
||||
|
||||
|
||||
/**
|
||||
* clear both main update timeouts
|
||||
* clear both main update timeouts, and reset values
|
||||
* -> stop program from working -> shutdown
|
||||
*/
|
||||
let clearUpdateTimeouts = () => {
|
||||
for(let intervalKey in updateTimeouts){
|
||||
if(updateTimeouts.hasOwnProperty(intervalKey)){
|
||||
clearTimeout(updateTimeouts[intervalKey]);
|
||||
}
|
||||
}
|
||||
Object.keys(updateTimeouts).forEach(intervalKey => {
|
||||
clearTimeout(updateTimeouts[intervalKey]);
|
||||
updateTimeouts[intervalKey] = 0;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -417,20 +416,20 @@ define([
|
||||
|
||||
// IMPORTANT: Get user data for ONE map that is currently visible
|
||||
// On later releases this can be easy changed to "full update" all maps for a user
|
||||
let mapIds = [];
|
||||
let mapId;
|
||||
let newSystemPositions = null;
|
||||
let activeMap = Util.getMapModule().getActiveMap();
|
||||
|
||||
if(activeMap){
|
||||
mapIds = [activeMap.data('id')];
|
||||
mapId = activeMap.data('id');
|
||||
newSystemPositions = MapUtil.newSystemPositionsByMap(activeMap);
|
||||
}
|
||||
|
||||
let updatedUserData = {
|
||||
mapIds: mapIds,
|
||||
mapIds: mapId ? [mapId] : [],
|
||||
getMapUserData: Util.getSyncType() === 'webSocket' ? 0 : 1,
|
||||
mapTracking: locationToggle.is(':checked') ? 1 : 0, // location tracking
|
||||
systemData: Util.getCurrentSystemData()
|
||||
systemData: Util.getCurrentSystemData(mapId)
|
||||
};
|
||||
|
||||
if(newSystemPositions){
|
||||
|
||||
@@ -13,6 +13,7 @@ define([
|
||||
'module/system_route',
|
||||
'module/system_intel',
|
||||
'module/system_killboard',
|
||||
'module/global_thera',
|
||||
'module/connection_info',
|
||||
'app/counter'
|
||||
], (
|
||||
@@ -30,6 +31,7 @@ define([
|
||||
SystemRouteModule,
|
||||
SystemIntelModule,
|
||||
SystemKillboardModule,
|
||||
TheraModule,
|
||||
ConnectionInfoModule
|
||||
) => {
|
||||
'use strict';
|
||||
@@ -56,6 +58,7 @@ define([
|
||||
|
||||
// editable 'settings' popover
|
||||
editableSettingsClass: 'pf-editable-settings',
|
||||
editableHeadlineClass: 'pf-editable-headline',
|
||||
editableToggleClass: 'pf-editable-toggle',
|
||||
editableToggleItemClass: 'pf-editable-toggle-item',
|
||||
|
||||
@@ -65,13 +68,6 @@ define([
|
||||
|
||||
let mapTabChangeBlocked = false; // flag for preventing map tab switch
|
||||
|
||||
/**
|
||||
* get all maps for a maps module
|
||||
* @param mapModule
|
||||
* @returns {jQuery}
|
||||
*/
|
||||
let getMaps = mapModule => $(mapModule).find('.' + Util.config.mapClass);
|
||||
|
||||
/**
|
||||
* get the current active mapElement
|
||||
* @returns {bool|jQuery}
|
||||
@@ -90,6 +86,12 @@ define([
|
||||
* @param tabContentWrapperEl
|
||||
*/
|
||||
let setMapTabContentWrapperObserver = tabContentWrapperEl => {
|
||||
$(tabContentWrapperEl).on('pf:renderGlobalModules', `.${Util.config.mapTabContentClass}`, function(e, data){
|
||||
getModules()
|
||||
.then(modules => filterModules(modules, 'global'))
|
||||
.then(modules => renderModules(modules, e.target, data));
|
||||
});
|
||||
|
||||
$(tabContentWrapperEl).on('pf:renderSystemModules', `.${Util.config.mapTabContentClass}`, function(e, data){
|
||||
getModules()
|
||||
.then(modules => filterModules(modules, 'system'))
|
||||
@@ -114,6 +116,12 @@ define([
|
||||
.then(modules => removeModules(modules, e.target));
|
||||
});
|
||||
|
||||
$(tabContentWrapperEl).on('pf:updateGlobalModules', `.${Util.config.mapTabContentClass}`, (e, data) => {
|
||||
getModules()
|
||||
.then(modules => filterModules(modules, 'global'))
|
||||
.then(modules => updateModules(modules, e.target, data));
|
||||
});
|
||||
|
||||
$(tabContentWrapperEl).on('pf:updateSystemModules', `.${Util.config.mapTabContentClass}`, (e, data) => {
|
||||
getModules()
|
||||
.then(modules => filterModules(modules, true, 'fullDataUpdate'))
|
||||
@@ -141,6 +149,7 @@ define([
|
||||
SystemRouteModule,
|
||||
SystemIntelModule,
|
||||
SystemKillboardModule,
|
||||
TheraModule,
|
||||
ConnectionInfoModule
|
||||
];
|
||||
|
||||
@@ -361,7 +370,7 @@ define([
|
||||
});
|
||||
};
|
||||
|
||||
removeModule(Module, gridArea, true).then(abc => render(Module, gridArea, defaultPosition, mapId, payload));
|
||||
removeModule(Module, gridArea, false).then(abc => render(Module, gridArea, defaultPosition, mapId, payload));
|
||||
};
|
||||
|
||||
return new Promise(renderModuleExecutor);
|
||||
@@ -533,7 +542,7 @@ define([
|
||||
let updateSystemModulesData = (mapModule, systemData) => {
|
||||
if(systemData){
|
||||
// check if current open system is still the requested info system
|
||||
let currentSystemData = Util.getCurrentSystemData();
|
||||
let currentSystemData = Util.getCurrentSystemData(systemData.mapId);
|
||||
|
||||
if(
|
||||
currentSystemData &&
|
||||
@@ -556,6 +565,7 @@ define([
|
||||
let setTabContentObserver = (tabContent, mapId) => {
|
||||
|
||||
let defaultSortableOptions = {
|
||||
invertSwap: true,
|
||||
animation: Init.animationSpeed.mapModule,
|
||||
handle: '.' + config.sortableHandleClass,
|
||||
draggable: '.' + config.moduleClass,
|
||||
@@ -926,10 +936,11 @@ define([
|
||||
let mapId = parseInt(linkEl.dataset.mapId) || 0;
|
||||
let defaultSystemId = parseInt(linkEl.dataset.defaultSystemId) || 0;
|
||||
let tabMapData = Util.getCurrentMapData(mapId);
|
||||
let tabContentEl = document.getElementById(config.mapTabIdPrefix + mapId);
|
||||
|
||||
if(tabMapData !== false){
|
||||
// tabContentEl does not exist in case of error where all map elements got removed
|
||||
if(tabMapData !== false && tabContentEl){
|
||||
// load map
|
||||
let tabContentEl = document.getElementById(config.mapTabIdPrefix + mapId);
|
||||
let areaMap = tabContentEl.querySelector(`.${Util.getMapTabContentAreaClass('map')}`);
|
||||
Map.loadMap(areaMap, tabMapData, {showAnimation: true}).then(payload => {
|
||||
// "wake up" scrollbar for map and get previous state back
|
||||
@@ -938,6 +949,11 @@ define([
|
||||
let areaMap = mapElement.closest('.mCustomScrollbar');
|
||||
$(areaMap).mCustomScrollbar('update');
|
||||
|
||||
// show "global" map panels of map was initial loaded
|
||||
if(payload.isFirstLoad){
|
||||
MapUtil.showMapInfo(mapConfig.map);
|
||||
}
|
||||
|
||||
// if there is an already an "active" system -> setCurrentSystemData for that again
|
||||
let activeSystemEl = mapElement.querySelector(`.${MapUtil.config.systemActiveClass}`);
|
||||
if(activeSystemEl){
|
||||
@@ -973,9 +989,6 @@ define([
|
||||
|
||||
// skip "add button"
|
||||
if(newMapId > 0){
|
||||
// delete currentSystemData -> will be set for new map (if there is is an active system)
|
||||
delete Init.currentSystemData;
|
||||
|
||||
let currentTabContentEl = document.getElementById(config.mapTabIdPrefix + oldMapId);
|
||||
|
||||
// disable scrollbar for map that will be hidden. "freeze" current state
|
||||
@@ -991,90 +1004,81 @@ define([
|
||||
* @param options
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
let updateTabData = (tabLinkEl, options) => {
|
||||
let updateTabData = (tabLinkEl, options) => new Promise(resolve => {
|
||||
// set "main" data
|
||||
tabLinkEl.dataset.mapId = options.id;
|
||||
|
||||
/**
|
||||
* update tab promise
|
||||
* @param resolve
|
||||
*/
|
||||
let updateTabExecutor = resolve => {
|
||||
// set "main" data
|
||||
tabLinkEl.dataset.mapId = options.id;
|
||||
// add updated timestamp (not available for "add" tab
|
||||
if(Util.getObjVal(options, 'updated.updated')){
|
||||
tabLinkEl.dataset.updated = options.updated.updated;
|
||||
}
|
||||
|
||||
// add updated timestamp (not available for "add" tab
|
||||
if(Util.getObjVal(options, 'updated.updated')){
|
||||
tabLinkEl.dataset.updated = options.updated.updated;
|
||||
// change "tab" link
|
||||
tabLinkEl.setAttribute('href', `#${config.mapTabIdPrefix}${options.id}`);
|
||||
|
||||
// change "map" icon
|
||||
let mapIconEl = tabLinkEl.querySelector(`.${config.mapTabIconClass}`);
|
||||
mapIconEl.classList.remove(...mapIconEl.classList);
|
||||
mapIconEl.classList.add(config.mapTabIconClass, 'fas', 'fa-fw', options.icon);
|
||||
|
||||
// change "shared" icon
|
||||
let mapSharedIconEl = tabLinkEl.querySelector(`.${config.mapTabSharedIconClass}`);
|
||||
mapSharedIconEl.style.display = 'none';
|
||||
|
||||
// check if the map is a "shared" map
|
||||
if(options.access){
|
||||
if(
|
||||
options.access.character.length > 1 ||
|
||||
options.access.corporation.length > 1 ||
|
||||
options.access.alliance.length > 1
|
||||
){
|
||||
mapSharedIconEl.style.display = 'initial';
|
||||
}
|
||||
}
|
||||
|
||||
// change "tab" link
|
||||
tabLinkEl.setAttribute('href', `#${config.mapTabIdPrefix}${options.id}`);
|
||||
// change map name label
|
||||
let textEl = tabLinkEl.querySelector(`.${config.mapTabLinkTextClass}`);
|
||||
textEl.textContent = options.name;
|
||||
|
||||
// change "map" icon
|
||||
let mapIconEl = tabLinkEl.querySelector(`.${config.mapTabIconClass}`);
|
||||
mapIconEl.classList.remove(...mapIconEl.classList);
|
||||
mapIconEl.classList.add(config.mapTabIconClass, 'fas', 'fa-fw', options.icon);
|
||||
// change tabClass
|
||||
let listEl = tabLinkEl.parentNode;
|
||||
|
||||
// change "shared" icon
|
||||
let mapSharedIconEl = tabLinkEl.querySelector(`.${config.mapTabSharedIconClass}`);
|
||||
mapSharedIconEl.style.display = 'none';
|
||||
// new tab classes
|
||||
let tabClasses = [config.mapTabClass, options.type.classTab];
|
||||
|
||||
// check if the map is a "shared" map
|
||||
if(options.access){
|
||||
if(
|
||||
options.access.character.length > 1 ||
|
||||
options.access.corporation.length > 1 ||
|
||||
options.access.alliance.length > 1
|
||||
){
|
||||
mapSharedIconEl.style.display = 'initial';
|
||||
}
|
||||
}
|
||||
if(options.draggable === false){
|
||||
tabClasses.push('noSort');
|
||||
}
|
||||
|
||||
// change map name label
|
||||
let textEl = tabLinkEl.querySelector(`.${config.mapTabLinkTextClass}`);
|
||||
textEl.textContent = options.name;
|
||||
// check if tab was "active" before
|
||||
if(listEl.classList.contains('active')){
|
||||
tabClasses.push('active');
|
||||
}
|
||||
listEl.classList.remove(...listEl.classList);
|
||||
listEl.classList.add(...tabClasses);
|
||||
|
||||
// change tabClass
|
||||
let listEl = tabLinkEl.parentNode;
|
||||
// set title for tooltip
|
||||
if(options.type.name !== undefined){
|
||||
textEl.setAttribute('title', `${options.type.name} map`);
|
||||
}
|
||||
|
||||
// new tab classes
|
||||
let tabClasses = [config.mapTabClass, options.type.classTab];
|
||||
|
||||
if(options.draggable === false){
|
||||
tabClasses.push('noSort');
|
||||
}
|
||||
|
||||
// check if tab was "active" before
|
||||
if(listEl.classList.contains('active')){
|
||||
tabClasses.push('active');
|
||||
}
|
||||
listEl.classList.remove(...listEl.classList);
|
||||
listEl.classList.add(...tabClasses);
|
||||
|
||||
// set title for tooltip
|
||||
if(options.type.name !== undefined){
|
||||
textEl.setAttribute('title', `${options.type.name} map`);
|
||||
}
|
||||
|
||||
let mapTooltipOptions = {
|
||||
placement: 'bottom',
|
||||
container: 'body',
|
||||
trigger: 'hover',
|
||||
delay: 150
|
||||
};
|
||||
|
||||
$(listEl.querySelector('[title]')).tooltip(mapTooltipOptions).tooltip('fixTitle');
|
||||
|
||||
resolve({
|
||||
action: 'update',
|
||||
data: {
|
||||
mapId: options.id,
|
||||
mapName: options.name
|
||||
}
|
||||
});
|
||||
let mapTooltipOptions = {
|
||||
placement: 'bottom',
|
||||
container: 'body',
|
||||
trigger: 'hover',
|
||||
delay: 150
|
||||
};
|
||||
|
||||
return new Promise(updateTabExecutor);
|
||||
};
|
||||
$(listEl.querySelector('[title]')).tooltip(mapTooltipOptions).tooltip('fixTitle');
|
||||
|
||||
resolve({
|
||||
action: 'update',
|
||||
data: {
|
||||
mapId: options.id,
|
||||
mapName: options.name
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* add a new tab to tab-map-module end return promise
|
||||
@@ -1545,10 +1549,14 @@ define([
|
||||
setMapTabLayout(tabEl, layoutCurrent);
|
||||
|
||||
// prepare select options for modules
|
||||
let sourceOptions = modules.sort((a, b) => a.isPlugin - b.isPlugin).map(Module => ({
|
||||
let modulePrioCounts = Array(BaseModule.scopeOrder.length).fill(0);
|
||||
let sourceOptions = modules.sort((a, b) => a.getOrderPrio() - b.getOrderPrio()).map(Module => ({
|
||||
value: Module.name,
|
||||
text: `(${Module.scope.substring(0, 3)}) ${Module.label}`,
|
||||
text: Module.label,
|
||||
metaData: {
|
||||
scope: Module.scope,
|
||||
orderPrio: Module.getOrderPrio(),
|
||||
prioCount: ++modulePrioCounts[Module.getOrderPrio()],
|
||||
isPlugin: Module.isPlugin
|
||||
}
|
||||
}));
|
||||
@@ -1628,6 +1636,19 @@ define([
|
||||
}
|
||||
}
|
||||
}, {passive: false});
|
||||
|
||||
// add "headlines" to Modules checklist -------------------------------------------------------
|
||||
anchorEl.childNodes.forEach((gridItem, i) => {
|
||||
if(sourceOptions[i].metaData.prioCount === 1){
|
||||
gridItem.classList.add(config.editableHeadlineClass);
|
||||
gridItem.setAttribute('data-count',
|
||||
modulePrioCounts[sourceOptions[i].metaData.orderPrio]
|
||||
);
|
||||
gridItem.setAttribute('data-headline',
|
||||
BaseModule.scopeOrder[sourceOptions[i].metaData.orderPrio]
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
settingsLinkEl.on('save', {sourceOptions: sourceOptions}, (e, params) => {
|
||||
@@ -1644,15 +1665,23 @@ define([
|
||||
let showModules = filterModules(modules, params.newValue.diff(oldValue), 'name');
|
||||
|
||||
removeModules(hideModules, tabContentEl).then(payload => {
|
||||
let showGlobalModules = showModules.filter(Module => Module.scope === 'global');
|
||||
let showSystemModules = showModules.filter(Module => Module.scope === 'system');
|
||||
let showConnectionModules = showModules.filter(Module => Module.scope === 'connection');
|
||||
if(showGlobalModules.length){
|
||||
renderModules(showGlobalModules, tabContentEl, {
|
||||
mapId: activeMapId,
|
||||
payload: null
|
||||
});
|
||||
}
|
||||
|
||||
if(
|
||||
showSystemModules.length &&
|
||||
Util.getCurrentSystemData()
|
||||
Util.getCurrentSystemData(activeMapId)
|
||||
){
|
||||
renderModules(showSystemModules, tabContentEl, {
|
||||
mapId: activeMapId,
|
||||
payload: Util.getCurrentSystemData()
|
||||
payload: Util.getCurrentSystemData(activeMapId)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1706,28 +1735,24 @@ define([
|
||||
/**
|
||||
* collect all data (systems/connections) for export/save from each active map in the map module
|
||||
* if no change detected -> do not attach map data to return array
|
||||
* @param mapModule
|
||||
* @param {HTMLElement} mapModule
|
||||
* @param filter
|
||||
* @returns {Array}
|
||||
* @returns {[]}
|
||||
*/
|
||||
let getMapModuleDataForUpdate = (mapModule, filter = ['hasId', 'hasChanged']) => {
|
||||
// get all active map elements for module
|
||||
let mapElements = getMaps(mapModule);
|
||||
|
||||
let data = [];
|
||||
for(let i = 0; i < mapElements.length; i++){
|
||||
[...mapModule.getElementsByClassName(Util.config.mapClass)].forEach(mapElement => {
|
||||
// get all changed (system / connection) data from this map
|
||||
let mapData = Map.getMapDataForSync($(mapElements[i]), filter);
|
||||
if(mapData !== false){
|
||||
if(
|
||||
mapData.data.systems.length > 0 ||
|
||||
mapData.data.connections.length > 0
|
||||
){
|
||||
data.push(mapData);
|
||||
}
|
||||
let mapData = Map.getMapDataForSync(mapElement, filter);
|
||||
if(
|
||||
mapData && (
|
||||
(Util.getObjVal(mapData, 'data.systems') || []).length ||
|
||||
(Util.getObjVal(mapData, 'data.connections') || []).length
|
||||
)
|
||||
){
|
||||
data.push(mapData);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
return data;
|
||||
};
|
||||
|
||||
|
||||
@@ -1293,47 +1293,35 @@ define([
|
||||
let mapUserUpdateKey = 'UPDATE_SERVER_USER_DATA';
|
||||
|
||||
// Set the name of the hidden property and the change event for visibility
|
||||
let hidden, visibilityChange;
|
||||
if(typeof document.hidden !== 'undefined'){ // Opera 12.10 and Firefox 18 and later support
|
||||
hidden = 'hidden';
|
||||
let visibilityState, visibilityChange;
|
||||
if(typeof document.visibilityState !== 'undefined'){ // Opera 12.10 and Firefox 18 and later support
|
||||
visibilityState = 'visibilityState';
|
||||
visibilityChange = 'visibilitychange';
|
||||
}else if(typeof document.mozHidden !== 'undefined'){
|
||||
hidden = 'mozHidden';
|
||||
visibilityChange = 'mozvisibilitychange';
|
||||
}else if(typeof document.msHidden !== 'undefined'){
|
||||
hidden = 'msHidden';
|
||||
visibilityChange = 'msvisibilitychange';
|
||||
}else if(typeof document.webkitHidden !== 'undefined'){
|
||||
hidden = 'webkitHidden';
|
||||
visibilityChange = 'webkitvisibilitychange';
|
||||
}
|
||||
|
||||
// function is called if the tab becomes active/inactive
|
||||
let handleVisibilityChange = () => {
|
||||
if(document[hidden]){
|
||||
// tab is invisible
|
||||
// globally store current visibility status
|
||||
window.isVisible = false;
|
||||
|
||||
Util.getCurrentTriggerDelay( mapUpdateKey, increaseTimer );
|
||||
Util.getCurrentTriggerDelay( mapUserUpdateKey, increaseTimer );
|
||||
}else{
|
||||
if(document[visibilityState] === 'visible'){
|
||||
// tab is visible
|
||||
// globally store current visibility status
|
||||
window.isVisible = true;
|
||||
|
||||
Util.getCurrentTriggerDelay( mapUpdateKey, -increaseTimer );
|
||||
Util.getCurrentTriggerDelay( mapUserUpdateKey, -increaseTimer );
|
||||
Util.getCurrentTriggerDelay(mapUpdateKey, -increaseTimer);
|
||||
Util.getCurrentTriggerDelay(mapUserUpdateKey, -increaseTimer);
|
||||
|
||||
// stop blinking tab from previous notifications
|
||||
Util.stopTabBlink();
|
||||
}else{
|
||||
// tab is invisible
|
||||
// globally store current visibility status
|
||||
window.isVisible = false;
|
||||
|
||||
Util.getCurrentTriggerDelay(mapUpdateKey, increaseTimer);
|
||||
Util.getCurrentTriggerDelay(mapUserUpdateKey, increaseTimer);
|
||||
}
|
||||
};
|
||||
|
||||
if(
|
||||
typeof document.addEventListener !== 'undefined' &&
|
||||
typeof document[hidden] !== 'undefined'
|
||||
){
|
||||
if(visibilityState && visibilityChange){
|
||||
// the current browser supports this feature
|
||||
// Handle page visibility change
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
define([
|
||||
'PNotify',
|
||||
'PNotifyDesktop',
|
||||
'PNotifyButtons',
|
||||
'PNotifyCallbacks',
|
||||
'PNotifyDesktop',
|
||||
'NonBlock'
|
||||
], (PNotify) => {
|
||||
'use strict';
|
||||
@@ -30,6 +31,9 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* default PNotify config
|
||||
*/
|
||||
let initDefaultPNotifyConfig = () => {
|
||||
PNotify.defaults.styling = 'bootstrap3';
|
||||
PNotify.defaults.icons = 'fontawesome5';
|
||||
@@ -54,7 +58,6 @@ define([
|
||||
config.modules = {
|
||||
Desktop: Object.assign({}, {desktop: true}, options.desktop)
|
||||
};
|
||||
startTabBlink(config.title); // make browser tab blink
|
||||
}
|
||||
|
||||
switch(config.type){
|
||||
@@ -99,60 +102,7 @@ define([
|
||||
|
||||
initDefaultPNotifyConfig();
|
||||
|
||||
// browser tab blink ==============================================================================================
|
||||
// initial page title (cached)
|
||||
let initialPageTitle = document.title;
|
||||
|
||||
// global blink timeout cache
|
||||
let blinkTimer;
|
||||
|
||||
/**
|
||||
* change document.title and make the browsers tab blink
|
||||
* @param blinkTitle
|
||||
*/
|
||||
let startTabBlink = blinkTitle => {
|
||||
let initBlink = (function(){
|
||||
// count blinks if tab is currently active
|
||||
let activeTabBlinkCount = 0;
|
||||
|
||||
let blink = (blinkTitle) => {
|
||||
// number of "blinks" should be limited if tab is currently active
|
||||
if(window.isVisible){
|
||||
activeTabBlinkCount++;
|
||||
}
|
||||
|
||||
// toggle page title
|
||||
document.title = (document.title === blinkTitle) ? initialPageTitle : blinkTitle;
|
||||
|
||||
if(activeTabBlinkCount > 10){
|
||||
stopTabBlink();
|
||||
}
|
||||
};
|
||||
|
||||
return () => {
|
||||
if(!blinkTimer){
|
||||
blinkTimer = setInterval(blink, 1000, blinkTitle);
|
||||
}
|
||||
};
|
||||
}(blinkTitle));
|
||||
|
||||
initBlink();
|
||||
};
|
||||
|
||||
/**
|
||||
* stop blinking document.title
|
||||
*/
|
||||
let stopTabBlink = () => {
|
||||
if(blinkTimer){
|
||||
clearInterval(blinkTimer);
|
||||
document.title = initialPageTitle;
|
||||
blinkTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
showNotify: showNotify,
|
||||
startTabBlink: startTabBlink,
|
||||
stopTabBlink: stopTabBlink
|
||||
showNotify: showNotify
|
||||
};
|
||||
});
|
||||
@@ -212,7 +212,7 @@ define([
|
||||
let systemsElement = $(this);
|
||||
|
||||
let systemTable = $('<table>', {
|
||||
id: Util.getTableId(config.tableId, 'systems', mapData.config.id, ''),
|
||||
id: Util.getTableId(config.tableId, 'systems', mapData.config.id),
|
||||
class: ['compact', 'stripe', 'order-column', 'row-border'].join(' ')
|
||||
});
|
||||
systemsElement.append(systemTable);
|
||||
@@ -469,7 +469,7 @@ define([
|
||||
|
||||
let confirmationSettings = {
|
||||
placement: 'left',
|
||||
title: 'Delete system',
|
||||
title: '---',
|
||||
template: Util.getConfirmationTemplate(null, {
|
||||
size: 'small',
|
||||
noTitle: true
|
||||
@@ -535,7 +535,7 @@ define([
|
||||
let connectionsElement = $(this);
|
||||
|
||||
let connectionTable = $('<table>', {
|
||||
id: Util.getTableId(config.tableId, 'connections', mapData.config.id, ''),
|
||||
id: Util.getTableId(config.tableId, 'connections', mapData.config.id),
|
||||
class: ['compact', 'stripe', 'order-column', 'row-border'].join(' ')
|
||||
});
|
||||
connectionsElement.append(connectionTable);
|
||||
@@ -678,7 +678,7 @@ define([
|
||||
|
||||
let confirmationSettings = {
|
||||
placement: 'left',
|
||||
title: 'Delete connection',
|
||||
title: '---',
|
||||
template: Util.getConfirmationTemplate(null, {
|
||||
size: 'small',
|
||||
noTitle: true
|
||||
@@ -686,9 +686,7 @@ define([
|
||||
onConfirm: function(e, target){
|
||||
let deleteRowElement = $(target).parents('tr');
|
||||
|
||||
// deleteSignatures(row);
|
||||
let connection = $().getConnectionById(mapData.config.id, rowData.id);
|
||||
|
||||
MapUtil.deleteConnections([connection], () => {
|
||||
// callback function after ajax "delete" success
|
||||
// remove table row
|
||||
|
||||
@@ -90,8 +90,7 @@ define([
|
||||
let name = parts[0];
|
||||
let sizeLabel;
|
||||
if(Util.getObjVal(customOptions, 'showWhSizeLabel')){
|
||||
let wormholeSizeData = Util.getObjVal(Init, 'wormholes.' + name + '.size');
|
||||
sizeLabel = Util.getObjVal(wormholeSizeData, 'label') || '';
|
||||
sizeLabel = Util.getObjVal(Init, `wormholes.${name}.size.label`) || '';
|
||||
}
|
||||
|
||||
let securityClass = Util.getSecurityClassForSystem(getSystemSecurityFromLabel(parts[1]));
|
||||
@@ -102,19 +101,17 @@ define([
|
||||
|
||||
let classes = [securityClass, Util.config.popoverTriggerClass, Util.config.helpDefaultClass];
|
||||
|
||||
markup += '<span>' + name + '</span>';
|
||||
markup += `<span>${name}</span>`;
|
||||
if(sizeLabel !== undefined){
|
||||
markup += '<span><kbd>' + sizeLabel + '</kbd></span>';
|
||||
}else{
|
||||
markup += ' ';
|
||||
markup += `<span><kbd>${sizeLabel}</kbd></span>`;
|
||||
}
|
||||
markup += '<i class="fas fa-long-arrow-alt-right txt-color txt-color-grayLight"></i>';
|
||||
markup += '<span class="' + classes.join(' ') + '" data-name="' + name + '"> ' + label + '</span>';
|
||||
markup += `<span class="${classes.join(' ')}" data-name="${name}"> ${label}</span>`;
|
||||
if(suffix.length){
|
||||
markup += ' <span>' + suffix + '</span>';
|
||||
markup += ` <span>${suffix}</span>`;
|
||||
}
|
||||
}else{
|
||||
markup += '<span>' + state.text + '</span>';
|
||||
markup += `<span>${state.text}</span>`;
|
||||
}
|
||||
|
||||
return $(markup);
|
||||
@@ -203,10 +200,10 @@ define([
|
||||
}
|
||||
|
||||
let securityClass = Util.getSecurityClassForSystem(parts[1]);
|
||||
markup += '<span class="' + styleClass.join(' ') + '">' + parts[0] + '</span> ';
|
||||
markup += '<span class="' + securityClass + '">' + parts[1] + '</span>';
|
||||
markup += `<span class="${styleClass.join(' ')}">${parts[0]}</span>`;
|
||||
markup += `<span class="${securityClass}"> ${parts[1]}</span>`;
|
||||
}else{
|
||||
markup += '<span>' + state.text + '</span>';
|
||||
markup += `<span>${state.text}</span>`;
|
||||
}
|
||||
|
||||
return $(markup);
|
||||
|
||||
@@ -2,9 +2,11 @@ define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/map/util',
|
||||
'app/lib/cache',
|
||||
'app/promises/promise.deferred',
|
||||
'app/promises/promise.queue'
|
||||
], ($, Init, Util, DeferredPromise, PromiseQueue) => {
|
||||
], ($, Init, Util, MapUtil, Cache, DeferredPromise, PromiseQueue) => {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
@@ -127,6 +129,34 @@ define([
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* label element
|
||||
* @param text
|
||||
* @param cls
|
||||
* @returns {HTMLSpanElement}
|
||||
*/
|
||||
newLabelElement(text, cls = []){
|
||||
let labelEl = document.createElement('span');
|
||||
labelEl.classList.add('label', 'center-block', ...cls);
|
||||
labelEl.textContent = text || '';
|
||||
return labelEl;
|
||||
}
|
||||
|
||||
/**
|
||||
* control button element
|
||||
* @param text
|
||||
* @param cls
|
||||
* @param iconCls
|
||||
* @returns {HTMLDivElement}
|
||||
*/
|
||||
newControlElement(text, cls = [], iconCls = ['fa-sync']){
|
||||
let controlEl = document.createElement('div');
|
||||
controlEl.classList.add(...[BaseModule.Util.config.dynamicAreaClass, this._config.controlAreaClass, ...cls]);
|
||||
controlEl.insertAdjacentHTML('beforeend', ` ${text}`);
|
||||
controlEl.prepend(this.newIconElement(iconCls));
|
||||
return controlEl;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP request handler for internal (Pathfinder) ajax calls
|
||||
* @param args
|
||||
@@ -245,6 +275,188 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get a unique cache key name for "source"/"target"-name
|
||||
* @param sourceName
|
||||
* @param targetName
|
||||
* @returns {string|boolean}
|
||||
*/
|
||||
static getConnectionDataCacheKey(sourceName, targetName){
|
||||
let key = false;
|
||||
if(sourceName && targetName){
|
||||
// names can be "undefined" in case system is currently in drag/drop state
|
||||
// sort() is important -> ignore direction
|
||||
key = `con_` + `${ [String(sourceName).toLowerCase(), String(targetName).toLowerCase()].sort() }`.hashCode();
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a connectionsData object that holds all connections for given mapIds (used as cache for route search)
|
||||
* @param mapIds
|
||||
* @returns {{}}
|
||||
*/
|
||||
static getConnectionsDataFromMaps(mapIds){
|
||||
let data = {};
|
||||
for(let mapId of mapIds){
|
||||
let map = MapUtil.getMapInstance(mapId);
|
||||
if(map){
|
||||
let cacheKey = `map_${mapId}`;
|
||||
let cache = BaseModule.getCache('mapConnections');
|
||||
let mapConnectionsData = cache.get(cacheKey);
|
||||
|
||||
if(!mapConnectionsData){
|
||||
mapConnectionsData = this.getConnectionsDataFromConnections(mapId, map.getAllConnections());
|
||||
// update cache
|
||||
cache.set(cacheKey, mapConnectionsData);
|
||||
}
|
||||
Object.assign(data, mapConnectionsData);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a connectionsData object for all connections
|
||||
* @param mapId
|
||||
* @param connections
|
||||
* @returns {{}}
|
||||
*/
|
||||
static getConnectionsDataFromConnections(mapId = 0, connections = []){
|
||||
let data = {};
|
||||
if(connections.length){
|
||||
let connectionsData = MapUtil.getDataByConnections(connections);
|
||||
for(let connectionData of connectionsData){
|
||||
let connectionDataCacheKey = BaseModule.getConnectionDataCacheKey(connectionData.sourceName, connectionData.targetName);
|
||||
|
||||
// skip double connections between same systems
|
||||
if(connectionDataCacheKey && !Object.keys(data).includes(connectionDataCacheKey)){
|
||||
data[connectionDataCacheKey] = {
|
||||
map: {
|
||||
id: mapId
|
||||
},
|
||||
connection: {
|
||||
id: connectionData.id,
|
||||
type: connectionData.type,
|
||||
scope: connectionData.scope,
|
||||
updated: connectionData.updated
|
||||
},
|
||||
source: {
|
||||
id: connectionData.source,
|
||||
name: connectionData.sourceName,
|
||||
alias: connectionData.sourceAlias
|
||||
},
|
||||
target: {
|
||||
id: connectionData.target,
|
||||
name: connectionData.targetName,
|
||||
alias: connectionData.targetAlias
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* search for a specific connection by "source"/"target"-name inside connectionsData cache
|
||||
* @param connectionsData
|
||||
* @param sourceName
|
||||
* @param targetName
|
||||
* @returns {*}
|
||||
*/
|
||||
static findConnectionsData(connectionsData, sourceName, targetName){
|
||||
return this.Util.getObjVal(connectionsData, this.getConnectionDataCacheKey(sourceName, targetName));
|
||||
}
|
||||
|
||||
/**
|
||||
* get fake connection data (default connection type in case connection was not found on a map)
|
||||
* @param sourceSystemData
|
||||
* @param targetSystemData
|
||||
* @param scope
|
||||
* @param types
|
||||
* @returns {{connection: {scope: string, id: number, type: [*]}, source: {name: number, alias: number, id: number}, target: {name: number, alias: number, id: number}}}
|
||||
*/
|
||||
static getFakeConnectionData(sourceSystemData, targetSystemData, scope = 'stargate', types = []){
|
||||
return {
|
||||
connection: {
|
||||
id: 0,
|
||||
scope: scope,
|
||||
type: types.length ? types : [MapUtil.getDefaultConnectionTypeByScope(scope)],
|
||||
updated: 0
|
||||
},
|
||||
source: {
|
||||
id: 0,
|
||||
name: sourceSystemData.system,
|
||||
alias: sourceSystemData.system
|
||||
},
|
||||
target: {
|
||||
id: 0,
|
||||
name: targetSystemData.system,
|
||||
alias: targetSystemData.system
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* get fake connection Element
|
||||
* @param connectionData
|
||||
* @returns {string}
|
||||
*/
|
||||
static getFakeConnectionElement(connectionData){
|
||||
let mapId = this.Util.getObjVal(connectionData, 'map.id') || 0;
|
||||
let connectionId = this.Util.getObjVal(connectionData, 'connection.id') || 0;
|
||||
let scope = this.Util.getObjVal(connectionData, 'connection.scope') || '';
|
||||
let classes = MapUtil.getConnectionFakeClassesByTypes(this.Util.getObjVal(connectionData, 'connection.type') || []);
|
||||
let disabled = !mapId || !connectionId;
|
||||
|
||||
let connectionElement = '<div data-mapId="' + mapId + '" data-connectionId="' + connectionId + '" ';
|
||||
connectionElement += (disabled ? 'data-disabled' : '');
|
||||
connectionElement += ' class="' + classes.join(' ') + '" ';
|
||||
connectionElement += ' title="' + scope + '" data-placement="bottom"></div>';
|
||||
return connectionElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* get static instance of in-memory Cache() store by 'name'
|
||||
* -> not persistent across page reloads
|
||||
* -> persistent across module instances (different and same maps)
|
||||
* @param name
|
||||
* @returns {Cache}
|
||||
*/
|
||||
static getCache(name){
|
||||
let key = `CACHE-${name}`;
|
||||
if(!this.Util.getObjVal(this, key)){
|
||||
let configKey = `cacheConfig.${name}`;
|
||||
let cacheConfig = this.Util.getObjVal(this, configKey);
|
||||
if(!cacheConfig){
|
||||
console.warn('Missing Cache config for %o. Expected at %o. Default config loaded…',
|
||||
name, `${this.name}.${configKey}`
|
||||
);
|
||||
cacheConfig = {};
|
||||
}else{
|
||||
// set cache name
|
||||
cacheConfig.name = name;
|
||||
}
|
||||
|
||||
this[key] = new Cache(cacheConfig);
|
||||
}
|
||||
return this[key];
|
||||
}
|
||||
|
||||
static now(){
|
||||
return new Date().getTime() / 1000;
|
||||
}
|
||||
|
||||
static getOrderPrio(){
|
||||
return this.isPlugin ?
|
||||
this.scopeOrder.indexOf('plugin') :
|
||||
(this.scopeOrder.indexOf(this.scope) !== -1 ?
|
||||
this.scopeOrder.indexOf(this.scope) :
|
||||
this.scopeOrder.length - 1
|
||||
);
|
||||
}
|
||||
|
||||
static newDeferredPromise(){
|
||||
return new DeferredPromise();
|
||||
}
|
||||
@@ -259,6 +471,14 @@ define([
|
||||
BaseModule.fullDataUpdate = false; // static module requires additional data (e.g. system description,...)
|
||||
BaseModule.Util = Util; // static access to Pathfinders Util object
|
||||
|
||||
BaseModule.scopeOrder = [
|
||||
'system',
|
||||
'connection',
|
||||
'global',
|
||||
'plugin',
|
||||
'undefined'
|
||||
];
|
||||
|
||||
BaseModule.handler = [
|
||||
'render',
|
||||
'init',
|
||||
@@ -268,6 +488,14 @@ define([
|
||||
'onSortableEvent'
|
||||
];
|
||||
|
||||
BaseModule.cacheConfig = {
|
||||
mapConnections: {
|
||||
ttl: 5,
|
||||
maxSize: 600,
|
||||
debug: false
|
||||
}
|
||||
};
|
||||
|
||||
BaseModule.defaultConfig = {
|
||||
position: 1,
|
||||
className: 'pf-base-module', // class for module
|
||||
@@ -276,6 +504,7 @@ define([
|
||||
sortTargetAreas: ['a', 'b', 'c'], // sortable areas where module can be dragged into
|
||||
headline: 'Base headline', // module headline
|
||||
bodyClassName: 'pf-module-body', // class for module body [optional: can be used]
|
||||
controlAreaClass: 'pf-module-control-area', // class for "control" areas
|
||||
|
||||
moduleHeadlineIconClass: 'pf-module-icon-button' // class for toolbar icons in the head
|
||||
};
|
||||
|
||||
@@ -78,11 +78,9 @@ define([
|
||||
*/
|
||||
newInfoPanelControlEl(mapId){
|
||||
let connectionEl = this.newConnectionElement(mapId);
|
||||
|
||||
let controlEl = document.createElement('div');
|
||||
controlEl.classList.add(Util.config.dynamicAreaClass, this._config.controlAreaClass);
|
||||
controlEl.insertAdjacentHTML('beforeend', '<i class="fas fa-fw fa-plus"></i> add connection <kbd>ctrl</kbd> + <kbd>click</kbd>');
|
||||
connectionEl.append(controlEl);
|
||||
connectionEl.append(
|
||||
this.newControlElement('add connection <kbd>ctrl</kbd> + <kbd>click</kbd>', [], ['fa-plus'])
|
||||
);
|
||||
|
||||
return connectionEl;
|
||||
}
|
||||
@@ -267,9 +265,12 @@ define([
|
||||
}, context => {
|
||||
// hide loading animation
|
||||
for(let contextData of context.connectionsData){
|
||||
let tableEls = this.moduleElement.querySelector('#' + this.getConnectionElementId(contextData.id))
|
||||
.getElementsByTagName('table');
|
||||
$(tableEls).hideLoadingAnimation();
|
||||
let connectionEl = this.moduleElement.querySelector('#' + this.getConnectionElementId(contextData.id));
|
||||
// connectionEl might be removed in meantime ( e.g. module removed)
|
||||
if(connectionEl){
|
||||
let tableEls = connectionEl.getElementsByTagName('table');
|
||||
$(tableEls).hideLoadingAnimation();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -351,7 +352,7 @@ define([
|
||||
let scopeLabel = MapUtil.getScopeInfoForConnection(connectionData.scope, 'label');
|
||||
|
||||
let element = document.createElement('div');
|
||||
element.classList.add(Util.config.dynamicAreaClass, this._config.controlAreaClass);
|
||||
element.classList.add(BaseModule.Util.config.dynamicAreaClass, this._config.controlAreaClass);
|
||||
|
||||
$(element).append(
|
||||
$('<table>', {
|
||||
@@ -990,7 +991,7 @@ define([
|
||||
|
||||
if(rowData.active){
|
||||
let confirmationSettings = {
|
||||
title: 'delete jump log',
|
||||
title: '---',
|
||||
template: Util.getConfirmationTemplate(null, {
|
||||
size: 'small',
|
||||
noTitle: true
|
||||
@@ -1251,7 +1252,6 @@ define([
|
||||
|
||||
// body
|
||||
connectionInfoPanelClass: 'pf-connection-info-panel', // class for connection info panels
|
||||
controlAreaClass: 'pf-module-control-area', // class for "control" areas
|
||||
|
||||
// info table
|
||||
moduleTableClass: 'pf-module-table', // class for module tables
|
||||
|
||||
@@ -249,7 +249,7 @@ define([ // dependencies for this module
|
||||
}
|
||||
};
|
||||
|
||||
DemoModule.isPlugin = true; // module is defined as 'plugin'
|
||||
DemoModule.isPlugin = true; // module is defined as 'plugin'
|
||||
DemoModule.scope = 'system'; // module scope controls how module gets updated and what type of data is injected
|
||||
DemoModule.sortArea = 'a'; // default sortable area
|
||||
DemoModule.position = 10; // default sort/order position within sortable area
|
||||
|
||||
1028
public/js/v2.0.0/app/ui/module/global_thera.js
Normal file
1028
public/js/v2.0.0/app/ui/module/global_thera.js
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user