2
.gitignore
vendored
2
.gitignore
vendored
@@ -50,3 +50,5 @@ Temporary Items
|
||||
.sass-cache
|
||||
.usage
|
||||
*.gz
|
||||
/composer-dev.lock
|
||||
/composer.lock
|
||||
|
||||
@@ -26,14 +26,15 @@ DB_CCP_NAME = eve_citadel_min
|
||||
DB_CCP_USER = root
|
||||
DB_CCP_PASS =
|
||||
|
||||
; CCP SSO settings (OAuth2) - visit: https://developers.eveonline.com/applications
|
||||
CCP_CREST_URL = https://api-sisi.testeveonline.com
|
||||
SSO_CCP_URL = https://sisilogin.testeveonline.com
|
||||
SSO_CCP_CLIENT_ID =
|
||||
SSO_CCP_SECRET_KEY =
|
||||
; CCP SSO (OAuth2) - visit: https://developers.eveonline.com/applications
|
||||
CCP_SSO_URL = https://sisilogin.testeveonline.com
|
||||
CCP_SSO_CLIENT_ID =
|
||||
CCP_SSO_SECRET_KEY =
|
||||
|
||||
; CCP XML APIv2
|
||||
CCP_XML = https://api.testeveonline.com
|
||||
; CCP ESI API
|
||||
CCP_ESI_URL = https://esi.tech.ccp.is
|
||||
CCP_ESI_DATASOURCE = singularity
|
||||
CCP_ESI_SCOPES = esi-location.read_location.v1,esi-location.read_ship_type.v1,esi-ui.write_waypoint.v1,esi-ui.open_window.v1
|
||||
|
||||
; SMTP settings (optional)
|
||||
SMTP_HOST = localhost
|
||||
@@ -70,14 +71,15 @@ DB_CCP_NAME =
|
||||
DB_CCP_USER =
|
||||
DB_CCP_PASS =
|
||||
|
||||
; CCP SSO settings
|
||||
CCP_CREST_URL = https://crest-tq.eveonline.com
|
||||
SSO_CCP_URL = https://login.eveonline.com
|
||||
SSO_CCP_CLIENT_ID =
|
||||
SSO_CCP_SECRET_KEY =
|
||||
; CCP SSO
|
||||
CCP_SSO_URL = https://login.eveonline.com
|
||||
CCP_SSO_CLIENT_ID =
|
||||
CCP_SSO_SECRET_KEY =
|
||||
|
||||
; CCP XML APIv2
|
||||
CCP_XML = https://api.eveonline.com
|
||||
; CCP ESI API
|
||||
CCP_ESI_URL = https://esi.tech.ccp.is
|
||||
CCP_ESI_DATASOURCE = tranquility
|
||||
CCP_ESI_SCOPES = esi-location.read_location.v1,esi-location.read_ship_type.v1,esi-ui.write_waypoint.v1,esi-ui.open_window.v1
|
||||
|
||||
; SMTP settings (optional)
|
||||
SMTP_HOST = localhost
|
||||
|
||||
@@ -109,15 +109,18 @@ class Route extends Controller\AccessController {
|
||||
* @param array $filterData
|
||||
*/
|
||||
private function setDynamicJumpData($mapIds = [], $filterData = []){
|
||||
// make sure, mapIds are integers (protect against SQL injections)
|
||||
$mapIds = array_unique( array_map('intval', $mapIds), SORT_NUMERIC);
|
||||
|
||||
if( !empty($mapIds) ){
|
||||
// make sure, mapIds are integers (protect against SQL injections)
|
||||
$mapIds = array_map('intval', $mapIds);
|
||||
// map filter ---------------------------------------------------------------------------------------------
|
||||
$whereMapIdsQuery = (count($mapIds) == 1) ? " = " . reset($mapIds) : " IN (" . implode(', ', $mapIds) . ")";
|
||||
|
||||
// connection filter --------------------------------------------------------
|
||||
// connection filter --------------------------------------------------------------------------------------
|
||||
$whereQuery = "";
|
||||
$includeScopes = [];
|
||||
$includeTypes = [];
|
||||
$excludeTypes = [];
|
||||
$includeEOL = true;
|
||||
|
||||
if( $filterData['stargates'] === true){
|
||||
@@ -147,16 +150,24 @@ class Route extends Controller\AccessController {
|
||||
$includeTypes[] = 'wh_critical';
|
||||
}
|
||||
|
||||
if( $filterData['wormholesFrigate'] !== true ){
|
||||
$excludeTypes[] = 'frigate';
|
||||
}
|
||||
|
||||
if( $filterData['wormholesEOL'] === false ){
|
||||
$includeEOL = false;
|
||||
}
|
||||
}
|
||||
|
||||
// search connections -------------------------------------------------------
|
||||
// search connections -------------------------------------------------------------------------------------
|
||||
|
||||
if( !empty($includeScopes) ){
|
||||
$whereQuery .= " `connection`.`scope` IN ('" . implode("', '", $includeScopes) . "') AND ";
|
||||
|
||||
if( !empty($excludeTypes) ){
|
||||
$whereQuery .= " `connection`.`type` NOT REGEXP '" . implode("|", $excludeTypes) . "' AND ";
|
||||
}
|
||||
|
||||
if( !empty($includeTypes) ){
|
||||
$whereQuery .= " `connection`.`type` REGEXP '" . implode("|", $includeTypes) . "' AND ";
|
||||
}
|
||||
@@ -179,7 +190,7 @@ class Route extends Controller\AccessController {
|
||||
`system_tar`.`id` = `connection`.`source` OR
|
||||
`system_tar`.`id` = `connection`.`target`
|
||||
WHERE
|
||||
`connection`.`mapId` IN (" . implode(', ', $mapIds) . ") AND
|
||||
`connection`.`mapId` " . $whereMapIdsQuery . " AND
|
||||
`connection`.`active` = 1 AND
|
||||
(
|
||||
`connection`.`source` = `system_src`.`id` OR
|
||||
@@ -195,7 +206,7 @@ class Route extends Controller\AccessController {
|
||||
`map` ON
|
||||
`map`.`id` = `system_src`.`mapId`
|
||||
WHERE
|
||||
`system_src`.`mapId` IN (" . implode(', ', $mapIds) . ") AND
|
||||
`system_src`.`mapId` " . $whereMapIdsQuery . " AND
|
||||
`system_src`.`active` = 1 AND
|
||||
`map`.`active` = 1
|
||||
HAVING
|
||||
@@ -228,7 +239,7 @@ class Route extends Controller\AccessController {
|
||||
$systemId = (int)$row['systemId'];
|
||||
$secStatus = (float)$row['trueSec'];
|
||||
|
||||
// fill "nameArray" data ----------------------------------------------------
|
||||
// fill "nameArray" data ----------------------------------------------------------------------------------
|
||||
if( !isset($this->nameArray[$systemId]) ){
|
||||
$this->nameArray[$systemId][0] = $systemName;
|
||||
$this->nameArray[$systemId][1] = $regionId;
|
||||
@@ -236,12 +247,12 @@ class Route extends Controller\AccessController {
|
||||
$this->nameArray[$systemId][3] = $secStatus;
|
||||
}
|
||||
|
||||
// fill "idArray" data ------------------------------------------------------
|
||||
// fill "idArray" data ------------------------------------------------------------------------------------
|
||||
if( !isset($this->idArray[$systemName]) ){
|
||||
$this->idArray[$systemName] = $systemId;
|
||||
}
|
||||
|
||||
// fill "jumpArray" data ----------------------------------------------------
|
||||
// fill "jumpArray" data ----------------------------------------------------------------------------------
|
||||
if( !is_array($this->jumpArray[$systemName]) ){
|
||||
$this->jumpArray[$systemName] = [];
|
||||
}
|
||||
@@ -527,7 +538,7 @@ class Route extends Controller\AccessController {
|
||||
$mapData = (array)$routeData['mapIds'];
|
||||
$mapData = array_flip( array_map('intval', $mapData) );
|
||||
|
||||
// check map access (filter requested mapIDs and format) --------------------
|
||||
// check map access (filter requested mapIDs and format) ----------------------------------------------
|
||||
array_walk($mapData, function(&$item, &$key, $data){
|
||||
|
||||
if( isset($data[1][$key]) ){
|
||||
@@ -561,6 +572,7 @@ class Route extends Controller\AccessController {
|
||||
'wormholes' => (bool) $routeData['wormholes'],
|
||||
'wormholesReduced' => (bool) $routeData['wormholesReduced'],
|
||||
'wormholesCritical' => (bool) $routeData['wormholesCritical'],
|
||||
'wormholesFrigate' => (bool) $routeData['wormholesFrigate'],
|
||||
'wormholesEOL' => (bool) $routeData['wormholesEOL'],
|
||||
'safer' => (bool) $routeData['safer']
|
||||
];
|
||||
|
||||
@@ -130,13 +130,9 @@ class System extends Controller\AccessController {
|
||||
* @return array
|
||||
*/
|
||||
public function getSystems(){
|
||||
|
||||
$ccpDB = $this->getDB('CCP');
|
||||
|
||||
$query = $this->_getQuery();
|
||||
|
||||
$rows = $ccpDB->exec($query, null, 60 * 60 * 24);
|
||||
|
||||
// format result
|
||||
$mapper = new Mapper\CcpSystemsMapper($rows);
|
||||
|
||||
@@ -385,20 +381,25 @@ class System extends Controller\AccessController {
|
||||
$return->clearOtherWaypoints = (bool)$postData['clearOtherWaypoints'];
|
||||
$return->first = (bool)$postData['first'];
|
||||
|
||||
/**
|
||||
* @var Sso $ssoController
|
||||
*/
|
||||
$ssoController = self::getController('Sso');
|
||||
foreach($postData['systemData'] as $systemData){
|
||||
$waypointData = $ssoController->setWaypoint($activeCharacter, $systemData['systemId'], [
|
||||
if( $accessToken = $activeCharacter->getAccessToken() ){
|
||||
$options = [
|
||||
'clearOtherWaypoints' => $return->clearOtherWaypoints,
|
||||
'first' => $return->first,
|
||||
]);
|
||||
if($waypointData['systemId']){
|
||||
$return->systemData[] = $systemData;
|
||||
}elseif( isset($waypointData['error']) ){
|
||||
$return->error[] = $waypointData['error'];
|
||||
'addToBeginning' => $return->first,
|
||||
];
|
||||
|
||||
foreach($postData['systemData'] as $systemData){
|
||||
$response = $f3->ccpClient->setWaypoint($systemData['systemId'], $accessToken, $options);
|
||||
|
||||
if(empty($response)){
|
||||
$return->systemData[] = $systemData;
|
||||
}else{
|
||||
$error = (object) [];
|
||||
$error->type = 'error';
|
||||
$error->message = $response['error'];
|
||||
$return->error[] = $error;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,14 +429,14 @@ class System extends Controller\AccessController {
|
||||
if( $system = $map->getSystemById($systemId) ){
|
||||
// check whether system should be deleted OR set "inactive"
|
||||
if(
|
||||
empty($system->alias) &&
|
||||
empty($system->description)
|
||||
!empty($system->description) ||
|
||||
( !empty($system->alias) && ($system->alias != $system->name) )
|
||||
){
|
||||
$system->erase();
|
||||
}else{
|
||||
// keep data -> set "inactive"
|
||||
$system->setActive(false);
|
||||
$system->save();
|
||||
}else{
|
||||
$system->erase();
|
||||
}
|
||||
|
||||
$system->reset();
|
||||
@@ -452,23 +453,3 @@ class System extends Controller\AccessController {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ class User extends Controller\Controller{
|
||||
}else{
|
||||
$characterError = (object) [];
|
||||
$characterError->type = 'warning';
|
||||
$characterError->message = 'This can happen through "invalid cookie data", "login restrictions", "CREST problems".';
|
||||
$characterError->message = 'This can happen through "invalid cookies(SSO)", "login restrictions", "ESI problems".';
|
||||
$return->error[] = $characterError;
|
||||
}
|
||||
}
|
||||
@@ -196,10 +196,39 @@ class User extends Controller\Controller{
|
||||
echo json_encode($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* remote open ingame information window (character, corporation or alliance) Id
|
||||
* -> the type is auto-recognized by CCP
|
||||
* @param \Base $f3
|
||||
*/
|
||||
public function openIngameWindow(\Base $f3){
|
||||
$data = $f3->get('POST');
|
||||
|
||||
$return = (object) [];
|
||||
$return->error = [];
|
||||
|
||||
if( $targetId = (int)$data['targetId']){
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
$response = $f3->ccpClient->openWindow($targetId, $activeCharacter->getAccessToken());
|
||||
|
||||
if(empty($response)){
|
||||
$return->targetId = $targetId;
|
||||
}else{
|
||||
$error = (object) [];
|
||||
$error->type = 'error';
|
||||
$error->message = $response['error'];
|
||||
$return->error[] = $error;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* update user account data
|
||||
* -> a fresh user automatically generated on first login with a new character
|
||||
* -> see CREST SSO login
|
||||
* -> see SSO login
|
||||
* @param \Base $f3
|
||||
*/
|
||||
public function saveAccount(\Base $f3){
|
||||
@@ -340,25 +369,23 @@ class User extends Controller\Controller{
|
||||
$user = $activeCharacter->getUser();
|
||||
|
||||
if($user){
|
||||
// send delete account mail
|
||||
// try to send delete account mail
|
||||
$msg = 'Hello ' . $user->name . ',<br><br>';
|
||||
$msg .= 'your account data has been successfully deleted.';
|
||||
|
||||
$mailController = new MailController();
|
||||
$status = $mailController->sendDeleteAccount($user->email, $msg);
|
||||
$mailController->sendDeleteAccount($user->email, $msg);
|
||||
|
||||
if($status){
|
||||
// save log
|
||||
self::getLogger('DELETE_ACCOUNT')->write(
|
||||
sprintf(self::LOG_DELETE_ACCOUNT, $user->id, $user->name)
|
||||
);
|
||||
// save log
|
||||
self::getLogger('DELETE_ACCOUNT')->write(
|
||||
sprintf(self::LOG_DELETE_ACCOUNT, $user->id, $user->name)
|
||||
);
|
||||
|
||||
// remove user
|
||||
$user->erase();
|
||||
// remove user
|
||||
$user->erase();
|
||||
|
||||
$this->logout($f3);
|
||||
die();
|
||||
}
|
||||
$this->logout($f3);
|
||||
die();
|
||||
}
|
||||
}else{
|
||||
// captcha not valid -> return error
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* Date: 23.01.2016
|
||||
* Time: 17:18
|
||||
*
|
||||
* Handles access to EVE-Online "CREST API" and "SSO" auth functions
|
||||
* Handles access to EVE-Online "ESI API" and "SSO" auth functions
|
||||
* - Add your API credentials in "environment.ini"
|
||||
* - Check "PATHFINDER.API" in "pathfinder.ini" for correct API URLs
|
||||
* Hint: \Web::instance()->request automatically caches responses by their response "Cache-Control" header!
|
||||
@@ -14,7 +14,6 @@
|
||||
namespace Controller\Ccp;
|
||||
use Controller;
|
||||
use Controller\Api as Api;
|
||||
use Data\Mapper as Mapper;
|
||||
use Model;
|
||||
use Lib;
|
||||
|
||||
@@ -23,7 +22,7 @@ class Sso extends Api\User{
|
||||
/**
|
||||
* @var int timeout (seconds) for API calls
|
||||
*/
|
||||
const CREST_TIMEOUT = 4;
|
||||
const SSO_TIMEOUT = 4;
|
||||
|
||||
/**
|
||||
* @var int expire time (seconds) for an valid "accessToken"
|
||||
@@ -37,32 +36,16 @@ class Sso extends Api\User{
|
||||
const SESSION_KEY_SSO_FROM_MAP = 'SESSION.SSO.FROM_MAP';
|
||||
|
||||
// error messages
|
||||
const ERROR_CCP_SSO_URL = 'Invalid "ENVIRONMENT.[ENVIRONMENT].SSO_CCP_URL" url. %s';
|
||||
const ERROR_CCP_CREST_URL = 'Invalid "ENVIRONMENT.[ENVIRONMENT].CCP_CREST_URL" url. %s';
|
||||
const ERROR_CCP_CLIENT_ID = 'Missing "ENVIRONMENT.[ENVIRONMENT].SSO_CCP_CLIENT_ID".';
|
||||
const ERROR_RESOURCE_DEPRECATED = 'Resource: %s has been marked as deprecated. %s';
|
||||
const ERROR_CCP_SSO_URL = 'Invalid "ENVIRONMENT.[ENVIRONMENT].CCP_SSO_URL" url. %s';
|
||||
const ERROR_CCP_CLIENT_ID = 'Missing "ENVIRONMENT.[ENVIRONMENT].CCP_SSO_CLIENT_ID".';
|
||||
const ERROR_ACCESS_TOKEN = 'Unable to get a valid "access_token. %s';
|
||||
const ERROR_VERIFY_CHARACTER = 'Unable to verify character data. %s';
|
||||
const ERROR_GET_ENDPOINT = 'Unable to get endpoint data. $s';
|
||||
const ERROR_FIND_ENDPOINT = 'Unable to find endpoint: %s';
|
||||
const ERROR_LOGIN_FAILED = 'Failed authentication due to technical problems: %s';
|
||||
const ERROR_CHARACTER_VERIFICATION = 'Character verification failed from CREST';
|
||||
const ERROR_CHARACTER_VERIFICATION = 'Character verification failed by SSP SSO';
|
||||
const ERROR_CHARACTER_FORBIDDEN = 'Character "%s" is not authorized to log in';
|
||||
const ERROR_SERVICE_TIMEOUT = 'CCP SSO service timeout (%ss). Try again later';
|
||||
const ERROR_COOKIE_LOGIN = 'Login from Cookie failed. Please retry by CCP SSO';
|
||||
|
||||
/**
|
||||
* CREST "Scopes" are used by pathfinder
|
||||
* -> Enable scopes: https://developers.eveonline.com
|
||||
* @var array
|
||||
*/
|
||||
private $requestScopes = [
|
||||
// 'characterFittingsRead',
|
||||
// 'characterFittingsWrite',
|
||||
'characterLocationRead',
|
||||
'characterNavigationWrite'
|
||||
];
|
||||
|
||||
/**
|
||||
* redirect user to CCP SSO page and request authorization
|
||||
* -> cf. Controller->getCookieCharacters() ( equivalent cookie based login)
|
||||
@@ -70,7 +53,7 @@ class Sso extends Api\User{
|
||||
*/
|
||||
public function requestAuthorization($f3){
|
||||
|
||||
if( !empty($ssoCcpClientId = Controller\Controller::getEnvironmentData('SSO_CCP_CLIENT_ID')) ){
|
||||
if( !empty($ssoCcpClientId = Controller\Controller::getEnvironmentData('CCP_SSO_CLIENT_ID')) ){
|
||||
$params = $f3->get('GET');
|
||||
|
||||
if(
|
||||
@@ -94,8 +77,8 @@ class Sso extends Api\User{
|
||||
($activeCharacter->getUser()->_id === $character->getUser()->_id)
|
||||
){
|
||||
// requested character belongs to current user
|
||||
// -> update character vom CREST (e.g. corp changed,..)
|
||||
$updateStatus = $character->updateFromCrest();
|
||||
// -> update character vom ESI (e.g. corp changed,..)
|
||||
$updateStatus = $character->updateFromESI();
|
||||
|
||||
if( empty($updateStatus) ){
|
||||
|
||||
@@ -111,7 +94,7 @@ class Sso extends Api\User{
|
||||
|
||||
if($loginCheck){
|
||||
// set "login" cookie
|
||||
$this->setLoginCookie($character);
|
||||
$this->setLoginCookie($character, $this->getRequestedScopeHash());
|
||||
|
||||
// -> pass current character data to target page
|
||||
$f3->set(Api\User::SESSION_KEY_TEMP_CHARACTER_ID, $character->_id);
|
||||
@@ -135,9 +118,9 @@ class Sso extends Api\User{
|
||||
|
||||
$urlParams = [
|
||||
'response_type' => 'code',
|
||||
'redirect_uri' => Controller\Controller::getEnvironmentData('URL') . $f3->build('/sso/callbackAuthorization'),
|
||||
'client_id' => Controller\Controller::getEnvironmentData('SSO_CCP_CLIENT_ID'),
|
||||
'scope' => implode(' ', $this->requestScopes),
|
||||
'redirect_uri' => Controller\Controller::getEnvironmentData('URL') . Controller\Controller::getEnvironmentData('BASE') . $f3->build('/sso/callbackAuthorization'),
|
||||
'client_id' => Controller\Controller::getEnvironmentData('CCP_SSO_CLIENT_ID'),
|
||||
'scope' => implode(' ', Controller\Controller::getEnvironmentData('CCP_ESI_SCOPES')),
|
||||
'state' => $state
|
||||
];
|
||||
|
||||
@@ -149,7 +132,7 @@ class Sso extends Api\User{
|
||||
}else{
|
||||
// SSO clientId missing
|
||||
$f3->set(self::SESSION_KEY_SSO_ERROR, self::ERROR_CCP_CLIENT_ID);
|
||||
self::getCrestLogger()->write(self::ERROR_CCP_CLIENT_ID);
|
||||
self::getSSOLogger()->write(self::ERROR_CCP_CLIENT_ID);
|
||||
$f3->reroute('@login');
|
||||
}
|
||||
}
|
||||
@@ -184,7 +167,7 @@ class Sso extends Api\User{
|
||||
$f3->clear(self::SESSION_KEY_SSO_STATE);
|
||||
$f3->clear(self::SESSION_KEY_SSO_FROM_MAP);
|
||||
|
||||
$accessData = $this->getCrestAccessData($getParams['code']);
|
||||
$accessData = $this->getSsoAccessData($getParams['code']);
|
||||
|
||||
if(
|
||||
isset($accessData->accessToken) &&
|
||||
@@ -199,11 +182,11 @@ class Sso extends Api\User{
|
||||
|
||||
// verification available data. Data is needed for "ownerHash" check
|
||||
|
||||
// get character data from CREST
|
||||
$characterData = $this->getCharacterData($accessData->accessToken);
|
||||
// get character data from ESI
|
||||
$characterData = $this->getCharacterData($verificationCharacterData->CharacterID);
|
||||
|
||||
if( isset($characterData->character) ){
|
||||
// add "ownerHash" and CREST tokens
|
||||
// add "ownerHash" and SSO tokens
|
||||
$characterData->character['ownerHash'] = $verificationCharacterData->CharacterOwnerHash;
|
||||
$characterData->character['crestAccessToken'] = $accessData->accessToken;
|
||||
$characterData->character['crestRefreshToken'] = $accessData->refreshToken;
|
||||
@@ -253,7 +236,7 @@ class Sso extends Api\User{
|
||||
|
||||
if($loginCheck){
|
||||
// set "login" cookie
|
||||
$this->setLoginCookie($characterModel);
|
||||
$this->setLoginCookie($characterModel, $this->getRequestedScopeHash());
|
||||
|
||||
// -> pass current character data to target page
|
||||
$f3->set(Api\User::SESSION_KEY_TEMP_CHARACTER_ID, $characterModel->_id);
|
||||
@@ -270,15 +253,15 @@ class Sso extends Api\User{
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// failed to verify character by CREST
|
||||
// failed to verify character by CCP SSO
|
||||
$f3->set(self::SESSION_KEY_SSO_ERROR, self::ERROR_CHARACTER_VERIFICATION);
|
||||
}
|
||||
}else{
|
||||
// CREST "accessData" missing (e.g. timeout)
|
||||
$f3->set(self::SESSION_KEY_SSO_ERROR, sprintf(self::ERROR_SERVICE_TIMEOUT, self::CREST_TIMEOUT));
|
||||
// SSO "accessData" missing (e.g. timeout)
|
||||
$f3->set(self::SESSION_KEY_SSO_ERROR, sprintf(self::ERROR_SERVICE_TIMEOUT, self::SSO_TIMEOUT));
|
||||
}
|
||||
}else{
|
||||
// invalid CREST response
|
||||
// invalid SSO response
|
||||
$f3->set(self::SESSION_KEY_SSO_ERROR, sprintf(self::ERROR_LOGIN_FAILED, 'Invalid response'));
|
||||
}
|
||||
}
|
||||
@@ -337,7 +320,7 @@ class Sso extends Api\User{
|
||||
* @param bool $authCode
|
||||
* @return null|\stdClass
|
||||
*/
|
||||
public function getCrestAccessData($authCode){
|
||||
public function getSsoAccessData($authCode){
|
||||
$accessData = null;
|
||||
|
||||
if( !empty($authCode) ){
|
||||
@@ -345,7 +328,7 @@ class Sso extends Api\User{
|
||||
$accessData = $this->verifyAuthorizationCode($authCode);
|
||||
}else{
|
||||
// Unable to get Token -> trigger error
|
||||
self::getCrestLogger()->write(sprintf(self::ERROR_ACCESS_TOKEN, $authCode));
|
||||
self::getSSOLogger()->write(sprintf(self::ERROR_ACCESS_TOKEN, $authCode));
|
||||
}
|
||||
|
||||
return $accessData;
|
||||
@@ -398,7 +381,7 @@ class Sso extends Api\User{
|
||||
if($verifyAuthCodeUrlParts){
|
||||
$contentType = 'application/x-www-form-urlencoded';
|
||||
$requestOptions = [
|
||||
'timeout' => self::CREST_TIMEOUT,
|
||||
'timeout' => self::SSO_TIMEOUT,
|
||||
'method' => 'POST',
|
||||
'user_agent' => $this->getUserAgent(),
|
||||
'header' => [
|
||||
@@ -428,7 +411,7 @@ class Sso extends Api\User{
|
||||
}
|
||||
}
|
||||
}else{
|
||||
self::getCrestLogger()->write(
|
||||
self::getSSOLogger()->write(
|
||||
sprintf(
|
||||
self::ERROR_ACCESS_TOKEN,
|
||||
print_r($requestParams, true)
|
||||
@@ -436,7 +419,7 @@ class Sso extends Api\User{
|
||||
);
|
||||
}
|
||||
}else{
|
||||
self::getCrestLogger()->write(
|
||||
self::getSSOLogger()->write(
|
||||
sprintf(self::ERROR_CCP_SSO_URL, __METHOD__)
|
||||
);
|
||||
}
|
||||
@@ -447,7 +430,7 @@ class Sso extends Api\User{
|
||||
/**
|
||||
* verify character data by "access_token"
|
||||
* -> get some basic information (like character id)
|
||||
* -> if more character information is required, use CREST endpoints request instead
|
||||
* -> if more character information is required, use ESI "characters" endpoints request instead
|
||||
* @param $accessToken
|
||||
* @return mixed|null
|
||||
*/
|
||||
@@ -458,7 +441,7 @@ class Sso extends Api\User{
|
||||
|
||||
if($verifyUrlParts){
|
||||
$requestOptions = [
|
||||
'timeout' => self::CREST_TIMEOUT,
|
||||
'timeout' => self::SSO_TIMEOUT,
|
||||
'method' => 'GET',
|
||||
'user_agent' => $this->getUserAgent(),
|
||||
'header' => [
|
||||
@@ -472,271 +455,83 @@ class Sso extends Api\User{
|
||||
if($apiResponse['body']){
|
||||
$characterData = json_decode($apiResponse['body']);
|
||||
}else{
|
||||
self::getCrestLogger()->write(sprintf(self::ERROR_VERIFY_CHARACTER, __METHOD__));
|
||||
self::getSSOLogger()->write(sprintf(self::ERROR_VERIFY_CHARACTER, __METHOD__));
|
||||
}
|
||||
}else{
|
||||
self::getCrestLogger()->write(sprintf(self::ERROR_CCP_SSO_URL, __METHOD__));
|
||||
self::getSSOLogger()->write(sprintf(self::ERROR_CCP_SSO_URL, __METHOD__));
|
||||
}
|
||||
|
||||
return $characterData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all available Endpoints
|
||||
* @param $accessToken
|
||||
* @param array $additionalOptions
|
||||
* @return mixed|null
|
||||
*/
|
||||
protected function getEndpoints($accessToken = '', $additionalOptions = []){
|
||||
$crestUrl = self::getCrestEndpoint();
|
||||
$additionalOptions['accept'] = 'application/vnd.ccp.eve.Api-v5+json';
|
||||
$endpoint = $this->getEndpoint($crestUrl, $accessToken, $additionalOptions);
|
||||
|
||||
return $endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a specific endpoint by its $resourceUrl
|
||||
* @param string $resourceUrl endpoint API url
|
||||
* @param string $accessToken CREST access token
|
||||
* @param array $additionalOptions optional request options (pathfinder specific)
|
||||
* @return mixed|null
|
||||
*/
|
||||
protected function getEndpoint($resourceUrl, $accessToken = '', $additionalOptions = []){
|
||||
$resourceUrlParts = parse_url($resourceUrl);
|
||||
$endpoint = null;
|
||||
|
||||
if($resourceUrlParts){
|
||||
$requestOptions = [
|
||||
'timeout' => self::CREST_TIMEOUT,
|
||||
'method' => 'GET',
|
||||
'user_agent' => $this->getUserAgent(),
|
||||
'header' => [
|
||||
'Host: login.eveonline.com',
|
||||
'Host: ' . $resourceUrlParts['host']
|
||||
]
|
||||
];
|
||||
|
||||
// some endpoints don´t require an "access_token" (e.g. public crest data)
|
||||
if( !empty($accessToken) ){
|
||||
$requestOptions['header'][] = 'Authorization: Bearer ' . $accessToken;
|
||||
}
|
||||
|
||||
// if specific contentType is required -> add it to request header
|
||||
// CREST versioning can be done by calling different "Accept:" Headers
|
||||
if( isset($additionalOptions['accept']) ){
|
||||
$requestOptions['header'][] = 'Accept: ' . $additionalOptions['accept'];
|
||||
}
|
||||
|
||||
$apiResponse = Lib\Web::instance()->request($resourceUrl, $requestOptions, $additionalOptions);
|
||||
|
||||
if(
|
||||
$apiResponse['timeout'] === false &&
|
||||
$apiResponse['headers']
|
||||
){
|
||||
// check headers for error
|
||||
$this->checkResponseHeaders($apiResponse['headers'], $requestOptions);
|
||||
|
||||
if($apiResponse['body']){
|
||||
$endpoint = json_decode($apiResponse['body'], true);
|
||||
}else{
|
||||
self::getCrestLogger()->write(sprintf(self::ERROR_GET_ENDPOINT, __METHOD__));
|
||||
}
|
||||
}
|
||||
}else{
|
||||
self::getCrestLogger()->write(sprintf(self::ERROR_CCP_CREST_URL, __METHOD__));
|
||||
}
|
||||
|
||||
return $endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* recursively walk down the CREST API tree by a given $path array
|
||||
* -> return "leaf" endpoint
|
||||
* @param $endpoint
|
||||
* @param $accessToken
|
||||
* @param array $path
|
||||
* @param array $additionalOptions
|
||||
* @return null
|
||||
*/
|
||||
protected function walkEndpoint($endpoint, $accessToken, $path = [], $additionalOptions = []){
|
||||
$targetEndpoint = null;
|
||||
|
||||
if( !empty($path) ){
|
||||
$newNode = array_shift($path);
|
||||
if(isset($endpoint[$newNode])){
|
||||
$currentEndpoint = $endpoint[$newNode];
|
||||
if(isset($currentEndpoint['href'])){
|
||||
$newEndpoint = $this->getEndpoint($currentEndpoint['href'], $accessToken, $additionalOptions);
|
||||
$targetEndpoint = $this->walkEndpoint($newEndpoint, $accessToken, $path, $additionalOptions);
|
||||
}else{
|
||||
// leaf found
|
||||
$targetEndpoint = $currentEndpoint;
|
||||
}
|
||||
}else{
|
||||
// endpoint not found
|
||||
self::getCrestLogger()->write(sprintf(self::ERROR_FIND_ENDPOINT, $newNode));
|
||||
}
|
||||
}else{
|
||||
$targetEndpoint = $endpoint;
|
||||
}
|
||||
|
||||
return $targetEndpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* get character data
|
||||
* @param $accessToken
|
||||
* @param array $additionalOptions
|
||||
* @param int $characterId
|
||||
* @return object
|
||||
*/
|
||||
public function getCharacterData($accessToken, $additionalOptions = []){
|
||||
$endpoints = $this->getEndpoints($accessToken, $additionalOptions);
|
||||
public function getCharacterData($characterId){
|
||||
$characterData = (object) [];
|
||||
|
||||
$endpoint = $this->walkEndpoint($endpoints, $accessToken, [
|
||||
'decode',
|
||||
'character'
|
||||
], $additionalOptions);
|
||||
$characterDataBasic = $this->getF3()->ccpClient->getCharacterData($characterId);
|
||||
|
||||
if( !empty($endpoint) ){
|
||||
$crestCharacterData = (new Mapper\CrestCharacter($endpoint))->getData();
|
||||
$characterData->character = $crestCharacterData
|
||||
;
|
||||
if(isset($endpoint['corporation'])){
|
||||
$characterData->corporation = (new Mapper\CrestCorporation($endpoint['corporation']))->getData();
|
||||
}
|
||||
if( !empty($characterDataBasic) ){
|
||||
// remove some "unwanted" data -> not relevant for Pathfinder
|
||||
$characterData->character = array_filter($characterDataBasic, function($key){
|
||||
return in_array($key, ['id', 'name', 'securityStatus']);
|
||||
}, ARRAY_FILTER_USE_KEY);
|
||||
|
||||
// IMPORTANT: alliance data is not yet available over CREST!
|
||||
// -> we need to request them over the XML api
|
||||
/*
|
||||
if(isset($endpoint['alliance'])){
|
||||
$characterData->alliance = (new Mapper\CrestAlliance($endpoint['alliance']))->getData();
|
||||
}
|
||||
*/
|
||||
$characterData->corporation = null;
|
||||
$characterData->alliance = null;
|
||||
|
||||
$xmlCharacterData = (new Xml())->getPublicCharacterData( (int)$crestCharacterData['id'] );
|
||||
if(isset($xmlCharacterData['alli'])){
|
||||
$characterData->alliance = $xmlCharacterData['alli'];
|
||||
}
|
||||
}
|
||||
if(isset($characterDataBasic['corporation'])){
|
||||
$corporationId = (int)$characterDataBasic['corporation']['id'];
|
||||
|
||||
return $characterData;
|
||||
}
|
||||
/**
|
||||
* @var Model\CorporationModel $corporationModel
|
||||
*/
|
||||
$corporationModel = Model\BasicModel::getNew('CorporationModel');
|
||||
$corporationModel->getById($corporationId, 0);
|
||||
|
||||
/**
|
||||
* get current character location data (result is cached!)
|
||||
* -> solarSystem data where character is currently active
|
||||
* @param $accessToken
|
||||
* @param array $additionalOptions
|
||||
* @return array
|
||||
*/
|
||||
public function getCharacterLocationData($accessToken, $additionalOptions = []){
|
||||
// null == CREST call failed (e.g. timeout)
|
||||
$locationData = [
|
||||
'timeout' => false
|
||||
];
|
||||
if($corporationModel->dry()){
|
||||
// request corporation data
|
||||
$corporationData = $this->getF3()->ccpClient->getCorporationData($corporationId);
|
||||
|
||||
$endpoints = $this->getEndpoints($accessToken, $additionalOptions);
|
||||
if( !empty($corporationData) ){
|
||||
// check for NPC corporation
|
||||
$corporationData['isNPC'] = $this->getF3()->ccpClient->isNpcCorporation($corporationId);
|
||||
|
||||
$additionalOptions['accept'] = 'application/vnd.ccp.eve.CharacterLocation-v1+json';
|
||||
$endpoint = $this->walkEndpoint($endpoints, $accessToken, [
|
||||
'decode',
|
||||
'character',
|
||||
'location'
|
||||
], $additionalOptions);
|
||||
|
||||
if( !is_null($endpoint) ){
|
||||
// request succeeded (e.g. no timeout)
|
||||
if(isset($endpoint['solarSystem'])){
|
||||
$locationData['system'] = (new Mapper\CrestSystem($endpoint['solarSystem']))->getData();
|
||||
}
|
||||
|
||||
if(isset($endpoint['station'])){
|
||||
$locationData['station'] = (new Mapper\CrestStation($endpoint['station']))->getData();
|
||||
}
|
||||
}else{
|
||||
// timeout
|
||||
$locationData['timeout'] = true;
|
||||
}
|
||||
|
||||
return $locationData;
|
||||
}
|
||||
|
||||
/**
|
||||
* set new ingame waypoint
|
||||
* @param Model\CharacterModel $character
|
||||
* @param int $systemId
|
||||
* @param array $options
|
||||
* @return array
|
||||
*/
|
||||
public function setWaypoint( Model\CharacterModel $character, $systemId, $options = []){
|
||||
$crestUrlParts = parse_url( self::getCrestEndpoint() );
|
||||
$waypointData = [];
|
||||
|
||||
if( $crestUrlParts ){
|
||||
$accessToken = $character->getAccessToken();
|
||||
$endpoints = $this->getEndpoints($accessToken);
|
||||
|
||||
// get endpoint list for "ui" endpoints
|
||||
$uiEndpoints = $endpoint = $this->walkEndpoint($endpoints, $accessToken, [
|
||||
'decode',
|
||||
'character',
|
||||
'ui'
|
||||
]);
|
||||
|
||||
if(
|
||||
isset($uiEndpoints['setWaypoints']) &&
|
||||
isset($uiEndpoints['setWaypoints']['href'])
|
||||
){
|
||||
$endpointUrl = $uiEndpoints['setWaypoints']['href'];
|
||||
$systemEndpoint = self::getCrestEndpoint() . '/solarsystems/' . $systemId . '/';
|
||||
|
||||
// request body
|
||||
$content = [
|
||||
'clearOtherWaypoints' => (bool)$options['clearOtherWaypoints'],
|
||||
'first' => (bool)$options['first'],
|
||||
'solarSystem' => [
|
||||
'href' => $systemEndpoint,
|
||||
'id' => (int)$systemId
|
||||
]
|
||||
];
|
||||
|
||||
$requestOptions = [
|
||||
'timeout' => self::CREST_TIMEOUT,
|
||||
'method' => 'POST',
|
||||
'user_agent' => $this->getUserAgent(),
|
||||
'header' => [
|
||||
'Scope: characterNavigationWrite',
|
||||
'Authorization: Bearer ' . $character->getAccessToken(),
|
||||
'Host: ' . $crestUrlParts['host'],
|
||||
'Content-Type: application/vnd.ccp.eve.PostWaypoint-v1+json;charset=utf-8',
|
||||
],
|
||||
'content' => json_encode($content, JSON_UNESCAPED_SLASHES)
|
||||
];
|
||||
|
||||
$apiResponse = Lib\Web::instance()->request($endpointUrl, $requestOptions);
|
||||
|
||||
if( isset($apiResponse['body']) ){
|
||||
$responseData = json_decode($apiResponse['body']);
|
||||
|
||||
if( empty($responseData) ){
|
||||
$waypointData['systemId'] = (int)$systemId;
|
||||
}elseif(
|
||||
isset($responseData->message) &&
|
||||
isset($responseData->key)
|
||||
){
|
||||
// waypoint could not be set...
|
||||
$error = (object) [];
|
||||
$error->type = 'error';
|
||||
$error->message = $responseData->key;
|
||||
$waypointData['error'] = $error;
|
||||
$corporationModel->copyfrom($corporationData, ['id', 'name', 'isNPC']);
|
||||
$characterData->corporation = $corporationModel->save();
|
||||
}
|
||||
}else{
|
||||
$characterData->corporation = $corporationModel;
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($characterDataBasic['alliance'])){
|
||||
$allianceId = (int)$characterDataBasic['alliance']['id'];
|
||||
|
||||
/**
|
||||
* @var Model\AllianceModel $allianceModel
|
||||
*/
|
||||
$allianceModel = Model\BasicModel::getNew('AllianceModel');
|
||||
$allianceModel->getById($allianceId, 0);
|
||||
|
||||
if($allianceModel->dry()){
|
||||
// request alliance data
|
||||
$allianceData = $this->getF3()->ccpClient->getAllianceData($allianceId);
|
||||
|
||||
if( !empty($allianceData) ){
|
||||
$allianceModel->copyfrom($allianceData, ['id', 'name']);
|
||||
$characterData->alliance = $allianceModel->save();
|
||||
}
|
||||
}else{
|
||||
$characterData->alliance = $allianceModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $waypointData;
|
||||
return $characterData;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -746,96 +541,24 @@ class Sso extends Api\User{
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function updateCharacter($characterData){
|
||||
|
||||
$characterModel = null;
|
||||
$corporationModel = null;
|
||||
$allianceModel = null;
|
||||
|
||||
if( isset($characterData->corporation) ){
|
||||
/**
|
||||
* @var Model\CorporationModel $corporationModel
|
||||
*/
|
||||
$corporationModel = Model\BasicModel::getNew('CorporationModel');
|
||||
$corporationModel->getById((int)$characterData->corporation['id'], 0);
|
||||
$corporationModel->copyfrom($characterData->corporation);
|
||||
$corporationModel->save();
|
||||
}
|
||||
if( !empty($characterData->character) ){
|
||||
|
||||
if( isset($characterData->alliance) ){
|
||||
/**
|
||||
* @var Model\AllianceModel $allianceModel
|
||||
*/
|
||||
$allianceModel = Model\BasicModel::getNew('AllianceModel');
|
||||
$allianceModel->getById((int)$characterData->alliance['id'], 0);
|
||||
$allianceModel->copyfrom($characterData->alliance);
|
||||
$allianceModel->save();
|
||||
}
|
||||
|
||||
if( isset($characterData->character) ){
|
||||
/**
|
||||
* @var Model\CharacterModel $characterModel
|
||||
*/
|
||||
$characterModel = Model\BasicModel::getNew('CharacterModel');
|
||||
$characterModel->getById((int)$characterData->character['id'], 0);
|
||||
$characterModel->copyfrom($characterData->character);
|
||||
$characterModel->corporationId = $corporationModel;
|
||||
$characterModel->allianceId = $allianceModel;
|
||||
$characterModel->copyfrom($characterData->character, ['id', 'name', 'ownerHash', 'crestAccessToken', 'crestRefreshToken', 'securityStatus']);
|
||||
$characterModel->corporationId = $characterData->corporation;
|
||||
$characterModel->allianceId = $characterData->alliance;
|
||||
$characterModel = $characterModel->save();
|
||||
}
|
||||
|
||||
return $characterModel;
|
||||
}
|
||||
|
||||
/**
|
||||
* get CREST server status (online/offline)
|
||||
* @return \stdClass object
|
||||
*/
|
||||
public function getCrestServerStatus(){
|
||||
$endpoints = $this->getEndpoints();
|
||||
|
||||
// set default status e.g. Endpoints don´t work
|
||||
$data = (object) [];
|
||||
$data->crestOffline = true;
|
||||
$data->serverName = 'EVE ONLINE';
|
||||
$data->serviceStatus = [
|
||||
'eve' => 'offline',
|
||||
'server' => 'offline',
|
||||
];
|
||||
$data->userCounts = [
|
||||
'eve' => 0
|
||||
];
|
||||
|
||||
$endpoint = $this->walkEndpoint($endpoints, '', ['serverName']);
|
||||
if( !empty($endpoint) ){
|
||||
$data->crestOffline = false;
|
||||
$data->serverName = (string) $endpoint;
|
||||
}
|
||||
$endpoint = $this->walkEndpoint($endpoints, '', ['serviceStatus']);
|
||||
if( !empty($endpoint) ){
|
||||
$data->crestOffline = false;
|
||||
$data->serviceStatus = (string) $endpoint;
|
||||
}
|
||||
$endpoint = $this->walkEndpoint($endpoints, '', ['userCount_str']);
|
||||
if( !empty($endpoint) ){
|
||||
$data->crestOffline = false;
|
||||
$data->userCounts = (string) $endpoint;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* check response "Header" data for errors
|
||||
* @param $headers
|
||||
* @param string $requestUrl
|
||||
* @param string $contentType
|
||||
*/
|
||||
protected function checkResponseHeaders($headers, $requestUrl = '', $contentType = ''){
|
||||
$headers = (array)$headers;
|
||||
if( preg_grep('/^X-Deprecated/i', $headers) ){
|
||||
self::getCrestLogger()->write(sprintf(self::ERROR_RESOURCE_DEPRECATED, $requestUrl, $contentType));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get "Authorization:" Header data
|
||||
* -> This header is required for any Auth-required endpoints!
|
||||
@@ -843,29 +566,11 @@ class Sso extends Api\User{
|
||||
*/
|
||||
protected function getAuthorizationHeader(){
|
||||
return base64_encode(
|
||||
Controller\Controller::getEnvironmentData('SSO_CCP_CLIENT_ID') . ':'
|
||||
. Controller\Controller::getEnvironmentData('SSO_CCP_SECRET_KEY')
|
||||
Controller\Controller::getEnvironmentData('CCP_SSO_CLIENT_ID') . ':'
|
||||
. Controller\Controller::getEnvironmentData('CCP_SSO_SECRET_KEY')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get CCP CREST url from configuration file
|
||||
* -> throw error if url is broken/missing
|
||||
* @return string
|
||||
*/
|
||||
static function getCrestEndpoint(){
|
||||
$url = '';
|
||||
if( \Audit::instance()->url(self::getEnvironmentData('CCP_CREST_URL')) ){
|
||||
$url = self::getEnvironmentData('CCP_CREST_URL');
|
||||
}else{
|
||||
$error = sprintf(self::ERROR_CCP_CREST_URL, __METHOD__);
|
||||
self::getCrestLogger()->write($error);
|
||||
\Base::instance()->error(502, $error);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* get CCP SSO url from configuration file
|
||||
* -> throw error if url is broken/missing
|
||||
@@ -873,11 +578,11 @@ class Sso extends Api\User{
|
||||
*/
|
||||
static function getSsoUrlRoot(){
|
||||
$url = '';
|
||||
if( \Audit::instance()->url(self::getEnvironmentData('SSO_CCP_URL')) ){
|
||||
$url = self::getEnvironmentData('SSO_CCP_URL');
|
||||
if( \Audit::instance()->url(self::getEnvironmentData('CCP_SSO_URL')) ){
|
||||
$url = self::getEnvironmentData('CCP_SSO_URL');
|
||||
}else{
|
||||
$error = sprintf(self::ERROR_CCP_SSO_URL, __METHOD__);
|
||||
self::getCrestLogger()->write($error);
|
||||
self::getSSOLogger()->write($error);
|
||||
\Base::instance()->error(502, $error);
|
||||
}
|
||||
|
||||
@@ -897,10 +602,10 @@ class Sso extends Api\User{
|
||||
}
|
||||
|
||||
/**
|
||||
* get logger for CREST logging
|
||||
* get logger for SSO logging
|
||||
* @return \Log
|
||||
*/
|
||||
static function getCrestLogger(){
|
||||
return parent::getLogger('CREST');
|
||||
static function getSSOLogger(){
|
||||
return parent::getLogger('SSO');
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus
|
||||
* Date: 23.05.2016
|
||||
* Time: 18:25
|
||||
*/
|
||||
|
||||
namespace controller\ccp;
|
||||
use Data\Mapper as Mapper;
|
||||
use Controller;
|
||||
use Lib;
|
||||
|
||||
|
||||
class Xml extends Controller\Controller{
|
||||
|
||||
/**
|
||||
* get HTTP request options for API (curl) request
|
||||
* @return array
|
||||
*/
|
||||
protected function getRequestOptions(){
|
||||
$requestOptions = [
|
||||
'timeout' => 4,
|
||||
'user_agent' => $this->getUserAgent(),
|
||||
'follow_location' => false // otherwise CURLOPT_FOLLOWLOCATION will fail
|
||||
];
|
||||
|
||||
return $requestOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* request character data from CCP API
|
||||
* @param int $characterId
|
||||
* @return array
|
||||
*/
|
||||
public function getPublicCharacterData($characterId){
|
||||
$characterData = [];
|
||||
$apiPath = self::getEnvironmentData('CCP_XML') . '/eve/CharacterInfo.xml.aspx';
|
||||
|
||||
$baseOptions = $this->getRequestOptions();
|
||||
$requestOptions = [
|
||||
'method' => 'GET',
|
||||
'content' => [
|
||||
'characterID' => (int)$characterId
|
||||
]
|
||||
|
||||
];
|
||||
|
||||
$requestOptions = array_merge($baseOptions, $requestOptions);
|
||||
$apiResponse = Lib\Web::instance()->request($apiPath, $requestOptions );
|
||||
if(
|
||||
$apiResponse['body'] &&
|
||||
($xml = simplexml_load_string($apiResponse['body']))
|
||||
){
|
||||
|
||||
if(
|
||||
isset($xml->result) &&
|
||||
is_object($rowApiData = $xml->result->children())
|
||||
){
|
||||
foreach($rowApiData as $item){
|
||||
// map attributes to array
|
||||
if(count($item->children()) == 0){
|
||||
$characterData[$item->getName()] = strval($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$data = (new Mapper\CcpCharacterMapper($characterData))->getData();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -8,10 +8,8 @@
|
||||
|
||||
namespace Controller;
|
||||
use Controller\Api as Api;
|
||||
use Controller\Ccp\Sso as Sso;
|
||||
use lib\Config;
|
||||
use lib\Socket;
|
||||
use Lib\Util;
|
||||
use Model;
|
||||
use DB;
|
||||
|
||||
@@ -189,8 +187,9 @@ class Controller {
|
||||
* set/update logged in cookie by character model
|
||||
* -> store validation data in DB
|
||||
* @param Model\CharacterModel $character
|
||||
* @param string $scopeHash
|
||||
*/
|
||||
protected function setLoginCookie(Model\CharacterModel $character){
|
||||
protected function setLoginCookie(Model\CharacterModel $character, $scopeHash = ''){
|
||||
|
||||
if( $this->getCookieState() ){
|
||||
$expireSeconds = (int) $this->getF3()->get('PATHFINDER.LOGIN.COOKIE_EXPIRE');
|
||||
@@ -222,7 +221,8 @@ class Controller {
|
||||
'characterId' => $character,
|
||||
'selector' => $selector,
|
||||
'token' => $token,
|
||||
'expires' => $expireTime->format('Y-m-d H:i:s')
|
||||
'expires' => $expireTime->format('Y-m-d H:i:s'),
|
||||
'scopeHash' => $scopeHash
|
||||
];
|
||||
|
||||
$authenticationModel = $character->rel('characterAuthentications');
|
||||
@@ -270,20 +270,20 @@ class Controller {
|
||||
// cookie data is well formatted
|
||||
$characterAuth->getByForeignKey('selector', $data[0], ['limit' => 1]);
|
||||
|
||||
// validate expire data
|
||||
// validate token
|
||||
// validate "scope hash", "expire data" and "validate token"
|
||||
if( !$characterAuth->dry() ){
|
||||
if(
|
||||
$characterAuth->scopeHash === $this->getRequestedScopeHash() &&
|
||||
strtotime($characterAuth->expires) >= $currentTime->getTimestamp() &&
|
||||
hash_equals($characterAuth->token, hash('sha256', $data[1]))
|
||||
){
|
||||
// cookie information is valid
|
||||
// -> try to update character information from CREST
|
||||
// -> try to update character information from ESI
|
||||
// e.g. Corp has changed, this also ensures valid "access_token"
|
||||
/**
|
||||
* @var $character Model\CharacterModel
|
||||
*/
|
||||
$updateStatus = $characterAuth->characterId->updateFromCrest();
|
||||
$updateStatus = $characterAuth->characterId->updateFromESI();
|
||||
|
||||
if( empty($updateStatus) ){
|
||||
// make sure character data is up2date!
|
||||
@@ -293,13 +293,15 @@ class Controller {
|
||||
|
||||
// check if character still has user (is not the case of "ownerHash" changed
|
||||
// check if character is still authorized to log in (e.g. corp/ally or config has changed
|
||||
// -> do NOT remove cookie on failure. This can be a temporary problem (e.g. CREST is down,..)
|
||||
// -> do NOT remove cookie on failure. This can be a temporary problem (e.g. ESI is down,..)
|
||||
if(
|
||||
$character->hasUserCharacter() &&
|
||||
$character->isAuthorized()
|
||||
){
|
||||
$characters[$name] = $character;
|
||||
}
|
||||
}else{
|
||||
$invalidCookie = true;
|
||||
}
|
||||
}else{
|
||||
// clear existing authentication data from DB
|
||||
@@ -449,6 +451,15 @@ class Controller {
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* get a hash over all requested ESI scopes
|
||||
* -> this helps to invalidate "authentication data" after scope change
|
||||
* @return string
|
||||
*/
|
||||
protected function getRequestedScopeHash(){
|
||||
return md5(serialize( self::getEnvironmentData('CCP_ESI_SCOPES') ));
|
||||
}
|
||||
|
||||
/**
|
||||
* log out current character
|
||||
* @param \Base $f3
|
||||
@@ -473,20 +484,37 @@ class Controller {
|
||||
}
|
||||
|
||||
/**
|
||||
* get EVE server status from CREST
|
||||
* get EVE server status from ESI
|
||||
* @param \Base $f3
|
||||
*/
|
||||
public function getEveServerStatus(\Base $f3){
|
||||
// server status can be cached for some seconds
|
||||
$cacheKey = 'eve_server_status';
|
||||
if( !$f3->exists($cacheKey, $return) ){
|
||||
$return = (object) [];
|
||||
$return->error = [];
|
||||
$return->status = [
|
||||
'serverName' => strtoupper( self::getEnvironmentData('CCP_ESI_DATASOURCE') ),
|
||||
'serviceStatus' => 'offline'
|
||||
];
|
||||
|
||||
$sso = new Sso();
|
||||
$return->status = $sso->getCrestServerStatus();
|
||||
$response = $f3->ccpClient->getServerStatus();
|
||||
|
||||
if( !empty($response) ){
|
||||
// calculate time diff since last server restart
|
||||
$timezone = new \DateTimeZone( $f3->get('TZ') );
|
||||
$dateNow = new \DateTime('now', $timezone);
|
||||
$dateServerStart = new \DateTime($response['startTime']);
|
||||
$interval = $dateNow->diff($dateServerStart);
|
||||
$startTimestampFormat = $interval->format('%hh %im');
|
||||
if($interval->days > 0){
|
||||
$startTimestampFormat = $interval->days . 'd ' . $startTimestampFormat;
|
||||
}
|
||||
|
||||
$response['serverName'] = strtoupper( self::getEnvironmentData('CCP_ESI_DATASOURCE') );
|
||||
$response['serviceStatus'] = 'online';
|
||||
$response['startTime'] = $startTimestampFormat;
|
||||
$return->status = $response;
|
||||
|
||||
if( !$return->status->crestOffline ){
|
||||
$f3->set($cacheKey, $return, 60);
|
||||
}
|
||||
}
|
||||
@@ -797,7 +825,7 @@ class Controller {
|
||||
/**
|
||||
* get environment specific configuration data
|
||||
* @param string $key
|
||||
* @return string|null
|
||||
* @return string|array|null
|
||||
*/
|
||||
static function getEnvironmentData($key){
|
||||
return Config::getEnvironmentData($key);
|
||||
|
||||
@@ -34,10 +34,14 @@ class MailController extends \SMTP{
|
||||
* @return bool
|
||||
*/
|
||||
public function sendDeleteAccount($to, $msg){
|
||||
$this->set('To', '<' . $to . '>');
|
||||
$this->set('From', '"Pathfinder" <' . Controller::getEnvironmentData('SMTP_FROM') . '>');
|
||||
$this->set('Subject', 'Account deleted');
|
||||
$status = $this->send($msg);
|
||||
$status = false;
|
||||
|
||||
if( !empty($to)){
|
||||
$this->set('To', '<' . $to . '>');
|
||||
$this->set('From', '"Pathfinder" <' . Controller::getEnvironmentData('SMTP_FROM') . '>');
|
||||
$this->set('Subject', 'Account deleted');
|
||||
$status = $this->send($msg);
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
@@ -49,10 +53,27 @@ class MailController extends \SMTP{
|
||||
* @return bool
|
||||
*/
|
||||
public function sendRallyPoint($to, $msg){
|
||||
$this->set('To', '<' . $to . '>');
|
||||
$this->set('From', '"Pathfinder" <' . Controller::getEnvironmentData('SMTP_FROM') . '>');
|
||||
$this->set('Subject', 'PATHFINDER - New rally point');
|
||||
$status = $this->send($msg);
|
||||
$status = false;
|
||||
|
||||
if( !empty($to)){
|
||||
$this->set('To', '<' . $to . '>');
|
||||
$this->set('From', '"Pathfinder" <' . Controller::getEnvironmentData('SMTP_FROM') . '>');
|
||||
$this->set('Subject', 'PATHFINDER - New rally point');
|
||||
$status = $this->send($msg);
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
public function send($message, $log = true, $mock = false){
|
||||
$status = false;
|
||||
|
||||
if(
|
||||
!empty($this->host) &&
|
||||
!empty($this->port)
|
||||
){
|
||||
$status = parent::send($message, $log, $mock);
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
@@ -34,11 +34,11 @@ class Setup extends Controller {
|
||||
'DB_CCP_NAME',
|
||||
'DB_CCP_USER',
|
||||
'DB_CCP_PASS',
|
||||
'CCP_CREST_URL',
|
||||
'SSO_CCP_URL',
|
||||
'SSO_CCP_CLIENT_ID',
|
||||
'SSO_CCP_SECRET_KEY',
|
||||
'CCP_XML',
|
||||
'CCP_SSO_URL',
|
||||
'CCP_SSO_CLIENT_ID',
|
||||
'CCP_SSO_SECRET_KEY',
|
||||
'CCP_ESI_URL',
|
||||
'CCP_ESI_DATASOURCE',
|
||||
'SMTP_HOST',
|
||||
'SMTP_PORT',
|
||||
'SMTP_SCHEME',
|
||||
@@ -183,6 +183,8 @@ class Setup extends Controller {
|
||||
$this->exportTable($params['exportTable']);
|
||||
}elseif( !empty($params['clearCache']) ){
|
||||
$this->clearCache($f3);
|
||||
}elseif( !empty($params['invalidateCookies']) ){
|
||||
$this->invalidateCookies($f3);
|
||||
}
|
||||
|
||||
// set template data ----------------------------------------------------------------
|
||||
@@ -314,7 +316,7 @@ class Setup extends Controller {
|
||||
];
|
||||
|
||||
// obscure some values
|
||||
$obscureVars = ['SSO_CCP_CLIENT_ID', 'SSO_CCP_SECRET_KEY', 'SMTP_PASS'];
|
||||
$obscureVars = ['CCP_SSO_CLIENT_ID', 'CCP_SSO_SECRET_KEY', 'SMTP_PASS'];
|
||||
|
||||
foreach($this->environmentVars as $var){
|
||||
if( !in_array($var, $excludeVars) ){
|
||||
@@ -1203,6 +1205,21 @@ class Setup extends Controller {
|
||||
$f3->clear('CACHE');
|
||||
}
|
||||
|
||||
/**
|
||||
* clear all character authentication (Cookie) data
|
||||
* @param \Base $f3
|
||||
*/
|
||||
protected function invalidateCookies(\Base $f3){
|
||||
$this->getDB('PF');
|
||||
$authentidationModel = Model\BasicModel::getNew('CharacterAuthenticationModel');
|
||||
$results = $authentidationModel->find();
|
||||
if($results){
|
||||
foreach($results as $result){
|
||||
$result->erase();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* convert Bytes to string + suffix
|
||||
* @param int $bytes
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
namespace Cron;
|
||||
use Controller;
|
||||
use DB;
|
||||
use lib\Config;
|
||||
|
||||
class CcpSystemsUpdate {
|
||||
|
||||
@@ -26,9 +25,9 @@ class CcpSystemsUpdate {
|
||||
*/
|
||||
protected $logTables = [
|
||||
'jumps' => 'system_jumps',
|
||||
'shipKills' => 'system_kills_ships',
|
||||
'podKills' => 'system_kills_pods',
|
||||
'factionKills' => 'system_kills_factions'
|
||||
'ship_kills' => 'system_kills_ships',
|
||||
'pod_kills' => 'system_kills_pods',
|
||||
'npc_kills' => 'system_kills_factions'
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -74,77 +73,37 @@ class CcpSystemsUpdate {
|
||||
*/
|
||||
function importSystemData($f3){
|
||||
|
||||
// prepare system jump log table ------------------------------------------------------------------------------
|
||||
$time_start = microtime(true);
|
||||
// prepare system jump log table
|
||||
$systemsData = $this->prepareSystemLogTables();
|
||||
$time_end = microtime(true);
|
||||
$execTimePrepareSystemLogTables = $time_end - $time_start;
|
||||
|
||||
// switch DB for data import..
|
||||
$pfDB = DB\Database::instance()->getDB('PF');
|
||||
|
||||
// get current jump Data -------------------------------------------------------
|
||||
// get current jump data --------------------------------------------------------------------------------------
|
||||
$time_start = microtime(true);
|
||||
$apiPath = Config::getEnvironmentData('CCP_XML') . '/map/Jumps.xml.aspx';
|
||||
|
||||
$apiResponse = \Web::instance()->request($apiPath, $this->apiRequestOptions );
|
||||
|
||||
$jumpData = [];
|
||||
$updateJumps = false;
|
||||
if($apiResponse['body']){
|
||||
$xml = simplexml_load_string($apiResponse['body']);
|
||||
$rowApiData = $xml->result->rowset;
|
||||
|
||||
foreach($rowApiData->children() as $systemApiData){
|
||||
$attributeApiData = $systemApiData->attributes();
|
||||
$systemId = $attributeApiData->solarSystemID->__toString();
|
||||
$shipJumps =$attributeApiData->shipJumps->__toString();
|
||||
|
||||
$jumpData[$systemId] = $shipJumps;
|
||||
}
|
||||
|
||||
$updateJumps = true;
|
||||
}
|
||||
$jumpData = $f3->ccpClient->getUniverseJumps();
|
||||
$time_end = microtime(true);
|
||||
$execTimeGetJumpData = $time_end - $time_start;
|
||||
|
||||
// get current kill Data -------------------------------------------------------
|
||||
// get current kill data --------------------------------------------------------------------------------------
|
||||
$time_start = microtime(true);
|
||||
$apiPath = Config::getEnvironmentData('CCP_XML') . '/map/Kills.xml.aspx';
|
||||
|
||||
$apiResponse = \Web::instance()->request($apiPath, $this->apiRequestOptions );
|
||||
$killData = [];
|
||||
$updateKills = false;
|
||||
if($apiResponse['body']){
|
||||
$xml = simplexml_load_string($apiResponse['body']);
|
||||
$rowApiData = $xml->result->rowset;
|
||||
foreach($rowApiData->children() as $systemApiData){
|
||||
$attributeApiData = $systemApiData->attributes();
|
||||
$systemId = $attributeApiData->solarSystemID->__toString();
|
||||
$shipKills =$attributeApiData->shipKills->__toString();
|
||||
$podKills =$attributeApiData->podKills->__toString();
|
||||
$factionKills =$attributeApiData->factionKills->__toString();
|
||||
|
||||
$killData[$systemId] = [
|
||||
'shipKills' => $shipKills,
|
||||
'podKills' => $podKills,
|
||||
'factionKills' => $factionKills,
|
||||
];
|
||||
}
|
||||
|
||||
$updateKills = true;
|
||||
|
||||
}
|
||||
$killData = $f3->ccpClient->getUniverseKills();
|
||||
$time_end = microtime(true);
|
||||
$execTimeGetKillData = $time_end - $time_start;
|
||||
|
||||
// update system log tables -----------------------------------------------------
|
||||
// merge both results
|
||||
$systemValues = array_replace_recursive($jumpData, $killData);
|
||||
|
||||
// update system log tables -----------------------------------------------------------------------------------
|
||||
$time_start = microtime(true);
|
||||
// make sure last update is (at least) 1h ago
|
||||
$pfDB->begin();
|
||||
|
||||
foreach($this->logTables as $key => $tableName){
|
||||
$sql = "UPDATE
|
||||
" . $tableName . "
|
||||
$tableName
|
||||
SET
|
||||
updated = now(),
|
||||
value24 = value23,
|
||||
@@ -173,47 +132,30 @@ class CcpSystemsUpdate {
|
||||
value1 = :value
|
||||
WHERE
|
||||
systemId = :systemId
|
||||
";
|
||||
";
|
||||
|
||||
foreach($systemsData as $systemData){
|
||||
$systemId = $systemData['systemId'];
|
||||
|
||||
if(
|
||||
$key == 'jumps' &&
|
||||
$updateJumps
|
||||
){
|
||||
// update jump data (if available)
|
||||
$currentJumps = 0;
|
||||
if(array_key_exists($systemData['systemId'], $jumpData)){
|
||||
$currentJumps = $jumpData[$systemData['systemId']];
|
||||
}
|
||||
|
||||
$pfDB->exec($sql, array(
|
||||
':systemId' => $systemData['systemId'],
|
||||
':value' => $currentJumps
|
||||
), 0, false);
|
||||
}else if($updateKills){
|
||||
|
||||
// update kill data (if available)
|
||||
$currentKills = 0;
|
||||
if(array_key_exists($systemData['systemId'], $killData)){
|
||||
$currentKillData = $killData[$systemData['systemId']];
|
||||
|
||||
$currentKills = $currentKillData[$key];
|
||||
}
|
||||
|
||||
$pfDB->exec($sql, array(
|
||||
':systemId' => $systemData['systemId'],
|
||||
':value' => $currentKills
|
||||
), 0, false);
|
||||
// update data (if available)
|
||||
$currentData = 0;
|
||||
if( isset($systemValues[$systemId][$key]) ){
|
||||
$currentData = (int)$systemValues[$systemId][$key];
|
||||
}
|
||||
|
||||
$pfDB->exec($sql, [
|
||||
':systemId' => $systemId,
|
||||
':value' => $currentData
|
||||
], 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
$pfDB->commit();
|
||||
|
||||
$time_end = microtime(true);
|
||||
$execTimeUpdateTables = $time_end - $time_start;
|
||||
|
||||
// Log ------------------------
|
||||
// Log --------------------------------------------------------------------------------------------------------
|
||||
$log = new \Log('cron_' . __FUNCTION__ . '.log');
|
||||
$log->write( sprintf(self::LOG_TEXT, __FUNCTION__, $execTimePrepareSystemLogTables, $execTimeGetJumpData, $execTimeGetKillData, $execTimeUpdateTables) );
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus
|
||||
* Date: 23.05.2016
|
||||
* Time: 20:32
|
||||
*/
|
||||
|
||||
namespace data\mapper;
|
||||
|
||||
|
||||
class CcpCharacterMapper extends AbstractIterator {
|
||||
|
||||
|
||||
protected static $map = [
|
||||
'characterID' => ['character' => 'id'],
|
||||
'characterName' => ['character' => 'name'],
|
||||
|
||||
'race' => 'race',
|
||||
|
||||
'bloodlineID' => ['blood' => 'id'],
|
||||
'bloodline' => ['blood' => 'name'],
|
||||
|
||||
'ancestryID' => ['origin' => 'id'],
|
||||
'ancestry' => ['origin' => 'name'],
|
||||
|
||||
'corporationID' => ['corp' => 'id'],
|
||||
'corporation' => ['corp' => 'name'],
|
||||
'corporationDate' => ['corp' => 'date'],
|
||||
|
||||
'allianceID' => ['alli' => 'id'],
|
||||
'alliance' => ['alli' => 'name'],
|
||||
'allianceDate' => ['alli' => 'date'],
|
||||
|
||||
'securityStatus' => 'security'
|
||||
];
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus
|
||||
* Date: 15.05.2016
|
||||
* Time: 22:04
|
||||
*/
|
||||
|
||||
namespace Data\Mapper;
|
||||
|
||||
|
||||
class CrestAlliance extends AbstractIterator {
|
||||
|
||||
protected static $map = [
|
||||
'id' => 'id',
|
||||
'name' => 'name'
|
||||
];
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus
|
||||
* Date: 31.01.2016
|
||||
* Time: 19:09
|
||||
*/
|
||||
|
||||
namespace Data\Mapper;
|
||||
|
||||
|
||||
class CrestCharacter extends AbstractIterator {
|
||||
|
||||
protected static $map = [
|
||||
'id' => 'id',
|
||||
'name' => 'name'
|
||||
];
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus
|
||||
* Date: 31.01.2016
|
||||
* Time: 03:55
|
||||
*/
|
||||
|
||||
namespace Data\Mapper;
|
||||
|
||||
|
||||
class CrestCorporation extends AbstractIterator {
|
||||
|
||||
protected static $map = [
|
||||
'id' => 'id',
|
||||
'name' => 'name',
|
||||
'isNPC' => 'isNPC'
|
||||
];
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus
|
||||
* Date: 01.05.2016
|
||||
* Time: 19:17
|
||||
*/
|
||||
|
||||
namespace Data\Mapper;
|
||||
|
||||
|
||||
class CrestServiceStatus extends AbstractIterator {
|
||||
|
||||
protected static $map = [
|
||||
'dust' => 'dust',
|
||||
'eve' => 'eve',
|
||||
'server' => 'server'
|
||||
];
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus
|
||||
* Date: 09.04.2016
|
||||
* Time: 21:11
|
||||
*/
|
||||
|
||||
namespace Data\Mapper;
|
||||
|
||||
|
||||
class CrestStation extends AbstractIterator {
|
||||
|
||||
protected static $map = [
|
||||
'id' => 'id',
|
||||
'name' => 'name'
|
||||
];
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus
|
||||
* Date: 07.02.2016
|
||||
* Time: 14:34
|
||||
*/
|
||||
|
||||
namespace Data\Mapper;
|
||||
|
||||
|
||||
class CrestSystem extends AbstractIterator {
|
||||
|
||||
protected static $map = [
|
||||
'id' => 'id',
|
||||
'name' => 'name'
|
||||
];
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus
|
||||
* Date: 01.05.2016
|
||||
* Time: 19:42
|
||||
*/
|
||||
|
||||
namespace Data\Mapper;
|
||||
|
||||
|
||||
class CrestUserCounts extends AbstractIterator {
|
||||
|
||||
protected static $map = [
|
||||
'dust' => 'dust',
|
||||
'eve' => 'eve'
|
||||
];
|
||||
}
|
||||
@@ -98,17 +98,26 @@ class Database extends \Prefab {
|
||||
*/
|
||||
protected function connect($dns, $name, $user, $password){
|
||||
$db = null;
|
||||
$f3 = \Base::instance();
|
||||
|
||||
$options = [
|
||||
\PDO::MYSQL_ATTR_COMPRESS => true,
|
||||
\PDO::ATTR_TIMEOUT => \Base::instance()->get('REQUIREMENTS.MYSQL.PDO_TIMEOUT'),
|
||||
];
|
||||
|
||||
// set ERRMODE depending on pathfinders global DEBUG level
|
||||
if($f3->get('DEBUG') >= 3){
|
||||
$options[\PDO::ATTR_ERRMODE] = \PDO::ERRMODE_WARNING;
|
||||
}else{
|
||||
$options[\PDO::ATTR_ERRMODE] = \PDO::ERRMODE_EXCEPTION;
|
||||
}
|
||||
|
||||
try {
|
||||
$db = new SQL(
|
||||
$dns . $name,
|
||||
$user,
|
||||
$password,
|
||||
[
|
||||
\PDO::MYSQL_ATTR_COMPRESS => true,
|
||||
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
|
||||
\PDO::ATTR_TIMEOUT => \Base::instance()->get('REQUIREMENTS.MYSQL.PDO_TIMEOUT'),
|
||||
]
|
||||
$options
|
||||
);
|
||||
}catch(\PDOException $e){
|
||||
// DB connection error
|
||||
|
||||
96
app/main/lib/ccpclient.php
Normal file
96
app/main/lib/ccpclient.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus4D
|
||||
* Date: 26.03.2017
|
||||
* Time: 19:17
|
||||
*/
|
||||
|
||||
namespace Lib;
|
||||
|
||||
use controller\LogController;
|
||||
use \Exodus4D\ESI\ESI as ApiClient;
|
||||
|
||||
class CcpClient extends \Prefab {
|
||||
|
||||
private $apiClient;
|
||||
|
||||
public function __construct(){
|
||||
$f3 = \Base::instance();
|
||||
|
||||
$this->apiClient = $this->getClient($f3);
|
||||
|
||||
$f3->set('ccpClient', $this);
|
||||
}
|
||||
|
||||
|
||||
protected function getClient($f3){
|
||||
$client = null;
|
||||
|
||||
if( !class_exists(ApiClient::class) ){
|
||||
LogController::getLogger('ERROR')->write($this->getMissingClientError());
|
||||
}else{
|
||||
$client = new ApiClient($f3);
|
||||
$client->setUrl( Config::getEnvironmentData('CCP_ESI_URL') );
|
||||
$client->setDatasource( Config::getEnvironmentData('CCP_ESI_DATASOURCE') );
|
||||
$client->setUserAgent($this->getUserAgent($f3));
|
||||
}
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Base $f3
|
||||
* @return string
|
||||
*/
|
||||
protected function getUserAgent($f3){
|
||||
$userAgent = '';
|
||||
$userAgent .= $f3->get('PATHFINDER.NAME');
|
||||
$userAgent .= ' - ' . $f3->get('PATHFINDER.VERSION');
|
||||
$userAgent .= ' | ' . $f3->get('PATHFINDER.CONTACT');
|
||||
$userAgent .= ' (' . $_SERVER['SERVER_NAME'] . ')';
|
||||
|
||||
return $userAgent;
|
||||
}
|
||||
|
||||
/**
|
||||
* get error msg for failed ApiClient() class -> Composer package not found
|
||||
* @return string
|
||||
*/
|
||||
protected function getMissingClientError(){
|
||||
return "Class '" . ApiClient::class . "' not found. -> Check installed Composer packages.'";
|
||||
}
|
||||
|
||||
/**
|
||||
* get error msg for undefined method in ApiClient() class
|
||||
* @param $method
|
||||
* @return string
|
||||
*/
|
||||
protected function getMissingMethodError($method){
|
||||
return "Method '" . $method . "()' not found in class '" . get_class($this->apiClient) . "'. -> Check installed Composer package version.'";
|
||||
}
|
||||
|
||||
/**
|
||||
* call request API data
|
||||
* @param $name
|
||||
* @param $arguments
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function __call($name, $arguments){
|
||||
$return = [];
|
||||
|
||||
if(is_object($this->apiClient)){
|
||||
if( method_exists($this->apiClient, $name) ){
|
||||
$return = call_user_func_array([$this->apiClient, $name], $arguments);
|
||||
}else{
|
||||
LogController::getLogger('ERROR')->write($this->getMissingMethodError($name));
|
||||
\Base::instance()->error(501, $this->getMissingMethodError($name));
|
||||
}
|
||||
}else{
|
||||
LogController::getLogger('ERROR')->write($this->getMissingClientError());
|
||||
\Base::instance()->error(501, $this->getMissingClientError());
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,12 @@ class Config extends \Prefab {
|
||||
const HIVE_KEY_PATHFINDER = 'PATHFINDER';
|
||||
const HIVE_KEY_ENVIRONMENT = 'ENVIRONMENT';
|
||||
|
||||
/**
|
||||
* environment config keys that should be parsed as array
|
||||
* -> use "," as delimiter in config files/data
|
||||
*/
|
||||
const ARRAY_KEYS = ['CCP_ESI_SCOPES'];
|
||||
|
||||
/**
|
||||
* all environment data
|
||||
* @var array
|
||||
@@ -79,6 +85,12 @@ class Config extends \Prefab {
|
||||
if( !empty($this->serverConfigData['ENV']) ){
|
||||
// get environment config from $_SERVER data
|
||||
$environmentData = (array)$this->serverConfigData['ENV'];
|
||||
|
||||
// some environment variables should be parsed as array
|
||||
array_walk($environmentData, function(&$item, $key){
|
||||
$item = (in_array($key, self::ARRAY_KEYS)) ? explode(',', $item) : $item;
|
||||
});
|
||||
|
||||
$environmentData['TYPE'] = 'PHP: environment variables';
|
||||
}else{
|
||||
// get environment data from *.ini file config
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
|
||||
namespace lib;
|
||||
|
||||
use controller\LogController;
|
||||
|
||||
class Socket {
|
||||
|
||||
// max TTL time (ms)
|
||||
@@ -106,7 +104,10 @@ class Socket {
|
||||
|
||||
$this->initSocket();
|
||||
|
||||
if( !$this->socket ){
|
||||
if(
|
||||
!$this->socket ||
|
||||
!$this->socketUri
|
||||
){
|
||||
// Socket not active (e.g. URI missing)
|
||||
return $response;
|
||||
}
|
||||
|
||||
@@ -15,8 +15,8 @@ class Web extends \Web {
|
||||
const ERROR_STATUS_LOG = 'HTTP %s: \'%s\' | url: %s \'%s\'%s';
|
||||
|
||||
/**
|
||||
* max number of CREST curls for a single endpoint until giving up...
|
||||
* this is because CREST is not very stable
|
||||
* max number of curls calls for a single resource until giving up...
|
||||
* this is because SSO API is not very stable
|
||||
*/
|
||||
const RETRY_COUNT_MAX = 3;
|
||||
|
||||
@@ -98,7 +98,7 @@ class Web extends \Web {
|
||||
* @param string $url
|
||||
* @param array|null $options
|
||||
* @param array $additionalOptions
|
||||
* @param int $retryCount request counter for failed crest call
|
||||
* @param int $retryCount request counter for failed call
|
||||
* @return array|FALSE|mixed
|
||||
*/
|
||||
public function request($url,array $options = null, $additionalOptions = [], $retryCount = 0 ) {
|
||||
|
||||
@@ -50,6 +50,11 @@ class CharacterAuthenticationModel extends BasicModel{
|
||||
'type' => Schema::DT_TIMESTAMP,
|
||||
'default' => Schema::DF_CURRENT_TIMESTAMP,
|
||||
'index' => true
|
||||
],
|
||||
'scopeHash' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
@@ -35,9 +35,6 @@ class CharacterLogModel extends BasicModel {
|
||||
]
|
||||
]
|
||||
],
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
'systemId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
@@ -47,26 +44,6 @@ class CharacterLogModel extends BasicModel {
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'constellationId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
],
|
||||
'constellationName' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'regionId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
],
|
||||
'regionName' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
'shipTypeId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
@@ -110,24 +87,6 @@ class CharacterLogModel extends BasicModel {
|
||||
$this->systemName = '';
|
||||
}
|
||||
|
||||
if( isset($logData['constellation']) ){
|
||||
$this->constellationId = (int)$logData['constellation']['id'];
|
||||
$this->constellationName = $logData['constellation']['name'];
|
||||
}else{
|
||||
$this->constellationId = null;
|
||||
$this->constellationName = '';
|
||||
}
|
||||
|
||||
if( isset($logData['region']) ){
|
||||
$this->regionId = (int)$logData['region']['id'];
|
||||
$this->regionName = $logData['region']['name'];
|
||||
}else{
|
||||
$this->regionId = null;
|
||||
$this->regionName = '';
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
if( isset($logData['ship']) ){
|
||||
$this->shipTypeId = (int)$logData['ship']['typeId'];
|
||||
$this->shipTypeName = $logData['ship']['typeName'];
|
||||
@@ -161,16 +120,6 @@ class CharacterLogModel extends BasicModel {
|
||||
$logData->system->id = (int)$this->systemId;
|
||||
$logData->system->name = $this->systemName;
|
||||
|
||||
$logData->constellation = (object) [];
|
||||
$logData->constellation->id = (int)$this->constellationId;
|
||||
$logData->constellation->name = $this->constellationName;
|
||||
|
||||
$logData->region = (object) [];
|
||||
$logData->region->id = (int)$this->regionId;
|
||||
$logData->region->name = $this->regionName;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
$logData->ship = (object) [];
|
||||
$logData->ship->typeId = (int)$this->shipTypeId;
|
||||
$logData->ship->typeName = $this->shipTypeName;
|
||||
|
||||
@@ -75,15 +75,6 @@ class CharacterModel extends BasicModel {
|
||||
]
|
||||
]
|
||||
],
|
||||
'factionId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
],
|
||||
'factionName' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'shared' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
@@ -94,6 +85,11 @@ class CharacterModel extends BasicModel {
|
||||
'nullable' => false,
|
||||
'default' => 1
|
||||
],
|
||||
'securityStatus' => [
|
||||
'type' => Schema::DT_FLOAT,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
],
|
||||
'userCharacter' => [
|
||||
'has-one' => ['Model\UserCharacterModel', 'characterId']
|
||||
],
|
||||
@@ -178,7 +174,7 @@ class CharacterModel extends BasicModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* set CREST accessToken for current session
|
||||
* set API accessToken for current session
|
||||
* -> update "tokenUpdated" column on change
|
||||
* -> this is required for expire checking!
|
||||
* @param string $accessToken
|
||||
@@ -191,6 +187,11 @@ class CharacterModel extends BasicModel {
|
||||
return $accessToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* logLocation specifies whether the current system should be tracked or not
|
||||
* @param $logLocation
|
||||
* @return bool
|
||||
*/
|
||||
public function set_logLocation($logLocation){
|
||||
$logLocation = (bool)$logLocation;
|
||||
if(
|
||||
@@ -304,7 +305,7 @@ class CharacterModel extends BasicModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* get CREST API "access_token" from OAuth
|
||||
* get ESI API "access_token" from OAuth
|
||||
* @return bool|string
|
||||
*/
|
||||
public function getAccessToken(){
|
||||
@@ -365,13 +366,8 @@ class CharacterModel extends BasicModel {
|
||||
$isAuthorized = false;
|
||||
$f3 = self::getF3();
|
||||
|
||||
$whitelistCorporations = $whitelistAlliance = [];
|
||||
if( !empty($f3->get('PATHFINDER.LOGIN.CORPORATION')) ){
|
||||
$whitelistCorporations = array_map('trim',(array) $f3->get('PATHFINDER.LOGIN.CORPORATION') );
|
||||
}
|
||||
if( !empty($f3->get('PATHFINDER.LOGIN.ALLIANCE')) ){
|
||||
$whitelistAlliance = array_map('trim',(array) $f3->get('PATHFINDER.LOGIN.ALLIANCE') );
|
||||
}
|
||||
$whitelistCorporations = array_filter( array_map('trim', (array)$f3->get('PATHFINDER.LOGIN.CORPORATION') ) );
|
||||
$whitelistAlliance = array_filter( array_map('trim', (array)$f3->get('PATHFINDER.LOGIN.ALLIANCE') ) );
|
||||
|
||||
if(
|
||||
empty($whitelistCorporations) &&
|
||||
@@ -405,48 +401,113 @@ class CharacterModel extends BasicModel {
|
||||
|
||||
/**
|
||||
* update character log (active system, ...)
|
||||
* -> CREST API request for character log data
|
||||
* -> API request for character log data
|
||||
* @param array $additionalOptions (optional) request options for cURL request
|
||||
* @return $this
|
||||
*/
|
||||
public function updateLog($additionalOptions = []){
|
||||
$deleteLog = true;
|
||||
|
||||
//check if log update is enabled for this user
|
||||
if( $this->logLocation ){
|
||||
// Try to pull data from CREST
|
||||
$ssoController = new Sso();
|
||||
$logData = $ssoController->getCharacterLocationData($this->getAccessToken(), $additionalOptions);
|
||||
// Try to pull data from API
|
||||
if( $accessToken = $this->getAccessToken() ){
|
||||
$locationData = self::getF3()->ccpClient->getCharacterLocationData($this->_id, $accessToken, $additionalOptions);
|
||||
|
||||
if($logData['timeout'] === false){
|
||||
if( empty($logData['system']) ){
|
||||
// character is not in-game
|
||||
if( $this->hasLog() ){
|
||||
// delete existing log
|
||||
$this->characterLog->erase();
|
||||
$this->save();
|
||||
}
|
||||
}else{
|
||||
if( !empty($locationData['system']['id']) ){
|
||||
// character is currently in-game
|
||||
|
||||
// IDs for "systemId", "stationId and "shipTypeId" that require more data
|
||||
$lookupIds = [];
|
||||
|
||||
if( !$characterLog = $this->getLog() ){
|
||||
// create new log
|
||||
$characterLog = $this->rel('characterLog');
|
||||
$characterLog->characterId = $this->_id;
|
||||
}
|
||||
$characterLog->setData($logData);
|
||||
$characterLog->save();
|
||||
|
||||
$this->characterLog = $characterLog;
|
||||
// get current log data and modify on change
|
||||
$logData = json_decode(json_encode( $characterLog->getData()), true);
|
||||
|
||||
if(
|
||||
empty($logData['system']['name']) ||
|
||||
$logData['system']['id'] !== $locationData['system']['id']
|
||||
){
|
||||
// system changed -> request "system name" for current system
|
||||
$lookupIds[] = $locationData['system']['id'];
|
||||
}
|
||||
|
||||
if( !empty($locationData['station']['id']) ){
|
||||
if(
|
||||
empty($logData['station']['name']) ||
|
||||
$logData['station']['id'] !== $locationData['station']['id']
|
||||
){
|
||||
// station changed -> request "station name" for current station
|
||||
$lookupIds[] = $locationData['station']['id'];
|
||||
}
|
||||
}else{
|
||||
unset($logData['station']);
|
||||
}
|
||||
|
||||
$logData = array_replace_recursive($logData, $locationData);
|
||||
|
||||
// get current ship data
|
||||
$shipData = self::getF3()->ccpClient->getCharacterShipData($this->_id, $accessToken, $additionalOptions);
|
||||
|
||||
if( !empty($shipData['ship']['typeId']) ){
|
||||
if(
|
||||
empty($logData['ship']['typeName']) ||
|
||||
$logData['ship']['typeId'] !== $shipData['ship']['typeId']
|
||||
){
|
||||
// ship changed -> request "station name" for current station
|
||||
$lookupIds[] = $shipData['ship']['typeId'];
|
||||
}
|
||||
|
||||
// "shipName"/"shipId" could have changed...
|
||||
$logData = array_replace_recursive($logData, $shipData);
|
||||
}else{
|
||||
unset($logData['ship']);
|
||||
}
|
||||
|
||||
if( !empty($lookupIds) ){
|
||||
// get "more" information for some Ids (e.g. name)
|
||||
$universeData = self::getF3()->ccpClient->getUniverseNamesData($lookupIds, $additionalOptions);
|
||||
|
||||
if( !empty($universeData) ){
|
||||
$deleteLog = false;
|
||||
$logData = array_replace_recursive($logData, $universeData);
|
||||
}
|
||||
}else{
|
||||
$deleteLog = false;
|
||||
}
|
||||
|
||||
if( !$deleteLog ){
|
||||
$characterLog->setData($logData);
|
||||
$characterLog->save();
|
||||
|
||||
$this->characterLog = $characterLog;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(
|
||||
$deleteLog &&
|
||||
$this->hasLog()
|
||||
){
|
||||
// delete existing log
|
||||
$this->characterLog->erase();
|
||||
$this->save();
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* update character data from CCPs CREST API
|
||||
* update character data from CCPs ESI API
|
||||
* @return array (some status messages)
|
||||
*/
|
||||
public function updateFromCrest(){
|
||||
public function updateFromESI(){
|
||||
$status = [];
|
||||
|
||||
if( $accessToken = $this->getAccessToken() ){
|
||||
@@ -458,36 +519,14 @@ class CharacterModel extends BasicModel {
|
||||
!is_null( $verificationCharacterData = $ssoController->verifyCharacterData($accessToken) ) &&
|
||||
$verificationCharacterData->CharacterID === $this->_id
|
||||
){
|
||||
// get character data from CREST
|
||||
$characterData = $ssoController->getCharacterData($accessToken);
|
||||
if( isset($characterData->character) ){
|
||||
// get character data from API
|
||||
$characterData = $ssoController->getCharacterData($this->_id);
|
||||
if( !empty($characterData->character) ){
|
||||
$characterData->character['ownerHash'] = $verificationCharacterData->CharacterOwnerHash;
|
||||
|
||||
$corporation = null;
|
||||
$alliance = null;
|
||||
if( isset($characterData->corporation) ){
|
||||
/**
|
||||
* @var $corporation CorporationModel
|
||||
*/
|
||||
$corporation = $this->rel('corporationId');
|
||||
$corporation->getById($characterData->corporation['id'], 0);
|
||||
$corporation->copyfrom($characterData->corporation, ['id', 'name', 'isNPC']);
|
||||
$corporation->save();
|
||||
}
|
||||
|
||||
if( isset($characterData->alliance) ){
|
||||
/**
|
||||
* @var $alliance AllianceModel
|
||||
*/
|
||||
$alliance = $this->rel('allianceId');
|
||||
$alliance->getById($characterData->alliance['id'], 0);
|
||||
$alliance->copyfrom($characterData->alliance, ['id', 'name']);
|
||||
$alliance->save();
|
||||
}
|
||||
|
||||
$this->copyfrom($characterData->character, ['name', 'ownerHash']);
|
||||
$this->set('corporationId', is_object($corporation) ? $corporation->get('id') : null);
|
||||
$this->set('allianceId', is_object($alliance) ? $alliance->get('id') : null);
|
||||
$this->copyfrom($characterData->character, ['ownerHash', 'securityStatus']);
|
||||
$this->corporationId = $characterData->corporation;
|
||||
$this->allianceId = $characterData->alliance;
|
||||
$this->save();
|
||||
}
|
||||
}else{
|
||||
|
||||
@@ -332,6 +332,10 @@ class ConnectionModel extends BasicModel{
|
||||
return $signatures;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all signature data linked to this connection
|
||||
* @return array
|
||||
*/
|
||||
public function getSignaturesData(){
|
||||
$signaturesData = [];
|
||||
$signatures = $this->getSignatures();
|
||||
|
||||
@@ -283,6 +283,22 @@ class SystemModel extends BasicModel {
|
||||
return $systemData;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for system alias
|
||||
* @param string $alias
|
||||
* @return string
|
||||
*/
|
||||
public function set_alias($alias){
|
||||
$alias = trim($alias);
|
||||
|
||||
// we don´t need redundant data. "name" is always preferred if "alias" is empty
|
||||
if($alias === $this->name){
|
||||
$alias = '';
|
||||
}
|
||||
|
||||
return $alias;
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for system security value
|
||||
* @param float $trueSec
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[PATHFINDER]
|
||||
NAME = Pathfinder
|
||||
; installed version (used for CSS/JS cache busting)
|
||||
VERSION = v1.2.1
|
||||
VERSION = v1.2.2
|
||||
; contact information [optional]
|
||||
CONTACT = https://github.com/exodus4d
|
||||
; public contact email [optional]
|
||||
@@ -142,8 +142,8 @@ EXPIRE_SIGNATURES = 259200
|
||||
[PATHFINDER.LOGFILES]
|
||||
; error log
|
||||
ERROR = error
|
||||
; CREST error log
|
||||
CREST = crest
|
||||
; SSO error log
|
||||
SSO = sso
|
||||
; login information
|
||||
LOGIN = login
|
||||
; session warnings (suspect)
|
||||
|
||||
@@ -39,7 +39,7 @@ ZMQ = 4.1.3
|
||||
[REQUIREMENTS.MYSQL]
|
||||
; min MySQL Version
|
||||
; newer "deviation" of MySQL like "MariaDB" > 10.1 are recommended
|
||||
VERSION = 5.6
|
||||
VERSION = 5.7
|
||||
; DB timeout (seconds)
|
||||
PDO_TIMEOUT = 2
|
||||
|
||||
|
||||
28
composer-dev.json
Normal file
28
composer-dev.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "exodus4d/pathfinder",
|
||||
"description": "Mapping tool for EVE ONLINE",
|
||||
"minimum-stability": "stable",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Mark Friedrich",
|
||||
"email": "pathfinder@exodus4d.de"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Exodus4D\\Pathfinder\\": "app/main"
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "../pathfinder_esi"
|
||||
}],
|
||||
"require": {
|
||||
"php-64bit": ">=7.0",
|
||||
"ext-zmq": "1.1.*",
|
||||
"react/zmq": "0.3.*",
|
||||
"exodus4d/pathfinder_esi": "dev-develop as 0.0.x-dev"
|
||||
}
|
||||
}
|
||||
@@ -14,9 +14,15 @@
|
||||
"Exodus4D\\Pathfinder\\": "app/main"
|
||||
}
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/exodus4d/pathfinder_esi"
|
||||
}],
|
||||
"require": {
|
||||
"php-64bit": ">=7.0",
|
||||
"ext-zmq": "1.1.*",
|
||||
"react/zmq": "0.3.*"
|
||||
"react/zmq": "0.3.*",
|
||||
"exodus4d/pathfinder_esi": "dev-master#v1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
index.php
11
index.php
@@ -1,6 +1,12 @@
|
||||
<?php
|
||||
session_name('pathfinder_session');
|
||||
$f3 = require('app/lib/base.php');
|
||||
|
||||
$composerAutoloader = 'vendor/autoload.php';
|
||||
if(file_exists($composerAutoloader)){
|
||||
require_once($composerAutoloader);
|
||||
}
|
||||
|
||||
$f3 = require_once('app/lib/base.php');
|
||||
|
||||
// load main config
|
||||
$f3->config('app/config.ini');
|
||||
@@ -8,6 +14,9 @@ $f3->config('app/config.ini');
|
||||
// load environment dependent config
|
||||
lib\Config::instance();
|
||||
|
||||
// initiate CCP API Client (ESI)
|
||||
lib\CcpClient::instance();
|
||||
|
||||
// initiate cron-jobs
|
||||
Cron::instance();
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ requirejs.config({
|
||||
blueImpGallery: 'lib/blueimp-gallery', // v2.21.3 Image Gallery - https://github.com/blueimp/Gallery
|
||||
blueImpGalleryHelper: 'lib/blueimp-helper', // helper function for Blue Imp Gallery
|
||||
blueImpGalleryBootstrap: 'lib/bootstrap-image-gallery', // v3.4.2 Bootstrap extension for Blue Imp Gallery - https://blueimp.github.io/Bootstrap-Image-Gallery
|
||||
bootstrapConfirmation: 'lib/bootstrap-confirmation', // v1.0.1 Bootstrap extension for inline confirm dialog - https://github.com/tavicu/bs-confirmation
|
||||
bootstrapConfirmation: 'lib/bootstrap-confirmation', // v1.0.5 Bootstrap extension for inline confirm dialog - https://github.com/tavicu/bs-confirmation
|
||||
bootstrapToggle: 'lib/bootstrap2-toggle.min', // v2.2.0 Bootstrap Toggle (Checkbox) - http://www.bootstraptoggle.com
|
||||
lazyload: 'lib/jquery.lazyload.min', // v1.9.5 LazyLoader images - http://www.appelsiini.net/projects/lazyload
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ define(['jquery'], function($) {
|
||||
logIn: 'api/user/logIn', // ajax URL - login
|
||||
logout: 'api/user/logout', // ajax URL - logout
|
||||
deleteLog: 'api/user/deleteLog', // ajax URL - delete character log
|
||||
openIngameWindow: 'api/user/openIngameWindow', // ajax URL - open inGame Window
|
||||
saveUserConfig: 'api/user/saveAccount', // ajax URL - saves/update user account
|
||||
deleteAccount: 'api/user/deleteAccount', // ajax URL - delete Account data
|
||||
// access API
|
||||
@@ -65,6 +66,7 @@ define(['jquery'], function($) {
|
||||
splashOverlay: 300, // "splash" loading overlay
|
||||
headerLink: 100, // links in head bar
|
||||
mapOverlay: 200, // show/hide duration for map overlays
|
||||
mapOverlayLocal: 180, // show/hide duration for map "local" overlay
|
||||
mapMoveSystem: 180, // system position has changed animation
|
||||
mapDeleteSystem: 200, // remove system from map
|
||||
mapModule: 200, // show/hide of an map module
|
||||
|
||||
@@ -46,6 +46,9 @@ define([
|
||||
// cookie hint
|
||||
cookieHintId: 'pf-cookie-hint', // id for "cookie hint" element
|
||||
|
||||
// login
|
||||
ssoButtonClass: 'pf-sso-login-button', // class for SSO login button
|
||||
|
||||
// character select
|
||||
characterSelectionClass: 'pf-character-selection', // class for character panel wrapper
|
||||
characterRowAnimateClass: 'pf-character-row-animate', // class for character panel row during animation
|
||||
@@ -66,7 +69,9 @@ define([
|
||||
serverPanelId: 'pf-server-panel', // id for EVE Online server status panel
|
||||
|
||||
// animation
|
||||
animateElementClass: 'pf-animate-on-visible' // class for elements that will be animated to show
|
||||
animateElementClass: 'pf-animate-on-visible', // class for elements that will be animated to show
|
||||
|
||||
defaultAcceptCookieExpire: 365 // default expire for "accept coolies" cookie
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -123,10 +128,39 @@ define([
|
||||
if(getCookie('cookie') !== '1'){
|
||||
// hint not excepted
|
||||
$('#' + config.cookieHintId).collapse('show');
|
||||
|
||||
// show Cookie accept hint on SSO login button
|
||||
let confirmationSettings = {
|
||||
container: 'body',
|
||||
placement: 'bottom',
|
||||
btnOkClass: 'btn btn-sm btn-default',
|
||||
btnOkLabel: 'dismiss',
|
||||
btnOkIcon: 'fa fa-fw fa-sign-in',
|
||||
title: 'Accept cookies',
|
||||
btnCancelClass: 'btn btn-sm btn-success',
|
||||
btnCancelLabel: 'accept',
|
||||
btnCancelIcon: 'fa fa-fw fa-check',
|
||||
onCancel: function(e, target){
|
||||
// "Accept cookies"
|
||||
setCookie('cookie', 1, config.defaultAcceptCookieExpire);
|
||||
|
||||
// set "default" href
|
||||
let href = $(target).data('bs.confirmation').getHref();
|
||||
$(e.target).attr('href', href);
|
||||
},
|
||||
onConfirm : function(e, target){
|
||||
// "NO cookies" => trigger "default" href link action
|
||||
},
|
||||
href: function(target){
|
||||
return $(target).attr('href');
|
||||
}
|
||||
};
|
||||
|
||||
$('.' + config.ssoButtonClass).confirmation(confirmationSettings);
|
||||
}
|
||||
|
||||
$('#' + config.cookieHintId + ' .btn-success').on('click', function(){
|
||||
setCookie('cookie', 1, 365);
|
||||
setCookie('cookie', 1, config.defaultAcceptCookieExpire);
|
||||
});
|
||||
|
||||
// manual -------------------------------------------------------------
|
||||
|
||||
533
js/app/map/local.js
Normal file
533
js/app/map/local.js
Normal file
@@ -0,0 +1,533 @@
|
||||
/**
|
||||
* map overlay functions for "Nearby" table
|
||||
* Created by Exodus on 13.04.2017.
|
||||
*/
|
||||
|
||||
define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/map/util'
|
||||
], function($, Init, Util, MapUtil) {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
overlayClass: 'pf-map-overlay', // class for all map overlays
|
||||
overlayLocalClass: 'pf-map-overlay-local', // class for "local" overlay
|
||||
|
||||
// left section
|
||||
overlayLocalContentClass: 'pf-map-overlay-local-content', // class for left area - content
|
||||
overlayLocalHeadlineClass: 'pf-map-overlay-headline', // class for headline
|
||||
overlayLocalTableClass: 'pf-local-table', // class for local tables
|
||||
|
||||
// right section
|
||||
overlayLocalTriggerClass: 'pf-map-overlay-local-trigger', // class for open/close trigger icon
|
||||
overlayLocalOpenClass: 'pf-map-overlay-local-open', // class for open status
|
||||
overlayLocalMainClass: 'pf-map-overlay-local-main', // class for right area (always visible)
|
||||
overlayLocalUsersClass: 'pf-map-overlay-local-users', // class for active user count
|
||||
overlayLocalJumpsClass: 'pf-map-overlay-local-jumps', // class for jump distance for table results
|
||||
|
||||
// dataTable
|
||||
tableImageCellClass: 'pf-table-image-cell', // class for table "image" cells
|
||||
tableActionCellClass: 'pf-table-action-cell', // class for table "action" cells
|
||||
tableActionCellIconClass: 'pf-table-action-icon-cell', // class for table "action" icon (icon is part of cell content)
|
||||
|
||||
tableCellEllipsisClass: 'pf-table-cell-ellipsis',
|
||||
tableCellEllipsis80Class: 'pf-table-cell-80',
|
||||
tableCellEllipsis90Class: 'pf-table-cell-90'
|
||||
};
|
||||
|
||||
/**
|
||||
* checks whether overlay is currently open or not
|
||||
* @param overlay
|
||||
* @returns {*}
|
||||
*/
|
||||
let isOpen = (overlay) => {
|
||||
return overlay.hasClass(config.overlayLocalOpenClass);
|
||||
};
|
||||
|
||||
/**
|
||||
* open overlay -> animation
|
||||
* @param overlay
|
||||
*/
|
||||
let openOverlay = (overlay) => {
|
||||
if( !isOpen(overlay) ){
|
||||
let overlayMain = overlay.find('.' + config.overlayLocalMainClass);
|
||||
overlayMain.find('.' + config.overlayLocalTriggerClass).addClass('right');
|
||||
overlay.addClass(config.overlayLocalOpenClass);
|
||||
|
||||
overlay.velocity({
|
||||
width: '350px'
|
||||
},{
|
||||
duration: Init.animationSpeed.mapOverlayLocal,
|
||||
easing: 'easeOut'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* close overlay -> animation
|
||||
* @param overlay
|
||||
*/
|
||||
let closeOverlay = (overlay) => {
|
||||
if( isOpen(overlay) ){
|
||||
let overlayMain = overlay.find('.' + config.overlayLocalMainClass);
|
||||
overlayMain.find('.' + config.overlayLocalTriggerClass).removeClass('right');
|
||||
overlay.removeClass(config.overlayLocalOpenClass);
|
||||
|
||||
overlay.velocity({
|
||||
width: '32px'
|
||||
},{
|
||||
duration: Init.animationSpeed.mapOverlayLocal,
|
||||
easing: 'easeOut'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* sets overlay observer
|
||||
* @param overlay
|
||||
* @param mapId
|
||||
*/
|
||||
let setOverlayObserver = (overlay, mapId) => {
|
||||
let overlayMain = overlay.find('.' + config.overlayLocalMainClass);
|
||||
|
||||
overlayMain.on('click', function(){
|
||||
let overlayMain = $(this).parent('.' + config.overlayLocalClass);
|
||||
let isOpenStatus = isOpen(overlayMain);
|
||||
|
||||
// store current state in indexDB (client)
|
||||
MapUtil.storeLocalData('map', mapId, 'showLocal', !isOpenStatus );
|
||||
|
||||
// trigger open/close
|
||||
if( isOpenStatus ){
|
||||
closeOverlay(overlay);
|
||||
}else{
|
||||
openOverlay(overlay);
|
||||
}
|
||||
});
|
||||
|
||||
overlayMain.initTooltips({
|
||||
container: 'body',
|
||||
placement: 'bottom'
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* filter DataTable rows by column data and return rowIds
|
||||
* @param table
|
||||
* @param data
|
||||
* @param values
|
||||
* @param checkExistence
|
||||
*/
|
||||
let filterRows = (table, data = 'id', values = [], checkExistence = true) => {
|
||||
return table.rows().eq(0).filter( function (rowIdx) {
|
||||
let rowExists = values.indexOf( table.row(rowIdx ).data()[data] ) !== -1;
|
||||
|
||||
if( !checkExistence ){
|
||||
rowExists = !rowExists;
|
||||
}
|
||||
|
||||
return rowExists;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the "headline" within the Overlay
|
||||
* @param overlay
|
||||
* @param systemData
|
||||
* @param characterAll
|
||||
* @param characterLocal
|
||||
*/
|
||||
let updateLocaleHeadline = (overlay, systemData, characterAll = 0, characterLocal = 0) => {
|
||||
let headlineElement = overlay.find('.' + config.overlayLocalHeadlineClass);
|
||||
let userCountElement = overlay.find('.' + config.overlayLocalUsersClass);
|
||||
|
||||
|
||||
let secClassBase = Util.getSecurityClassForSystem('security');
|
||||
let secClass = Util.getSecurityClassForSystem(systemData.security);
|
||||
|
||||
let childElements = headlineElement.children('span');
|
||||
childElements.eq(1).removeClass().addClass(
|
||||
[secClassBase, secClass].join(' ')
|
||||
).text(systemData.security);
|
||||
|
||||
childElements.eq(2).text(systemData.alias ? systemData.alias : systemData.name);
|
||||
|
||||
// update userCount for "near by" count -------------------------------------------------------------------
|
||||
if( characterAll > 0){
|
||||
userCountElement.toggleClass( 'txt-color-green', true).toggleClass( 'txt-color-red', false);
|
||||
}else{
|
||||
userCountElement.toggleClass( 'txt-color-green', false).toggleClass( 'txt-color-red', true);
|
||||
}
|
||||
userCountElement.text(characterAll);
|
||||
|
||||
// update userCount in current system ---------------------------------------------------------------------
|
||||
if( characterLocal > 0){
|
||||
childElements.eq(3).toggleClass( 'txt-color-green', true).toggleClass( 'txt-color-red', false);
|
||||
}else{
|
||||
childElements.eq(3).toggleClass( 'txt-color-green', false).toggleClass( 'txt-color-red', true);
|
||||
}
|
||||
childElements.eq(3).text(characterLocal);
|
||||
};
|
||||
|
||||
/**
|
||||
* updates all changed table rows
|
||||
* @param systemData
|
||||
* @param userData
|
||||
*/
|
||||
$.fn.updateLocalTable = function(systemData, userData){
|
||||
return this.each(function(){
|
||||
let overlay = $(this);
|
||||
let tableElement = overlay.find('.' + config.overlayLocalTableClass);
|
||||
let localTable = tableElement.DataTable();
|
||||
let mapId = systemData.mapId;
|
||||
|
||||
let characterAllIds = [];
|
||||
let characterLocalIds = [];
|
||||
|
||||
// system is on map (just for security check)
|
||||
for(let jumps in userData) {
|
||||
if( userData.hasOwnProperty(jumps) ){
|
||||
jumps = parseInt(jumps);
|
||||
|
||||
for(let j = 0; j < userData[jumps].length; j++){
|
||||
// add jump distance
|
||||
userData[jumps][j].jumps = jumps;
|
||||
|
||||
let rowData = userData[jumps][j];
|
||||
|
||||
// check for existing rows
|
||||
let indexes = filterRows(localTable, 'id', [rowData.id]);
|
||||
|
||||
if(indexes.length > 0){
|
||||
// row exists -> update
|
||||
let changedRow = localTable.row( parseInt(indexes[0]) );
|
||||
let changedRowElement = changedRow.nodes().to$();
|
||||
|
||||
// remove tooltips
|
||||
changedRowElement.find('[title]').tooltip('hide').tooltip('destroy');
|
||||
|
||||
// update data
|
||||
changedRow.data(rowData);
|
||||
}else{
|
||||
// new row
|
||||
localTable.row.add(rowData);
|
||||
}
|
||||
|
||||
if(jumps === 0){
|
||||
characterLocalIds.push(rowData.id);
|
||||
}
|
||||
|
||||
characterAllIds.push(rowData.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove rows that no longer exists ----------------------------------------------------------------------
|
||||
let indexesRemove = filterRows(localTable, 'id', characterAllIds, false);
|
||||
localTable.rows(indexesRemove).remove();
|
||||
|
||||
localTable.draw();
|
||||
|
||||
// update system relevant data in overlay -----------------------------------------------------------------
|
||||
updateLocaleHeadline(overlay, systemData, characterAllIds.length, characterLocalIds.length);
|
||||
|
||||
// open Overlay -------------------------------------------------------------------------------------------
|
||||
if( !isOpen(overlay) ){
|
||||
let promiseStore = MapUtil.getLocaleData('map', mapId);
|
||||
promiseStore.then(function(dataStore) {
|
||||
if(
|
||||
dataStore &&
|
||||
dataStore.showLocal
|
||||
){
|
||||
openOverlay(overlay);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Access a nested JSON object by "dot.notation" syntax
|
||||
* @param obj
|
||||
* @param selector
|
||||
* @returns {*}
|
||||
*/
|
||||
let getDescendantProp = (obj, selector) => {
|
||||
return selector.split('.').reduce(function(a, b) {
|
||||
return a[b];
|
||||
}, obj);
|
||||
};
|
||||
|
||||
/**
|
||||
* init tooltip for a "DataTables" Cell
|
||||
* @param api
|
||||
* @param cell
|
||||
* @param titleSelector
|
||||
*/
|
||||
let initCellTooltip = (api, cell, titleSelector = '') => {
|
||||
$(cell).hover( function(e){
|
||||
let rowIdx = api.cell(cell).index().row;
|
||||
let rowData = api.row(rowIdx).data();
|
||||
|
||||
$(this).tooltip({
|
||||
container: 'body',
|
||||
title: String( getDescendantProp(rowData, titleSelector) ),
|
||||
placement: 'left',
|
||||
delay: 100
|
||||
}).tooltip('show');
|
||||
}, function(e){
|
||||
$(this).tooltip('hide');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* init all map local overlay on a "parent" element
|
||||
* @returns {*}
|
||||
*/
|
||||
$.fn.initLocalOverlay = function(mapId){
|
||||
return this.each(function(){
|
||||
let parentElement = $(this);
|
||||
|
||||
let overlay = $('<div>', {
|
||||
class: [config.overlayClass, config.overlayLocalClass].join(' ')
|
||||
});
|
||||
|
||||
let content = $('<div>', {
|
||||
class: [ 'text-right', config.overlayLocalContentClass].join(' ')
|
||||
});
|
||||
|
||||
// crate new route table
|
||||
let table = $('<table>', {
|
||||
class: ['compact', 'order-column', config.overlayLocalTableClass].join(' ')
|
||||
});
|
||||
|
||||
let overlayMain = $('<div>', {
|
||||
text: '',
|
||||
class: config.overlayLocalMainClass
|
||||
}).append(
|
||||
$('<i>', {
|
||||
class: ['fa', 'fa-chevron-down', 'fa-fw', 'pf-animate-rotate', config.overlayLocalTriggerClass].join(' ')
|
||||
}),
|
||||
$('<span>', {
|
||||
class: ['badge', 'txt-color', 'txt-color-red', config.overlayLocalUsersClass].join(' '),
|
||||
text: 0
|
||||
}),
|
||||
$('<div>', {
|
||||
class: config.overlayLocalJumpsClass
|
||||
}).append(
|
||||
$('<span>', {
|
||||
class: ['badge', 'txt-color', 'txt-color-grayLight'].join(' '),
|
||||
text: MapUtil.config.defaultLocalJumpRadius
|
||||
}).attr('title', 'jumps')
|
||||
)
|
||||
|
||||
);
|
||||
|
||||
let headline = $('<div>', {
|
||||
class: config.overlayLocalHeadlineClass
|
||||
}).append(
|
||||
$('<span>', {
|
||||
html: 'Nearby ',
|
||||
class: 'pull-left'
|
||||
}),
|
||||
$('<span>'),
|
||||
$('<span>'),
|
||||
$('<span>', {
|
||||
class: ['badge', ' txt-color', 'txt-color-red'].join(' '),
|
||||
text: 0
|
||||
})
|
||||
);
|
||||
|
||||
content.append(headline);
|
||||
content.append(table);
|
||||
|
||||
overlay.append(overlayMain);
|
||||
overlay.append(content);
|
||||
|
||||
// set observer
|
||||
setOverlayObserver(overlay, mapId);
|
||||
|
||||
parentElement.append(overlay);
|
||||
|
||||
// init local table ---------------------------------------------------------------------------------------
|
||||
|
||||
table.on('draw.dt', function(e, settings){
|
||||
// init table tooltips
|
||||
$(this).find('td').initTooltips({
|
||||
container: 'body',
|
||||
placement: 'left'
|
||||
});
|
||||
|
||||
// hide pagination in case of only one page
|
||||
let paginationElement = overlay.find('.dataTables_paginate');
|
||||
let pageElements = paginationElement.find('span .paginate_button');
|
||||
if(pageElements.length <= 1){
|
||||
paginationElement.hide();
|
||||
}else{
|
||||
paginationElement.show();
|
||||
}
|
||||
});
|
||||
|
||||
// table init complete
|
||||
table.on( 'init.dt', function (){
|
||||
// init table head tooltips
|
||||
$(this).initTooltips({
|
||||
container: 'body',
|
||||
placement: 'top'
|
||||
});
|
||||
});
|
||||
|
||||
let localTable = table.DataTable( {
|
||||
pageLength: 13, // hint: if pagination visible => we need space to show it
|
||||
paging: true,
|
||||
lengthChange: false,
|
||||
ordering: true,
|
||||
order: [ 0, 'asc' ],
|
||||
info: false,
|
||||
searching: false,
|
||||
hover: false,
|
||||
autoWidth: false,
|
||||
rowId: function(rowData) {
|
||||
return 'pf-local-row_' + rowData.id; // characterId
|
||||
},
|
||||
language: {
|
||||
emptyTable: '<span>You are alone</span>'
|
||||
},
|
||||
columnDefs: [
|
||||
{
|
||||
targets: 0,
|
||||
orderable: true,
|
||||
title: '<span title="jumps" data-toggle="tooltip"> </span>',
|
||||
width: '1px',
|
||||
className: ['pf-help-default', 'text-center'].join(' '),
|
||||
data: 'jumps',
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
let api = this.DataTable();
|
||||
initCellTooltip(api, cell, 'log.system.name');
|
||||
}
|
||||
},{
|
||||
targets: 1,
|
||||
orderable: false,
|
||||
title: '',
|
||||
width: '26px',
|
||||
className: ['pf-help-default', 'text-center', config.tableImageCellClass].join(' '),
|
||||
data: 'log.ship',
|
||||
render: {
|
||||
_: function(data, type, row, meta){
|
||||
let value = data.typeName;
|
||||
if(type === 'display'){
|
||||
value = '<img src="' + Init.url.ccpImageServer + 'Render/' + data.typeId + '_32.png"/>';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
},
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
let api = this.DataTable();
|
||||
initCellTooltip(api, cell, 'log.ship.typeName');
|
||||
}
|
||||
}, {
|
||||
targets: 2,
|
||||
orderable: true,
|
||||
title: 'ship name',
|
||||
width: '80px',
|
||||
data: 'log.ship',
|
||||
render: {
|
||||
_: function(data, type, row, meta){
|
||||
let value = data.name;
|
||||
if(type === 'display'){
|
||||
value = '<div class="' + config.tableCellEllipsisClass + ' ' + config.tableCellEllipsis80Class + '">' + data.name + '</div>';
|
||||
}
|
||||
return value;
|
||||
},
|
||||
sort: 'name'
|
||||
}
|
||||
},{
|
||||
targets: 3,
|
||||
orderable: true,
|
||||
title: 'pilot',
|
||||
data: 'name',
|
||||
render: {
|
||||
_: function(data, type, row, meta){
|
||||
let value = data;
|
||||
if(type === 'display'){
|
||||
value = '<div class="' + config.tableCellEllipsisClass + ' ' + config.tableCellEllipsis90Class + '">' + data + '</div>';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
},{
|
||||
targets: 4,
|
||||
orderable: false,
|
||||
title: '<i title="docked station" data-toggle="tooltip" class="fa fa-home text-right"></i>',
|
||||
width: '10px',
|
||||
className: ['pf-help-default'].join(' '),
|
||||
data: 'log.station',
|
||||
render: {
|
||||
_: function(data, type, row, meta){
|
||||
let value = '';
|
||||
if(
|
||||
type === 'display' &&
|
||||
data.id
|
||||
){
|
||||
value = '<i class="fa fa-home"></i>';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
},
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
let api = this.DataTable();
|
||||
initCellTooltip(api, cell, 'log.station.name');
|
||||
}
|
||||
},{
|
||||
targets: 5,
|
||||
orderable: false,
|
||||
title: '<i title="open ingame" data-toggle="tooltip" class="fa fa-id-card text-right"></i>',
|
||||
width: '10px',
|
||||
className: [config.tableActionCellClass].join(' '),
|
||||
data: 'id',
|
||||
render: {
|
||||
_: function(data, type, row, meta){
|
||||
let value = data;
|
||||
if(type === 'display'){
|
||||
value = '<i class="fa fa-id-card ' + config.tableActionCellIconClass + '"></i>';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
},
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
// open character information window (ingame)
|
||||
$(cell).on('click', { tableApi: this.DataTable(), cellData: cellData }, function(e){
|
||||
let cellData = e.data.tableApi.cell(this).data();
|
||||
Util.openIngameWindow(e.data.cellData);
|
||||
});
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear Overlay and "Reset"
|
||||
* @param mapId
|
||||
*/
|
||||
$.fn.clearLocalTable = function(mapId){
|
||||
return this.each(function(){
|
||||
let overlay = $(this);
|
||||
|
||||
// update locale overlay headline -------------------------------------------------------------------------
|
||||
updateLocaleHeadline(overlay, {
|
||||
name: 'unknown',
|
||||
security: ''
|
||||
});
|
||||
|
||||
// clear all table rows -----------------------------------------------------------------------------------
|
||||
let tableElement = overlay.find('.' + config.overlayLocalTableClass);
|
||||
let localTable = tableElement.DataTable();
|
||||
localTable.rows().remove().draw();
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
@@ -15,7 +15,8 @@ define([
|
||||
'dragToSelect',
|
||||
'select2',
|
||||
'app/map/contextmenu',
|
||||
'app/map/overlay'
|
||||
'app/map/overlay',
|
||||
'app/map/local'
|
||||
], function($, Init, Util, Render, bootbox, MapUtil, System, MagnetizerWrapper) {
|
||||
|
||||
'use strict';
|
||||
@@ -59,13 +60,7 @@ define([
|
||||
systemDialogSelectClass: 'pf-system-dialog-select', // class for system select Element
|
||||
|
||||
// system security classes
|
||||
systemSec: 'pf-system-sec',
|
||||
systemSecHigh: 'pf-system-sec-highSec',
|
||||
systemSecLow: 'pf-system-sec-lowSec',
|
||||
systemSecNull: 'pf-system-sec-nullSec',
|
||||
systemSecWHHeigh: 'pf-system-sec-high',
|
||||
systemSecWHMid: 'pf-system-sec-mid',
|
||||
systemSecWHLow: 'pf-system-sec-low'
|
||||
systemSec: 'pf-system-sec'
|
||||
};
|
||||
|
||||
// active jsPlumb instances currently running
|
||||
@@ -1639,8 +1634,10 @@ define([
|
||||
id: id ? id : 0,
|
||||
source: parseInt( source.data('id') ),
|
||||
sourceName: source.data('name'),
|
||||
sourceAlias: source.getSystemInfo(['alias']),
|
||||
target: parseInt( target.data('id') ),
|
||||
targetName: target.data('name'),
|
||||
targetAlias: target.getSystemInfo(['alias']),
|
||||
scope: connection.scope,
|
||||
type: connectionTypes,
|
||||
updated: updated ? updated : 0
|
||||
@@ -2719,7 +2716,7 @@ define([
|
||||
break;
|
||||
case 'info':
|
||||
// open map info dialog
|
||||
$(document).triggerMenuEvent('ShowMapInfo');
|
||||
$(document).triggerMenuEvent('ShowMapInfo', {tab: 'information'});
|
||||
break;
|
||||
|
||||
}
|
||||
@@ -2873,6 +2870,44 @@ define([
|
||||
mapUpdateQueue.splice(mapQueueIndex, 1);
|
||||
}
|
||||
});
|
||||
|
||||
// update "local" overlay for this map
|
||||
mapContainer.on('pf:updateLocal', function(e, userData){
|
||||
let mapElement = $(this);
|
||||
let mapOverlay = mapElement.getMapOverlay('local');
|
||||
|
||||
let currentCharacterLog = Util.getCurrentCharacterLog();
|
||||
let currentMapData = Util.getCurrentMapData(userData.config.id);
|
||||
let clearLocal = true;
|
||||
|
||||
if(
|
||||
currentMapData &&
|
||||
currentCharacterLog &&
|
||||
currentCharacterLog.system
|
||||
){
|
||||
let currentSystemData = currentMapData.data.systems.filter(function (system) {
|
||||
return system.systemId === currentCharacterLog.system.id;
|
||||
});
|
||||
|
||||
if(currentSystemData.length){
|
||||
// current user system is on this map
|
||||
currentSystemData = currentSystemData[0];
|
||||
|
||||
// check for active users "nearby" (x jumps radius)
|
||||
let nearBySystemData = Util.getNearBySystemData(currentSystemData, currentMapData, MapUtil.config.defaultLocalJumpRadius);
|
||||
let nearByCharacterData = Util.getNearByCharacterData(nearBySystemData, userData.data.systems);
|
||||
|
||||
// update "local" table in overlay
|
||||
mapOverlay.updateLocalTable(currentSystemData, nearByCharacterData);
|
||||
clearLocal = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(clearLocal){
|
||||
mapOverlay.clearLocalTable();
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -3007,15 +3042,16 @@ define([
|
||||
// the current user can only be in a single system ------------------------------------------
|
||||
if(
|
||||
characterLogExists &&
|
||||
!currentUserOnMap &&
|
||||
currentCharacterLog.system.id === systemId
|
||||
){
|
||||
currentUserIsHere = true;
|
||||
currentUserOnMap = true;
|
||||
if( !currentUserOnMap ){
|
||||
currentUserIsHere = true;
|
||||
currentUserOnMap = true;
|
||||
|
||||
// set current location data for header update
|
||||
headerUpdateData.currentSystemId = $(system).data('id');
|
||||
//headerUpdateData.currentSystemName = currentCharacterLog.system.name;
|
||||
// set current location data for header update
|
||||
headerUpdateData.currentSystemId = $(system).data('id');
|
||||
headerUpdateData.currentSystemName = currentCharacterLog.system.name;
|
||||
}
|
||||
}
|
||||
|
||||
system.updateSystemUserData(map, tempUserData, currentUserIsHere);
|
||||
@@ -3289,15 +3325,17 @@ define([
|
||||
*/
|
||||
$.fn.initMapScrollbar = function(){
|
||||
// get Map Scrollbar
|
||||
let scrollableElement = $(this).find('.' + config.mapWrapperClass);
|
||||
let mapTabContentElement = $(this);
|
||||
let scrollableElement = mapTabContentElement.find('.' + config.mapWrapperClass);
|
||||
let mapElement = mapTabContentElement.find('.' + config.mapClass);
|
||||
let mapId = mapElement.data('id');
|
||||
|
||||
|
||||
scrollableElement.initCustomScrollbar({
|
||||
callbacks: {
|
||||
onScroll: function(){
|
||||
// scroll complete
|
||||
let mapElement = $(this).find('.' + config.mapClass);
|
||||
// store new map scrollOffset -> localDB
|
||||
MapUtil.storeLocalData('map', mapElement.data('id'), 'offsetX', Math.abs(this.mcs.left) );
|
||||
MapUtil.storeLocalData('map', mapId, 'offsetX', Math.abs(this.mcs.left) );
|
||||
},
|
||||
onScrollStart: function(){
|
||||
// hide all open xEditable fields
|
||||
@@ -3308,9 +3346,8 @@ define([
|
||||
},
|
||||
whileScrolling:function(){
|
||||
// update scroll position for drag-frame-selection
|
||||
let mapElement = $(scrollableElement).find('.' + config.mapClass);
|
||||
$(mapElement).data('scrollLeft', this.mcs.left);
|
||||
$(mapElement).data('scrollTop', this.mcs.top);
|
||||
mapElement.data('scrollLeft', this.mcs.left);
|
||||
mapElement.data('scrollTop', this.mcs.top);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -3319,6 +3356,8 @@ define([
|
||||
// add map overlays after scrollbar is initialized
|
||||
// because of its absolute position
|
||||
scrollableElement.initMapOverlays();
|
||||
|
||||
scrollableElement.initLocalOverlay(mapId);
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -13,16 +13,13 @@ define([
|
||||
logTimerCount: 3, // map log timer in seconds
|
||||
|
||||
// map
|
||||
mapClass: 'pf-map', // class for all maps
|
||||
mapWrapperClass: 'pf-map-wrapper', // wrapper div (scrollable)
|
||||
|
||||
// map overlay positions
|
||||
mapOverlayClass: 'pf-map-overlay', // class for all map overlays
|
||||
mapOverlayTimerClass: 'pf-map-overlay-timer', // class for map overlay timer e.g. map timer
|
||||
mapOverlayInfoClass: 'pf-map-overlay-info', // class for map overlay info e.g. map info
|
||||
|
||||
// connection overlays
|
||||
|
||||
overlayLocalClass: 'pf-map-overlay-local', // class for map overlay "local" table
|
||||
|
||||
// system
|
||||
systemHeadClass: 'pf-system-head', // class for system head
|
||||
@@ -40,16 +37,6 @@ define([
|
||||
connectionOverlaySmallClass: 'pf-map-connection-small-overlay' // class for "smaller" overlays
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* get mapElement from overlay or any child of that
|
||||
* @param mapOverlay
|
||||
* @returns {JQuery}
|
||||
*/
|
||||
let getMapElementFromOverlay = (mapOverlay) => {
|
||||
return $(mapOverlay).parents('.' + config.mapWrapperClass).find('.' + config.mapClass);
|
||||
};
|
||||
|
||||
/**
|
||||
* get MapObject (jsPlumb) from mapElement
|
||||
* @param mapElement
|
||||
@@ -66,7 +53,7 @@ define([
|
||||
* @returns {*}
|
||||
*/
|
||||
let getMapObjectFromOverlayIcon = (overlayIcon) => {
|
||||
let mapElement = getMapElementFromOverlay(overlayIcon);
|
||||
let mapElement = Util.getMapElementFromOverlay(overlayIcon);
|
||||
|
||||
return getMapObjectFromMapElement( mapElement );
|
||||
};
|
||||
@@ -381,7 +368,7 @@ define([
|
||||
iconClass: ['fa', 'fa-fw', 'fa-tags'],
|
||||
hoverIntent: {
|
||||
over: function(e){
|
||||
let mapElement = getMapElementFromOverlay(this);
|
||||
let mapElement = Util.getMapElementFromOverlay(this);
|
||||
mapElement.find('.' + config.systemHeadClass).each(function(){
|
||||
let system = $(this);
|
||||
// init tooltip if not already exists
|
||||
@@ -399,7 +386,7 @@ define([
|
||||
});
|
||||
},
|
||||
out: function(e){
|
||||
let mapElement = getMapElementFromOverlay(this);
|
||||
let mapElement = Util.getMapElementFromOverlay(this);
|
||||
mapElement.find('.' + config.systemHeadClass).tooltip('hide');
|
||||
}
|
||||
}
|
||||
@@ -411,7 +398,7 @@ define([
|
||||
iconClass: ['fa', 'fa-fw', 'fa-link'],
|
||||
hoverIntent: {
|
||||
over: function(e){
|
||||
let mapElement = getMapElementFromOverlay(this);
|
||||
let mapElement = Util.getMapElementFromOverlay(this);
|
||||
mapElement.showEndpointOverlays();
|
||||
},
|
||||
out: function(e){
|
||||
@@ -518,7 +505,6 @@ define([
|
||||
* @returns {*}
|
||||
*/
|
||||
$.fn.getMapOverlay = function(overlayType){
|
||||
|
||||
let mapWrapperElement = $(this).parents('.' + config.mapWrapperClass);
|
||||
|
||||
let mapOverlay = null;
|
||||
@@ -529,6 +515,9 @@ define([
|
||||
case 'info':
|
||||
mapOverlay = mapWrapperElement.find('.' + config.mapOverlayInfoClass);
|
||||
break;
|
||||
case 'local':
|
||||
mapOverlay = mapWrapperElement.find('.' + config.overlayLocalClass);
|
||||
break;
|
||||
}
|
||||
|
||||
return mapOverlay;
|
||||
@@ -626,7 +615,7 @@ define([
|
||||
duration: Init.animationSpeed.mapOverlay,
|
||||
complete: function(){
|
||||
counterChart.data('interval', false);
|
||||
getMapElementFromOverlay(mapOverlayTimer).trigger('pf:unlocked');
|
||||
Util.getMapElementFromOverlay(mapOverlayTimer).trigger('pf:unlocked');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ define([
|
||||
|
||||
let config = {
|
||||
mapSnapToGridDimension: 20, // px for grid snapping (grid YxY)
|
||||
defaultLocalJumpRadius: 3, // default search radius (in jumps) for "nearby" pilots
|
||||
|
||||
// local storage
|
||||
characterLocalStoragePrefix: 'character_', // prefix for character data local storage key
|
||||
|
||||
@@ -119,7 +119,7 @@ define([
|
||||
firstCell.drawSystemGraphModule(currentSystemData.systemData);
|
||||
|
||||
// draw signature table module
|
||||
firstCell.drawSignatureTableModule(currentSystemData.systemData);
|
||||
firstCell.drawSignatureTableModule(currentSystemData.mapId, currentSystemData.systemData);
|
||||
|
||||
// draw system routes module
|
||||
secondCell.drawSystemRouteModule(currentSystemData.mapId, currentSystemData.systemData);
|
||||
@@ -201,8 +201,12 @@ define([
|
||||
|
||||
let currentMapUserData = Util.getCurrentMapUserData(mapId);
|
||||
|
||||
// update map with current user data
|
||||
|
||||
if(currentMapUserData){
|
||||
// trigger "update local" for this map => async
|
||||
mapElement.trigger('pf:updateLocal', currentMapUserData);
|
||||
|
||||
// update map with current user data
|
||||
mapElement.updateUserData(currentMapUserData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ define([
|
||||
'app/util',
|
||||
'app/logging',
|
||||
'mustache',
|
||||
'app/map/util',
|
||||
'text!img/logo.svg!strip',
|
||||
'text!templates/modules/header.html',
|
||||
'text!templates/modules/footer.html',
|
||||
@@ -24,7 +25,7 @@ define([
|
||||
'dialog/credit',
|
||||
'slidebars',
|
||||
'app/module_map'
|
||||
], function($, Init, Util, Logging, Mustache, TplLogo, TplHead, TplFooter) {
|
||||
], function($, Init, Util, Logging, Mustache, MapUtil, TplLogo, TplHead, TplFooter) {
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -135,26 +136,27 @@ define([
|
||||
});
|
||||
|
||||
body.watchKey('signaturePaste', (e) => {
|
||||
let moduleElement = $('.' + config.systemSigModuleClass);
|
||||
|
||||
// check if there is a signature module active (system clicked)
|
||||
if(moduleElement.length){
|
||||
e = e.originalEvent;
|
||||
let targetElement = $(e.target);
|
||||
|
||||
// do not read clipboard if pasting into form elements
|
||||
if(
|
||||
targetElement.prop('tagName').toLowerCase() !== 'input' &&
|
||||
targetElement.prop('tagName').toLowerCase() !== 'textarea' || (
|
||||
targetElement.is('input[type="search"]') // Datatables "search" field bubbles `paste.DT` event :(
|
||||
)
|
||||
){
|
||||
let clipboard = (e.originalEvent || e).clipboardData.getData('text/plain');
|
||||
moduleElement.trigger('pf:updateSystemSignatureModuleByClipboard', [clipboard]);
|
||||
// just send event to the current active map
|
||||
let activeMap = Util.getMapModule().getActiveMap();
|
||||
if(activeMap){
|
||||
// look for active signature module (active system)
|
||||
let signatureModuleElement = MapUtil.getTabContentElementByMapElement(activeMap).find('.' + config.systemSigModuleClass);
|
||||
if(signatureModuleElement.length){
|
||||
e = e.originalEvent;
|
||||
let targetElement = $(e.target);
|
||||
// do not read clipboard if pasting into form elements
|
||||
if(
|
||||
targetElement.prop('tagName').toLowerCase() !== 'input' &&
|
||||
targetElement.prop('tagName').toLowerCase() !== 'textarea' || (
|
||||
targetElement.is('input[type="search"]') // Datatables "search" field bubbles `paste.DT` event :(
|
||||
)
|
||||
){
|
||||
let clipboard = (e.originalEvent || e).clipboardData.getData('text/plain');
|
||||
signatureModuleElement.trigger('pf:updateSystemSignatureModuleByClipboard', [clipboard]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
@@ -321,7 +323,7 @@ define([
|
||||
class: 'fa fa-street-view fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowMapInfo');
|
||||
$(document).triggerMenuEvent('ShowMapInfo', {tab: 'information'});
|
||||
})
|
||||
).append(
|
||||
getMenuHeadline('Settings')
|
||||
@@ -494,7 +496,7 @@ define([
|
||||
|
||||
// active pilots
|
||||
$('.' + config.headActiveUserClass).find('a').on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowMapInfo');
|
||||
$(document).triggerMenuEvent('ShowMapInfo', {tab: 'activity'});
|
||||
});
|
||||
|
||||
// current location
|
||||
@@ -659,9 +661,9 @@ define([
|
||||
return false;
|
||||
});
|
||||
|
||||
$(document).on('pf:menuShowMapInfo', function(e){
|
||||
$(document).on('pf:menuShowMapInfo', function(e, data){
|
||||
// show map information dialog
|
||||
$.fn.showMapInfoDialog();
|
||||
$.fn.showMapInfoDialog(data);
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ define([
|
||||
tableImageSmallCellClass: 'pf-table-image-small-cell', // class for table "small image" cells
|
||||
tableActionCellClass: 'pf-table-action-cell', // class for table "action" cells
|
||||
tableCounterCellClass: 'pf-table-counter-cell', // class for table "counter" cells
|
||||
tableActionCellIconClass: 'pf-table-action-icon-cell', // class for table "action" icon (icon is part of cell content)
|
||||
|
||||
loadingOptions: { // config for loading overlay
|
||||
icon: {
|
||||
@@ -625,8 +626,16 @@ define([
|
||||
// table init complete
|
||||
userTable.on( 'init.dt', function () {
|
||||
usersElement.hideLoadingAnimation();
|
||||
|
||||
// init table tooltips
|
||||
let tooltipElements = usersElement.find('[data-toggle="tooltip"]');
|
||||
tooltipElements.tooltip();
|
||||
});
|
||||
|
||||
let getIconForInformationWindow = () => {
|
||||
return '<i class="fa fa-fw fa-id-card ' + config.tableActionCellIconClass + '" title="open ingame" data-toggle="tooltip"></i>';
|
||||
};
|
||||
|
||||
// users table ================================================================================================
|
||||
// prepare users data for dataTables
|
||||
let currentMapUserData = Util.getCurrentMapUserData( mapData.config.id );
|
||||
@@ -681,7 +690,9 @@ define([
|
||||
searchable: true,
|
||||
data: 'log.ship',
|
||||
render: {
|
||||
_: 'typeName',
|
||||
_: function(data, type, row){
|
||||
return data.typeName + ' <i class="fa fa-fw fa-question-circle pf-help" title="' + data.name + '" data-toggle="tooltip"></i>';
|
||||
},
|
||||
sort: 'typeName'
|
||||
}
|
||||
},{
|
||||
@@ -702,7 +713,24 @@ define([
|
||||
title: 'pilot',
|
||||
orderable: true,
|
||||
searchable: true,
|
||||
data: 'name'
|
||||
className: [config.tableActionCellClass].join(' '),
|
||||
data: 'name',
|
||||
render: {
|
||||
_: function(data, type, row, meta){
|
||||
let value = data;
|
||||
if(type === 'display'){
|
||||
value += ' ' + getIconForInformationWindow();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
},
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
// open character information window (ingame)
|
||||
$(cell).on('click', { tableApi: this.DataTable() }, function(e) {
|
||||
let rowData = e.data.tableApi.row(this).data();
|
||||
Util.openIngameWindow(rowData.id);
|
||||
});
|
||||
}
|
||||
},{
|
||||
targets: 4,
|
||||
title: '',
|
||||
@@ -721,9 +749,23 @@ define([
|
||||
title: 'corporation',
|
||||
orderable: true,
|
||||
searchable: true,
|
||||
className: [config.tableActionCellClass].join(' '),
|
||||
data: 'corporation',
|
||||
render: {
|
||||
_: 'name'
|
||||
_: function (data, type, row, meta) {
|
||||
let value = data.name;
|
||||
if(type === 'display'){
|
||||
value += ' ' + getIconForInformationWindow();
|
||||
}
|
||||
return value;
|
||||
}
|
||||
},
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
// open character information window (ingame)
|
||||
$(cell).on('click', { tableApi: this.DataTable() }, function(e) {
|
||||
let cellData = e.data.tableApi.cell(this).data();
|
||||
Util.openIngameWindow(cellData.id);
|
||||
});
|
||||
}
|
||||
},{
|
||||
targets: 6,
|
||||
@@ -753,9 +795,9 @@ define([
|
||||
|
||||
/**
|
||||
* shows the map information modal dialog
|
||||
* @param options
|
||||
*/
|
||||
$.fn.showMapInfoDialog = function(){
|
||||
|
||||
$.fn.showMapInfoDialog = function(options){
|
||||
let activeMap = Util.getMapModule().getActiveMap();
|
||||
let mapData = activeMap.getMapDataFromClient({forceData: true});
|
||||
|
||||
@@ -770,7 +812,11 @@ define([
|
||||
mapInfoId: config.mapInfoId,
|
||||
mapInfoSystemsId: config.mapInfoSystemsId,
|
||||
mapInfoConnectionsId: config.mapInfoConnectionsId,
|
||||
mapInfoUsersId: config.mapInfoUsersId
|
||||
mapInfoUsersId: config.mapInfoUsersId,
|
||||
|
||||
// default open tab ----------
|
||||
openTabInformation: options.tab === 'information',
|
||||
openTabActivity: options.tab === 'activity'
|
||||
};
|
||||
|
||||
let content = Mustache.render(template, data);
|
||||
|
||||
@@ -9,7 +9,7 @@ define([
|
||||
'app/util',
|
||||
'app/render',
|
||||
'bootbox'
|
||||
], function($, Init, Util, Render, bootbox, MapUtil) {
|
||||
], function($, Init, Util, Render, bootbox) {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
|
||||
@@ -145,10 +145,21 @@ define([
|
||||
}
|
||||
}).on('change', function(e){
|
||||
// select changed
|
||||
}).on('select2:open', function(){
|
||||
// clear selected system (e.g. default system)
|
||||
// => improves usability (not necessary). There is a small "x" whe it could be cleared manually
|
||||
if(
|
||||
options.maxSelectionLength === 1 &&
|
||||
$(this).val() !== null
|
||||
){
|
||||
$(this).val('').trigger('change');
|
||||
}
|
||||
})
|
||||
).done(function(){
|
||||
// open select
|
||||
selectElement.select2('open');
|
||||
).done(function(a,b){
|
||||
// open select if not already pre-selected
|
||||
if($(this).val() === null){
|
||||
selectElement.select2('open');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ define([
|
||||
], function($, Init, Util, Render, MapUtil) {
|
||||
'use strict';
|
||||
|
||||
var config = {
|
||||
let config = {
|
||||
// module info
|
||||
moduleClass: 'pf-module', // class for each module
|
||||
|
||||
@@ -35,41 +35,38 @@ define([
|
||||
descriptionArea: 'pf-system-info-description-area', // class for "description" area
|
||||
addDescriptionButtonClass: 'pf-system-info-description-button', // class for "add description" button
|
||||
moduleElementToolbarClass: 'pf-table-tools', // class for "module toolbar" element
|
||||
moduleToolbarActionId: 'pf-system-info-collapse-container', // id for "module toolbar action" element
|
||||
tableToolsActionClass: 'pf-table-tools-action', // class for "edit" action
|
||||
|
||||
descriptionTextareaElementClass: 'pf-system-info-description', // class for "description" textarea element (xEditable)
|
||||
descriptionTextareaCharCounter: 'pf-form-field-char-count' // class for "character counter" element for form field
|
||||
};
|
||||
|
||||
// disable Module update temporary (until. some requests/animations) are finished
|
||||
var disableModuleUpdate = true;
|
||||
let disableModuleUpdate = true;
|
||||
|
||||
// animation speed values
|
||||
var animationSpeedToolbarAction = 200;
|
||||
let animationSpeedToolbarAction = 200;
|
||||
|
||||
// max character length for system description
|
||||
var maxDescriptionLength = 512;
|
||||
let maxDescriptionLength = 512;
|
||||
|
||||
/**
|
||||
* set module observer and look for relevant system data to update
|
||||
*/
|
||||
var setModuleObserver = function(moduleElement){
|
||||
let setModuleObserver = function(moduleElement){
|
||||
|
||||
$(document).off('pf:updateSystemInfoModule').on('pf:updateSystemInfoModule', function(e, data){
|
||||
if(data){
|
||||
moduleElement.updateSystemInfoModule(data);
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* shows the tool action element by animation
|
||||
* @param toolsActionElement
|
||||
*/
|
||||
var showToolsActionElement = function(){
|
||||
|
||||
// "toolbar action" element
|
||||
var toolsActionElement = $('#' + config.moduleToolbarActionId);
|
||||
|
||||
let showToolsActionElement = function(toolsActionElement){
|
||||
toolsActionElement.velocity('stop').velocity({
|
||||
opacity: 1,
|
||||
height: '100%'
|
||||
@@ -82,12 +79,9 @@ define([
|
||||
|
||||
/**
|
||||
* hides the tool action element by animation
|
||||
* @param toolsActionElement
|
||||
*/
|
||||
var hideToolsActionElement = function(){
|
||||
|
||||
// "toolbar action" element
|
||||
var toolsActionElement = $('#' + config.moduleToolbarActionId);
|
||||
|
||||
let hideToolsActionElement = function(toolsActionElement){
|
||||
toolsActionElement.velocity('stop').velocity('reverse', {
|
||||
display: 'none',
|
||||
visibility: 'hidden'
|
||||
@@ -106,24 +100,23 @@ define([
|
||||
return;
|
||||
}
|
||||
|
||||
var moduleElement = $(this);
|
||||
let moduleElement = $(this);
|
||||
|
||||
var systemId = moduleElement.data('id');
|
||||
let systemId = moduleElement.data('id');
|
||||
|
||||
if(systemId === systemData.id){
|
||||
// update module
|
||||
|
||||
// system status =====================================================================================
|
||||
var systemStatusLabelElement = moduleElement.find('.' + config.systemInfoStatusLabelClass);
|
||||
var systemStatusId = parseInt( systemStatusLabelElement.attr( config.systemInfoStatusAttributeName ) );
|
||||
|
||||
let systemStatusLabelElement = moduleElement.find('.' + config.systemInfoStatusLabelClass);
|
||||
let systemStatusId = parseInt( systemStatusLabelElement.attr( config.systemInfoStatusAttributeName ) );
|
||||
|
||||
if(systemStatusId !== systemData.status.id){
|
||||
// status changed
|
||||
|
||||
var currentStatusClass = Util.getStatusInfoForSystem(systemStatusId, 'class');
|
||||
var newStatusClass = Util.getStatusInfoForSystem(systemData.status.id, 'class');
|
||||
var newStatusLabel = Util.getStatusInfoForSystem(systemData.status.id, 'label');
|
||||
let currentStatusClass = Util.getStatusInfoForSystem(systemStatusId, 'class');
|
||||
let newStatusClass = Util.getStatusInfoForSystem(systemData.status.id, 'class');
|
||||
let newStatusLabel = Util.getStatusInfoForSystem(systemData.status.id, 'label');
|
||||
|
||||
systemStatusLabelElement.removeClass(currentStatusClass).addClass(newStatusClass).text(newStatusLabel);
|
||||
|
||||
@@ -132,43 +125,40 @@ define([
|
||||
}
|
||||
|
||||
// description textarea element ======================================================================
|
||||
var descriptionTextareaElement = moduleElement.find('.' + config.descriptionTextareaElementClass);
|
||||
|
||||
var description = descriptionTextareaElement.editable('getValue', true);
|
||||
let descriptionTextareaElement = moduleElement.find('.' + config.descriptionTextareaElementClass);
|
||||
let description = descriptionTextareaElement.editable('getValue', true);
|
||||
|
||||
if(description !== systemData.description){
|
||||
// description changed
|
||||
|
||||
// description button
|
||||
var descriptionButton = moduleElement.find('.' + config.addDescriptionButtonClass);
|
||||
let descriptionButton = moduleElement.find('.' + config.addDescriptionButtonClass);
|
||||
|
||||
// set new value
|
||||
descriptionTextareaElement.editable('setValue', systemData.description);
|
||||
|
||||
let actionElement = descriptionButton.siblings('.' + config.tableToolsActionClass);
|
||||
|
||||
if(systemData.description.length === 0){
|
||||
// show/activate description field
|
||||
|
||||
// show button if value is empty
|
||||
descriptionButton.show();
|
||||
|
||||
|
||||
hideToolsActionElement();
|
||||
|
||||
hideToolsActionElement(actionElement);
|
||||
}else{
|
||||
// hide/disable description field
|
||||
|
||||
// hide tool button
|
||||
descriptionButton.hide();
|
||||
|
||||
showToolsActionElement();
|
||||
showToolsActionElement(actionElement);
|
||||
}
|
||||
}
|
||||
|
||||
// created/updated tooltip ===========================================================================
|
||||
|
||||
var nameRowElement = $(moduleElement).find('.' + config.systemInfoNameInfoClass);
|
||||
let nameRowElement = $(moduleElement).find('.' + config.systemInfoNameInfoClass);
|
||||
|
||||
var tooltipData = {
|
||||
let tooltipData = {
|
||||
created: systemData.created,
|
||||
updated: systemData.updated
|
||||
};
|
||||
@@ -176,7 +166,7 @@ define([
|
||||
nameRowElement.addCharacterInfoTooltip( tooltipData );
|
||||
}
|
||||
|
||||
$('.' + config.descriptionArea).hideLoadingAnimation();
|
||||
moduleElement.find('.' + config.descriptionArea).hideLoadingAnimation();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -185,13 +175,13 @@ define([
|
||||
* @param charCounterElement
|
||||
* @param maxCharLength
|
||||
*/
|
||||
var updateCounter = function(field, charCounterElement, maxCharLength){
|
||||
var value = field.val();
|
||||
var inputLength = value.length;
|
||||
let updateCounter = function(field, charCounterElement, maxCharLength){
|
||||
let value = field.val();
|
||||
let inputLength = value.length;
|
||||
|
||||
// line breaks are 2 characters!
|
||||
var newLines = value.match(/(\r\n|\n|\r)/g);
|
||||
var addition = 0;
|
||||
let newLines = value.match(/(\r\n|\n|\r)/g);
|
||||
let addition = 0;
|
||||
if (newLines != null) {
|
||||
addition = newLines.length;
|
||||
}
|
||||
@@ -212,10 +202,10 @@ define([
|
||||
* @param mapId
|
||||
* @param systemData
|
||||
*/
|
||||
var drawModule = function(parentElement, mapId, systemData){
|
||||
let drawModule = function(parentElement, mapId, systemData){
|
||||
|
||||
// create new module container
|
||||
var moduleElement = $('<div>', {
|
||||
let moduleElement = $('<div>', {
|
||||
class: [config.moduleClass, config.systemInfoModuleClass].join(' '),
|
||||
css: {opacity: 0}
|
||||
});
|
||||
@@ -226,14 +216,14 @@ define([
|
||||
parentElement.prepend(moduleElement);
|
||||
|
||||
// shattered wormhole info data
|
||||
var shatteredWormholeInfo = false;
|
||||
let shatteredWormholeInfo = false;
|
||||
|
||||
// add security class for statics
|
||||
if(
|
||||
systemData.statics &&
|
||||
systemData.statics.length > 0
|
||||
){
|
||||
for(var i = 0; i < systemData.statics.length; i++){
|
||||
for(let i = 0; i < systemData.statics.length; i++){
|
||||
systemData.statics[i].class = Util.getSecurityClassForSystem( systemData.statics[i].security );
|
||||
}
|
||||
}else if(systemData.type.id === 1){
|
||||
@@ -241,27 +231,26 @@ define([
|
||||
shatteredWormholeInfo = true;
|
||||
}
|
||||
|
||||
var effectName = MapUtil.getEffectInfoForSystem(systemData.effect, 'name');
|
||||
var effectClass = MapUtil.getEffectInfoForSystem(systemData.effect, 'class');
|
||||
let effectName = MapUtil.getEffectInfoForSystem(systemData.effect, 'name');
|
||||
let effectClass = MapUtil.getEffectInfoForSystem(systemData.effect, 'class');
|
||||
|
||||
// systemInfo template config
|
||||
var moduleConfig = {
|
||||
let moduleConfig = {
|
||||
name: 'modules/system_info',
|
||||
position: moduleElement,
|
||||
link: 'append',
|
||||
functions: {
|
||||
after: function(){
|
||||
let tempModuleElement = parentElement.find('.' + config.systemInfoModuleClass);
|
||||
|
||||
// lock "description" field until first update
|
||||
$('.' + config.descriptionArea).showLoadingAnimation();
|
||||
|
||||
|
||||
var tempModuleElement = $('.' + config.systemInfoModuleClass);
|
||||
tempModuleElement.find('.' + config.descriptionArea).showLoadingAnimation();
|
||||
|
||||
// "add description" button
|
||||
var descriptionButton = tempModuleElement.find('.' + config.addDescriptionButtonClass);
|
||||
let descriptionButton = tempModuleElement.find('.' + config.addDescriptionButtonClass);
|
||||
|
||||
// description textarea element
|
||||
var descriptionTextareaElement = tempModuleElement.find('.' + config.descriptionTextareaElementClass);
|
||||
let descriptionTextareaElement = tempModuleElement.find('.' + config.descriptionTextareaElementClass);
|
||||
|
||||
// init description textarea
|
||||
descriptionTextareaElement.editable({
|
||||
@@ -304,9 +293,8 @@ define([
|
||||
Util.showNotify({title: 'System updated', text: 'Name: ' + response.name, type: 'success'});
|
||||
},
|
||||
error: function(jqXHR, newValue){
|
||||
|
||||
var reason = '';
|
||||
var status = '';
|
||||
let reason = '';
|
||||
let status = '';
|
||||
if(jqXHR.name){
|
||||
// save error new sig (mass save)
|
||||
reason = jqXHR.name;
|
||||
@@ -324,13 +312,13 @@ define([
|
||||
|
||||
// on xEditable open -------------------------------------------------------------------------
|
||||
descriptionTextareaElement.on('shown', function(e, editable){
|
||||
var textarea = editable.input.$input;
|
||||
let textarea = editable.input.$input;
|
||||
|
||||
// disable module update until description field is open
|
||||
disableModuleUpdate = true;
|
||||
|
||||
// create character counter
|
||||
var charCounter = $('<kbd>', {
|
||||
let charCounter = $('<kbd>', {
|
||||
class: [config.descriptionTextareaCharCounter, 'txt-color', 'text-right'].join(' ')
|
||||
});
|
||||
textarea.parent().next().append(charCounter);
|
||||
@@ -345,11 +333,10 @@ define([
|
||||
|
||||
// on xEditable close ------------------------------------------------------------------------
|
||||
descriptionTextareaElement.on('hidden', function(e){
|
||||
var value = $(this).editable('getValue', true);
|
||||
|
||||
let value = $(this).editable('getValue', true);
|
||||
if(value.length === 0){
|
||||
// show button if value is empty
|
||||
hideToolsActionElement();
|
||||
hideToolsActionElement(descriptionButton.siblings('.' + config.tableToolsActionClass));
|
||||
descriptionButton.show();
|
||||
}
|
||||
|
||||
@@ -360,6 +347,7 @@ define([
|
||||
// enable xEditable field on Button click ----------------------------------------------------
|
||||
descriptionButton.on('click', function(e){
|
||||
e.stopPropagation();
|
||||
let descriptionButton = $(this);
|
||||
|
||||
// hide tool buttons
|
||||
descriptionButton.hide();
|
||||
@@ -367,24 +355,23 @@ define([
|
||||
// show field *before* showing the element
|
||||
descriptionTextareaElement.editable('show');
|
||||
|
||||
showToolsActionElement();
|
||||
showToolsActionElement(descriptionButton.siblings('.' + config.tableToolsActionClass));
|
||||
});
|
||||
|
||||
|
||||
// init tooltips -----------------------------------------------------------------------------
|
||||
var tooltipElements = $('.' + config.systemInfoModuleClass + ' [data-toggle="tooltip"]');
|
||||
let tooltipElements = tempModuleElement.find('[data-toggle="tooltip"]');
|
||||
tooltipElements.tooltip();
|
||||
|
||||
// init system effect popover ----------------------------------------------------------------
|
||||
var infoEffectElement = $(moduleElement).find('.' + config.systemInfoEffectInfoClass);
|
||||
let infoEffectElement = $(moduleElement).find('.' + config.systemInfoEffectInfoClass);
|
||||
|
||||
if(infoEffectElement.length){
|
||||
// effect row exists -> get effect data
|
||||
var systemEffectData = Util.getSystemEffectData( systemData.security, systemData.effect);
|
||||
let systemEffectData = Util.getSystemEffectData( systemData.security, systemData.effect);
|
||||
|
||||
if(systemEffectData !== false){
|
||||
// transform data into table
|
||||
var systemEffectTable = Util.getSystemEffectTable( systemEffectData );
|
||||
let systemEffectTable = Util.getSystemEffectTable( systemEffectData );
|
||||
|
||||
infoEffectElement.popover({
|
||||
html: true,
|
||||
@@ -403,9 +390,9 @@ define([
|
||||
|
||||
// init static wormhole information ----------------------------------------------------------
|
||||
if(systemData.statics){
|
||||
for(var i = 0; i < systemData.statics.length; i++){
|
||||
var staticData = systemData.statics[i];
|
||||
var staticRowElement = tempModuleElement.find('.' + config.systemInfoWormholeClass + staticData.name);
|
||||
for(let i = 0; i < systemData.statics.length; i++){
|
||||
let staticData = systemData.statics[i];
|
||||
let staticRowElement = tempModuleElement.find('.' + config.systemInfoWormholeClass + staticData.name);
|
||||
staticRowElement.addWormholeInfoTooltip(staticData);
|
||||
}
|
||||
}
|
||||
@@ -424,13 +411,13 @@ define([
|
||||
|
||||
function details_in_popup(popoverElement){
|
||||
popoverElement = $(popoverElement);
|
||||
var popover = popoverElement.data('bs.popover');
|
||||
let popover = popoverElement.data('bs.popover');
|
||||
|
||||
|
||||
$.ajax({
|
||||
url: popoverElement.data('url'),
|
||||
success: function(data){
|
||||
var systemEffectTable = Util.getSystemsInfoTable( data.systemData );
|
||||
let systemEffectTable = Util.getSystemsInfoTable( data.systemData );
|
||||
popover.options.content = systemEffectTable;
|
||||
// reopen popover (new content size)
|
||||
popover.show();
|
||||
@@ -444,7 +431,7 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
var moduleData = {
|
||||
let moduleData = {
|
||||
system: systemData,
|
||||
tableClass: config.systemInfoTableClass,
|
||||
nameInfoClass: config.systemInfoNameInfoClass,
|
||||
@@ -463,7 +450,7 @@ define([
|
||||
effectClass: effectClass,
|
||||
moduleToolbarClass: config.moduleElementToolbarClass,
|
||||
descriptionButtonClass: config.addDescriptionButtonClass,
|
||||
moduleToolbarActionId: config.moduleToolbarActionId,
|
||||
tableToolsActionClass: config.tableToolsActionClass,
|
||||
descriptionTextareaClass: config.descriptionTextareaElementClass,
|
||||
|
||||
shatteredWormholeInfo: shatteredWormholeInfo,
|
||||
@@ -483,7 +470,7 @@ define([
|
||||
* show system info module with animation
|
||||
* @param moduleElement
|
||||
*/
|
||||
var showModule = function(moduleElement){
|
||||
let showModule = function(moduleElement){
|
||||
moduleElement.velocity('transition.slideDownIn', {
|
||||
duration: Init.animationSpeed.mapModule,
|
||||
delay: Init.animationSpeed.mapModule,
|
||||
@@ -504,10 +491,10 @@ define([
|
||||
*/
|
||||
$.fn.drawSystemInfoModule = function(mapId, systemData){
|
||||
|
||||
var parentElement = $(this);
|
||||
let parentElement = $(this);
|
||||
|
||||
// check if module already exists
|
||||
var moduleElement = parentElement.find('.' + config.systemInfoModuleClass);
|
||||
let moduleElement = parentElement.find('.' + config.systemInfoModuleClass);
|
||||
|
||||
if(moduleElement.length > 0){
|
||||
moduleElement.velocity('transition.slideDownOut', {
|
||||
|
||||
@@ -183,6 +183,7 @@ define([
|
||||
wormholes: (rowData.hasOwnProperty('wormholes')) ? rowData.wormholes | 0 : 1,
|
||||
wormholesReduced: (rowData.hasOwnProperty('wormholesReduced')) ? rowData.wormholesReduced | 0 : 1,
|
||||
wormholesCritical: (rowData.hasOwnProperty('wormholesCritical')) ? rowData.wormholesCritical | 0 : 1,
|
||||
wormholesFrigate: (rowData.hasOwnProperty('wormholesFrigate')) ? rowData.wormholesFrigate | 0 : 1,
|
||||
wormholesEOL: (rowData.hasOwnProperty('wormholesEOL')) ? rowData.wormholesEOL | 0 : 1,
|
||||
safer: (rowData.hasOwnProperty('safer')) ? rowData.safer.value | 0 : 0
|
||||
};
|
||||
@@ -273,6 +274,7 @@ define([
|
||||
wormholes: routeDialogData.hasOwnProperty('wormholes') ? parseInt( routeDialogData.wormholes ) : 0,
|
||||
wormholesReduced: routeDialogData.hasOwnProperty('wormholesReduced') ? parseInt( routeDialogData.wormholesReduced ) : 0,
|
||||
wormholesCritical: routeDialogData.hasOwnProperty('wormholesCritical') ? parseInt( routeDialogData.wormholesCritical ) : 0,
|
||||
wormholesFrigate: routeDialogData.hasOwnProperty('wormholesFrigate') ? parseInt( routeDialogData.wormholesFrigate ) : 0,
|
||||
wormholesEOL: routeDialogData.hasOwnProperty('wormholesEOL') ? parseInt( routeDialogData.wormholesEOL ) : 0
|
||||
}]
|
||||
};
|
||||
@@ -480,12 +482,14 @@ define([
|
||||
let wormholeCheckbox = routeDialog.find('input[type="checkbox"][name="wormholes"]');
|
||||
let wormholeReducedCheckbox = routeDialog.find('input[type="checkbox"][name="wormholesReduced"]');
|
||||
let wormholeCriticalCheckbox = routeDialog.find('input[type="checkbox"][name="wormholesCritical"]');
|
||||
let wormholeFrigateCheckbox = routeDialog.find('input[type="checkbox"][name="wormholesFrigate"]');
|
||||
let wormholeEolCheckbox = routeDialog.find('input[type="checkbox"][name="wormholesEOL"]');
|
||||
|
||||
// store current "checked" state for each box ---------------------------------------------
|
||||
let storeCheckboxStatus = function(){
|
||||
wormholeReducedCheckbox.data('selectState', wormholeReducedCheckbox.prop('checked'));
|
||||
wormholeCriticalCheckbox.data('selectState', wormholeCriticalCheckbox.prop('checked'));
|
||||
wormholeFrigateCheckbox.data('selectState', wormholeFrigateCheckbox.prop('checked'));
|
||||
wormholeEolCheckbox.data('selectState', wormholeEolCheckbox.prop('checked'));
|
||||
};
|
||||
|
||||
@@ -495,10 +499,12 @@ define([
|
||||
if( $(this).is(':checked') ){
|
||||
wormholeReducedCheckbox.prop('disabled', false);
|
||||
wormholeCriticalCheckbox.prop('disabled', false);
|
||||
wormholeFrigateCheckbox.prop('disabled', false);
|
||||
wormholeEolCheckbox.prop('disabled', false);
|
||||
|
||||
wormholeReducedCheckbox.prop('checked', wormholeReducedCheckbox.data('selectState'));
|
||||
wormholeCriticalCheckbox.prop('checked', wormholeCriticalCheckbox.data('selectState'));
|
||||
wormholeFrigateCheckbox.prop('checked', wormholeFrigateCheckbox.data('selectState'));
|
||||
wormholeEolCheckbox.prop('checked', wormholeEolCheckbox.data('selectState'));
|
||||
}else{
|
||||
storeCheckboxStatus();
|
||||
@@ -507,6 +513,8 @@ define([
|
||||
wormholeReducedCheckbox.prop('disabled', true);
|
||||
wormholeCriticalCheckbox.prop('checked', false);
|
||||
wormholeCriticalCheckbox.prop('disabled', true);
|
||||
wormholeFrigateCheckbox.prop('checked', false);
|
||||
wormholeFrigateCheckbox.prop('disabled', true);
|
||||
wormholeEolCheckbox.prop('checked', false);
|
||||
wormholeEolCheckbox.prop('disabled', true);
|
||||
}
|
||||
@@ -580,6 +588,7 @@ define([
|
||||
wormholes: routeData.wormholes,
|
||||
wormholesReduced: routeData.wormholesReduced,
|
||||
wormholesCritical: routeData.wormholesCritical,
|
||||
wormholesFrigate: routeData.wormholesFrigate,
|
||||
wormholesEOL: routeData.wormholesEOL,
|
||||
safer: {
|
||||
value: routeData.safer,
|
||||
|
||||
@@ -64,8 +64,8 @@ define([
|
||||
// disable "copy&paste" from clipboard (until request finished)
|
||||
let disableCopyFromClipboard = false;
|
||||
|
||||
// cache for dataTable object
|
||||
let signatureTable = null;
|
||||
// cache for dataTable object6
|
||||
let dataTableInstances = {};
|
||||
|
||||
// empty signatureData object -> for "add row" table
|
||||
let emptySignatureData = {
|
||||
@@ -106,16 +106,117 @@ define([
|
||||
let signatureGroupsLabels = Util.getSignatureGroupInfo('label');
|
||||
let signatureGroupsNames = Util.getSignatureGroupInfo('name');
|
||||
|
||||
/**
|
||||
* check whether a dataTable API instance exists in the global cache
|
||||
* args: 1. mapId, 2. systemId, 3, tableType (primary/secondary) string
|
||||
* @param args
|
||||
* @returns {boolean}
|
||||
*/
|
||||
let checkDataTableInstance = (...args) => {
|
||||
let obj = dataTableInstances;
|
||||
for(let arg of args){
|
||||
if ( !obj || !obj.hasOwnProperty(arg) ){
|
||||
return false;
|
||||
}
|
||||
obj = obj[arg];
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* stores a dataTableApi instance to global cache ( overwrites existing)
|
||||
* @param mapId
|
||||
* @param systemId
|
||||
* @param tableType
|
||||
* @param instance
|
||||
*/
|
||||
let setDataTableInstance = (mapId, systemId, tableType, instance) => {
|
||||
let tmpObj = {
|
||||
[mapId]: {
|
||||
[systemId]: {
|
||||
[tableType]: instance
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$.extend(true, dataTableInstances, tmpObj);
|
||||
};
|
||||
|
||||
/**
|
||||
* get a dataTableApi instance from global cache
|
||||
* @param mapId
|
||||
* @param systemId
|
||||
* @param tableType
|
||||
* @returns {*}
|
||||
*/
|
||||
let getDataTableInstance = (mapId, systemId, tableType) => {
|
||||
let instance = null;
|
||||
if( checkDataTableInstance(mapId, systemId, tableType) ){
|
||||
instance = dataTableInstances[mapId][systemId][tableType];
|
||||
}
|
||||
return instance;
|
||||
};
|
||||
|
||||
/**
|
||||
* get dataTable instance from "moduleElement" (DOM node)
|
||||
* @param moduleElement
|
||||
* @param tableType
|
||||
* @returns {*}
|
||||
*/
|
||||
let getDataTableInstanceByModuleElement = (moduleElement, tableType) => {
|
||||
return getDataTableInstance(moduleElement.data('mapId'), moduleElement.data('systemId'), tableType);
|
||||
};
|
||||
|
||||
/**
|
||||
* delete a dataTableApi instance from global cache
|
||||
* -> see checkDataTableInstance() for parameter order
|
||||
* @param args
|
||||
*/
|
||||
let deleteDataTableInstance = (...args) => {
|
||||
// check if instance exists
|
||||
if( checkDataTableInstance.apply(null, args) ){
|
||||
|
||||
// callback for "leaf" delete callback
|
||||
let deleteCallback = (dataTableApi) => {
|
||||
dataTableApi.destroy();
|
||||
};
|
||||
|
||||
// recursive delete from dataTableInstances Object cache
|
||||
let deepDelete = (target, obj, callback) => {
|
||||
if(target.length > 1){
|
||||
// remove first target param for next recursive call
|
||||
let currentTarget = target.shift();
|
||||
|
||||
deepDelete(target, obj[currentTarget], callback);
|
||||
|
||||
// delete "parent" key when current key became empty
|
||||
if( !Object.keys( obj[currentTarget] ).length ){
|
||||
delete obj[currentTarget];
|
||||
}
|
||||
}else{
|
||||
// check for callback function
|
||||
if( typeof callback === 'function' ){
|
||||
callback(obj[target]);
|
||||
}
|
||||
|
||||
delete obj[target];
|
||||
}
|
||||
};
|
||||
|
||||
deepDelete(args, dataTableInstances, deleteCallback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* collect all data of all editable fields in a signature table
|
||||
* @param tableApi
|
||||
* @returns {Array}
|
||||
*/
|
||||
let getSignatureTableData = function(){
|
||||
let signatureTableApi = signatureTable.api();
|
||||
let getTableData = function(tableApi){
|
||||
let tableData = [];
|
||||
|
||||
signatureTableApi.rows().eq(0).each(function(idx){
|
||||
let row = signatureTableApi.row(idx);
|
||||
tableApi.rows().eq(0).each(function(idx){
|
||||
let row = tableApi.row(idx);
|
||||
// default row data
|
||||
let defaultRowData = row.data();
|
||||
let rowElement = row.nodes().to$();
|
||||
@@ -151,16 +252,14 @@ define([
|
||||
|
||||
/**
|
||||
* updates a single cell with new data (e.g. "updated" cell)
|
||||
* @param tableApi
|
||||
* @param rowElement
|
||||
* @param cellIndex
|
||||
* @param data
|
||||
*/
|
||||
let updateSignatureCell = function(rowElement, cellIndex, data){
|
||||
|
||||
let signatureTableApi = signatureTable.api();
|
||||
let rowIndex = signatureTableApi.row( rowElement ).index();
|
||||
|
||||
let updateCell = signatureTableApi.cell( rowIndex, cellIndex );
|
||||
let updateSignatureCell = function(tableApi, rowElement, cellIndex, data){
|
||||
let rowIndex = tableApi.row( rowElement ).index();
|
||||
let updateCell = tableApi.cell( rowIndex, cellIndex );
|
||||
let updateCellElement = updateCell.nodes().to$();
|
||||
|
||||
if(cellIndex === 7){
|
||||
@@ -184,7 +283,6 @@ define([
|
||||
* @param deleteOutdatedSignatures -> set to "true" if signatures should be deleted that are not included in "signatureData"
|
||||
*/
|
||||
$.fn.updateSignatureTable = function(signatureDataOrig, deleteOutdatedSignatures){
|
||||
|
||||
// check if table update is allowed
|
||||
if(disableTableUpdate === true){
|
||||
return;
|
||||
@@ -199,13 +297,12 @@ define([
|
||||
let moduleElement = $(this);
|
||||
|
||||
// get signature table API
|
||||
let signatureTableApi = signatureTable.api();
|
||||
let signatureTableApi = getDataTableInstanceByModuleElement(moduleElement, 'primary');
|
||||
|
||||
// get current system data
|
||||
let currentSystemData = Util.getCurrentSystemData();
|
||||
|
||||
|
||||
let tableData = getSignatureTableData();
|
||||
let tableData = getTableData(signatureTableApi);
|
||||
|
||||
let notificationCounter = {
|
||||
added: 0,
|
||||
@@ -229,7 +326,7 @@ define([
|
||||
signatureTableApi.row(currentRowElement).remove().draw();
|
||||
|
||||
// and add "new" row
|
||||
let changedRowElement = addSignatureRow(currentSystemData.systemData, signatureData[i], false);
|
||||
let changedRowElement = addSignatureRow(signatureTableApi, currentSystemData.systemData, signatureData[i], false);
|
||||
|
||||
// highlight
|
||||
changedRowElement.pulseTableRow('changed');
|
||||
@@ -272,7 +369,7 @@ define([
|
||||
// add new signatures -----------------------------------------------------------------------------------------
|
||||
for(let k = 0; k < signatureData.length; k++){
|
||||
// and add "new" row
|
||||
let newRowElement = addSignatureRow(currentSystemData.systemData, signatureData[k], false);
|
||||
let newRowElement = addSignatureRow(signatureTableApi, currentSystemData.systemData, signatureData[k], false);
|
||||
|
||||
// highlight
|
||||
newRowElement.pulseTableRow('added');
|
||||
@@ -333,15 +430,15 @@ define([
|
||||
* @param options
|
||||
*/
|
||||
$.fn.updateScannedSignaturesBar = function(options){
|
||||
|
||||
let moduleElement = $(this);
|
||||
let signatureTableApi = getDataTableInstanceByModuleElement(moduleElement, 'primary');
|
||||
|
||||
// get progress bar
|
||||
let progressBarWrapper = moduleElement.find('.' + config.signatureScannedProgressBarClass);
|
||||
let progressBar = $(progressBarWrapper).find('.progress-bar');
|
||||
let progressBarLabel = $(progressBarWrapper).find('.progress-label-right');
|
||||
|
||||
let tableData = getSignatureTableData();
|
||||
let tableData = getTableData(signatureTableApi);
|
||||
|
||||
let sigCount = 0;
|
||||
let percent = 0;
|
||||
@@ -392,7 +489,6 @@ define([
|
||||
}
|
||||
|
||||
}, 100);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -478,12 +574,15 @@ define([
|
||||
type: 'POST',
|
||||
url: Init.path.saveSignatureData,
|
||||
data: requestData,
|
||||
dataType: 'json'
|
||||
dataType: 'json',
|
||||
context: {
|
||||
moduleElement: moduleElement
|
||||
}
|
||||
}).done(function(responseData){
|
||||
unlockSignatureTable(true);
|
||||
|
||||
// updates table with new/updated signature information
|
||||
moduleElement.updateSignatureTable(responseData.signatures, false);
|
||||
this.moduleElement.updateSignatureTable(responseData.signatures, false);
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
let reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': Update signatures', text: reason, type: 'warning'});
|
||||
@@ -816,47 +915,45 @@ define([
|
||||
|
||||
/**
|
||||
* get all rows of a table
|
||||
* @param table
|
||||
* @param tableApi
|
||||
* @returns {*}
|
||||
*/
|
||||
let getRows = function(table){
|
||||
let tableApi = table.api();
|
||||
let getRows = function(tableApi){
|
||||
let rows = tableApi.rows();
|
||||
|
||||
return rows;
|
||||
};
|
||||
|
||||
/**
|
||||
* get all selected rows of a table
|
||||
* @param table
|
||||
* @param tableApi
|
||||
* @returns {*}
|
||||
*/
|
||||
let getSelectedRows = function(table){
|
||||
let tableApi = table.api();
|
||||
|
||||
let getSelectedRows = function(tableApi){
|
||||
let selectedRows = tableApi.rows('.selected');
|
||||
|
||||
return selectedRows;
|
||||
};
|
||||
|
||||
/**
|
||||
* check the "delete signature" button. show/hide the button if a signature is selected
|
||||
* @param moduleElement
|
||||
*/
|
||||
let checkDeleteSignaturesButton = function(){
|
||||
let checkDeleteSignaturesButton = function(moduleElement){
|
||||
moduleElement = $(moduleElement);
|
||||
let signatureTableApi = getDataTableInstanceByModuleElement(moduleElement, 'primary');
|
||||
|
||||
let selectedRows = getSelectedRows(signatureTable);
|
||||
let selectedRows = getSelectedRows(signatureTableApi);
|
||||
let selectedRowCount = selectedRows.data().length;
|
||||
let clearButton = $('.' + config.sigTableClearButtonClass);
|
||||
let clearButton = moduleElement.find('.' + config.sigTableClearButtonClass);
|
||||
|
||||
if(selectedRowCount > 0){
|
||||
let allRows = getRows(signatureTable);
|
||||
let allRows = getRows(signatureTableApi);
|
||||
let rowCount = allRows.data().length;
|
||||
|
||||
let badgetText = selectedRowCount;
|
||||
let badgeText = selectedRowCount;
|
||||
if(selectedRowCount >= rowCount){
|
||||
badgetText = 'all';
|
||||
badgeText = 'all';
|
||||
}
|
||||
clearButton.find('.badge').text( badgetText );
|
||||
clearButton.find('.badge').text( badgeText );
|
||||
|
||||
// update clear signatures button text
|
||||
clearButton.velocity('stop');
|
||||
@@ -882,10 +979,10 @@ define([
|
||||
|
||||
/**
|
||||
* draw signature table toolbar (add signature button, scan progress bar
|
||||
* @param mapId
|
||||
* @param systemData
|
||||
*/
|
||||
$.fn.drawSignatureTableToolbar = function(systemData){
|
||||
|
||||
$.fn.drawSignatureTableToolbar = function(mapId, systemData){
|
||||
let moduleElement = $(this);
|
||||
|
||||
// add toolbar buttons for table ------------------------------------------------------------------------------
|
||||
@@ -930,8 +1027,10 @@ define([
|
||||
label: 'select all',
|
||||
icon: 'fa-check-square',
|
||||
onClick: function(){
|
||||
let allRows = getRows(signatureTable);
|
||||
let selectedRows = getSelectedRows(signatureTable);
|
||||
let signatureTableApi = getDataTableInstanceByModuleElement(moduleElement, 'primary');
|
||||
|
||||
let allRows = getRows(signatureTableApi);
|
||||
let selectedRows = getSelectedRows(signatureTableApi);
|
||||
let allRowElements = allRows.nodes().to$();
|
||||
|
||||
if(allRows.data().length === selectedRows.data().length){
|
||||
@@ -941,7 +1040,7 @@ define([
|
||||
}
|
||||
|
||||
// check delete button
|
||||
checkDeleteSignaturesButton();
|
||||
checkDeleteSignaturesButton(moduleElement);
|
||||
}
|
||||
})
|
||||
).append(
|
||||
@@ -955,12 +1054,12 @@ define([
|
||||
},
|
||||
onClick: function(){
|
||||
// delete all rows
|
||||
|
||||
let selectedRows = getSelectedRows(signatureTable);
|
||||
let signatureTableApi = getDataTableInstanceByModuleElement(moduleElement, 'primary');
|
||||
let selectedRows = getSelectedRows(signatureTableApi);
|
||||
|
||||
bootbox.confirm('Delete ' + selectedRows.data().length + ' signature?', function(result) {
|
||||
if(result){
|
||||
deleteSignatures(selectedRows);
|
||||
deleteSignatures(signatureTableApi, selectedRows);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -984,15 +1083,18 @@ define([
|
||||
tableToolbar.after(tableToolbarAction);
|
||||
|
||||
let signatureData = formatSignatureData(systemData, [emptySignatureData], emptySignatureOptions);
|
||||
table.dataTable( {
|
||||
let signatureTable = table.dataTable( {
|
||||
data: signatureData,
|
||||
paging: false,
|
||||
ordering: false,
|
||||
info: false,
|
||||
searching: false
|
||||
} );
|
||||
let signatureTableApi = signatureTable.api();
|
||||
|
||||
table.makeEditable(systemData);
|
||||
setDataTableInstance(mapId, systemData.id, 'secondary', signatureTableApi);
|
||||
|
||||
table.makeEditable(signatureTableApi, systemData);
|
||||
|
||||
// scanned signatures progress bar ----------------------------------------------------------------------------
|
||||
let moduleConfig = {
|
||||
@@ -1019,18 +1121,16 @@ define([
|
||||
* @param title
|
||||
*/
|
||||
let updateTooltip = function(element, title){
|
||||
element = $(element);
|
||||
|
||||
element.attr('data-container', 'body').attr('title', title.toUpperCase()).tooltip('fixTitle')
|
||||
$(element).attr('data-container', 'body').attr('title', title.toUpperCase()).tooltip('fixTitle')
|
||||
.tooltip('setContent');
|
||||
};
|
||||
|
||||
/**
|
||||
* make a table or row editable
|
||||
* @param tableApi
|
||||
* @param systemData
|
||||
*/
|
||||
$.fn.makeEditable = function(systemData){
|
||||
|
||||
$.fn.makeEditable = function(tableApi, systemData){
|
||||
// table element OR row element
|
||||
let tableElement = $(this);
|
||||
|
||||
@@ -1055,7 +1155,7 @@ define([
|
||||
// the current field is in the "primary" table (not the "add" new sig row)
|
||||
if(
|
||||
$(e.target).hasClass(config.sigTableEditSigGroupSelect) &&
|
||||
tableElement.hasClass(config.sigTablePrimaryClass)
|
||||
$(e.target).parents('.' + config.sigTableClass).hasClass(config.sigTablePrimaryClass)
|
||||
){
|
||||
currentField.parents('.' + config.moduleClass).updateScannedSignaturesBar({showNotice: true});
|
||||
}
|
||||
@@ -1142,7 +1242,7 @@ define([
|
||||
updateTooltip(columnElement, newValue);
|
||||
|
||||
// update "updated" cell
|
||||
updateSignatureCell(rowElement, 7, newRowData.updated);
|
||||
updateSignatureCell(tableApi, rowElement, 7, newRowData.updated);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1179,7 +1279,7 @@ define([
|
||||
let newRowData = response.signatures[0];
|
||||
|
||||
// update "updated" cell
|
||||
updateSignatureCell(rowElement, 7, newRowData.updated);
|
||||
updateSignatureCell(tableApi, rowElement, 7, newRowData.updated);
|
||||
}
|
||||
|
||||
// find related "type" select (same row) and change options
|
||||
@@ -1250,7 +1350,7 @@ define([
|
||||
let newRowData = response.signatures[0];
|
||||
|
||||
// update "updated" cell
|
||||
updateSignatureCell(rowElement, 7, newRowData.updated);
|
||||
updateSignatureCell(tableApi, rowElement, 7, newRowData.updated);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1273,7 +1373,7 @@ define([
|
||||
let newRowData = response.signatures[0];
|
||||
|
||||
// update "updated" cell
|
||||
updateSignatureCell(rowElement, 7, newRowData.updated);
|
||||
updateSignatureCell(tableApi, rowElement, 7, newRowData.updated);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1328,7 +1428,7 @@ define([
|
||||
let newRowData = response.signatures[0];
|
||||
|
||||
// update "updated" cell
|
||||
updateSignatureCell(rowElement, 7, newRowData.updated);
|
||||
updateSignatureCell(tableApi, rowElement, 7, newRowData.updated);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1378,13 +1478,13 @@ define([
|
||||
// take target...
|
||||
connectionOptions.push({
|
||||
value: connectionData.id,
|
||||
text: connectionData.targetName
|
||||
text: connectionData.targetAlias
|
||||
});
|
||||
}else if(systemData.id !== connectionData.source){
|
||||
// take source...
|
||||
connectionOptions.push({
|
||||
value: connectionData.id,
|
||||
text: connectionData.sourceName
|
||||
text: connectionData.sourceAlias
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1628,15 +1728,14 @@ define([
|
||||
|
||||
/**
|
||||
* deletes signature rows from signature table
|
||||
* @param tableApi
|
||||
* @param rows
|
||||
*/
|
||||
let deleteSignatures = function(rows){
|
||||
|
||||
let deleteSignatures = function(tableApi, rows){
|
||||
let deletedSignatures = 0;
|
||||
|
||||
let moduleElement = $('.' + config.systemSigModuleClass);
|
||||
let data = rows.data();
|
||||
let signatureTableApi = signatureTable.api();
|
||||
let rowElements = rows.nodes().to$();
|
||||
let signatureCount = data.length;
|
||||
|
||||
@@ -1652,7 +1751,7 @@ define([
|
||||
// animation callback function
|
||||
let removeCallback = function(rowElement){
|
||||
// delete signature row
|
||||
signatureTableApi.row(rowElement).remove().draw();
|
||||
tableApi.row(rowElement).remove().draw();
|
||||
|
||||
deletedSignatures++;
|
||||
|
||||
@@ -1686,25 +1785,20 @@ define([
|
||||
Util.showNotify({title: jqXHR.status + ': Delete signature', text: reason, type: 'warning'});
|
||||
$(document).setProgramStatus('problem');
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* adds a new row to signature Table
|
||||
* @param signatureTableApi
|
||||
* @param systemData
|
||||
* @param signatureData
|
||||
* @param animate
|
||||
* @returns {*}
|
||||
*/
|
||||
let addSignatureRow = function(systemData, signatureData, animate){
|
||||
|
||||
let addSignatureRow = function(signatureTableApi, systemData, signatureData, animate){
|
||||
let newSignatureData = formatSignatureData(systemData, [signatureData], fullSignatureOptions);
|
||||
|
||||
// insert new row in main signature table
|
||||
let tablePrimaryElement = $('.' + config.sigTablePrimaryClass);
|
||||
let dataTablePrimary = tablePrimaryElement.DataTable();
|
||||
let newRowNode = dataTablePrimary.row.add(newSignatureData.shift()).draw().nodes();
|
||||
let newRowNode = signatureTableApi.row.add(newSignatureData.shift()).draw().nodes();
|
||||
let newRowElement = newRowNode.to$();
|
||||
|
||||
if(animate === true){
|
||||
@@ -1713,13 +1807,13 @@ define([
|
||||
newRowElement.toggleTableRow(function(newRowElement){
|
||||
// make new row editable
|
||||
|
||||
newRowElement.makeEditable(systemData);
|
||||
newRowElement.makeEditable(signatureTableApi, systemData);
|
||||
|
||||
// update scan progress bar
|
||||
newRowElement.parents('.' + config.moduleClass).updateScannedSignaturesBar({showNotice: true});
|
||||
});
|
||||
}else{
|
||||
newRowElement.makeEditable(systemData);
|
||||
newRowElement.makeEditable(signatureTableApi, systemData);
|
||||
}
|
||||
|
||||
return newRowElement;
|
||||
@@ -1732,10 +1826,8 @@ define([
|
||||
$.fn.toggleTableRow = function(callback){
|
||||
let rowElement = $(this);
|
||||
let cellElements = rowElement.children('td');
|
||||
|
||||
let duration = 100;
|
||||
|
||||
|
||||
// wrap each <td> into a container (for better animation performance)
|
||||
// slideUp new wrapper divs
|
||||
if(rowElement.is(':visible')){
|
||||
@@ -1815,11 +1907,11 @@ define([
|
||||
|
||||
/**
|
||||
* draw a signature table with data
|
||||
* @param mapId
|
||||
* @param signatureData
|
||||
* @param systemData
|
||||
* @returns {*}
|
||||
*/
|
||||
$.fn.drawSignatureTable = function(signatureData, systemData){
|
||||
$.fn.drawSignatureTable = function(mapId, signatureData, systemData){
|
||||
let moduleElement = $(this);
|
||||
|
||||
// setup filter select in footer
|
||||
@@ -1886,14 +1978,14 @@ define([
|
||||
};
|
||||
|
||||
// create signature table and store the jquery object global for this module
|
||||
signatureTable = table.dataTable(dataTableOptions);
|
||||
let signatureTable = table.dataTable(dataTableOptions);
|
||||
let signatureTableApi = signatureTable.api();
|
||||
setDataTableInstance(mapId, systemData.id, 'primary', signatureTableApi);
|
||||
|
||||
// make Table editable
|
||||
signatureTable.makeEditable(systemData);
|
||||
signatureTable.makeEditable(signatureTableApi, systemData);
|
||||
|
||||
moduleElement.updateScannedSignaturesBar({showNotice: true});
|
||||
|
||||
return signatureTable;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -2093,6 +2185,12 @@ define([
|
||||
// submit all fields within a table row
|
||||
let formFields = rowElement.find('.editable');
|
||||
|
||||
// get the current "primary table" for insert row on ajax callback
|
||||
// -> important: in case of long response, target table might have changed...
|
||||
let moduleElement = $(e.target).parents('.' + config.moduleClass);
|
||||
let primaryTable = moduleElement.find('.' + config.sigTablePrimaryClass);
|
||||
let secondaryTable = moduleElement.find('.' + config.sigTableSecondaryClass);
|
||||
|
||||
// the "hide" makes sure to take care about open editable fields (e.g. description)
|
||||
// otherwise, changes would not be submitted in this field (not necessary)
|
||||
formFields.editable('hide');
|
||||
@@ -2104,6 +2202,10 @@ define([
|
||||
dataType: 'json', //assuming json response
|
||||
beforeSend: function( xhr, settings ){
|
||||
lockSignatureTable();
|
||||
},
|
||||
context: {
|
||||
primaryTable: primaryTable,
|
||||
secondaryTable: secondaryTable
|
||||
}
|
||||
},
|
||||
data: {
|
||||
@@ -2112,21 +2214,22 @@ define([
|
||||
},
|
||||
error: $.fn.editable.defaults.error, // user default xEditable error function
|
||||
success: function (data, editableConfig) {
|
||||
let context = editableConfig.ajaxOptions.context;
|
||||
let primaryTableApi = context.primaryTable.DataTable();
|
||||
let secondaryTableApi = context.secondaryTable.DataTable();
|
||||
|
||||
unlockSignatureTable(false);
|
||||
|
||||
let newRowElement = addSignatureRow(systemData, data.signatures[0], true);
|
||||
let newRowElement = addSignatureRow(primaryTableApi, systemData, data.signatures[0], true);
|
||||
|
||||
// highlight
|
||||
newRowElement.pulseTableRow('added');
|
||||
|
||||
// prepare "add signature" table for new entry -> reset -------------------
|
||||
let signatureData = formatSignatureData(systemData, [emptySignatureData], emptySignatureOptions);
|
||||
let newAddRowElement = secondaryTableApi.clear().row.add(signatureData.shift()).draw().nodes();
|
||||
|
||||
let dataSecondaryElement = $('.' + config.sigTableSecondaryClass);
|
||||
let dataTableSecondary = dataSecondaryElement.DataTable();
|
||||
let newAddRowElement = dataTableSecondary.clear().row.add(signatureData.shift()).draw().nodes();
|
||||
|
||||
newAddRowElement.to$().makeEditable(systemData);
|
||||
newAddRowElement.to$().makeEditable(secondaryTableApi, systemData);
|
||||
|
||||
Util.showNotify({
|
||||
title: 'Signature added',
|
||||
@@ -2149,20 +2252,21 @@ define([
|
||||
btnOkClass: 'btn btn-sm btn-danger',
|
||||
btnOkLabel: 'delete',
|
||||
btnOkIcon: 'fa fa-fw fa-close',
|
||||
onConfirm : function(e, target){
|
||||
onConfirm: function(e, target){
|
||||
// top scroll to top
|
||||
e.preventDefault();
|
||||
|
||||
let tableApi = tempTableElement.DataTable();
|
||||
|
||||
let deleteRowElement = $(target).parents('tr');
|
||||
let row = tempTableElement.DataTable().rows(deleteRowElement);
|
||||
deleteSignatures(row);
|
||||
let row = tableApi.rows(deleteRowElement);
|
||||
deleteSignatures(tableApi, row);
|
||||
}
|
||||
};
|
||||
|
||||
// init confirmation dialog
|
||||
$(cell).confirmation(confirmationSettings);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2178,31 +2282,29 @@ define([
|
||||
* @param systemData
|
||||
*/
|
||||
let setModuleObserver = function(moduleElement, systemData){
|
||||
let tablePrimaryElement = $('.' + config.sigTablePrimaryClass);
|
||||
let dataTablePrimary = signatureTable.DataTable();
|
||||
let signatureTableApi = signatureTable.api();
|
||||
let tablePrimaryElement = moduleElement.find('.' + config.sigTablePrimaryClass);
|
||||
let signatureTableApi = getDataTableInstanceByModuleElement(moduleElement, 'primary');
|
||||
|
||||
$(document).off('pf:updateSystemSignatureModule').on('pf:updateSystemSignatureModule', function(e, data){
|
||||
if(data.signatures){
|
||||
moduleElement.updateSignatureTable(data.signatures, true);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// set multi row select ---------------------------------------------------------------------------------------
|
||||
tablePrimaryElement.on('click', 'tr', function(e){
|
||||
tablePrimaryElement.on('click', 'tr', {moduleElement: moduleElement}, function(e){
|
||||
if(e.ctrlKey) {
|
||||
$(this).toggleClass('selected');
|
||||
|
||||
// check delete button
|
||||
checkDeleteSignaturesButton();
|
||||
checkDeleteSignaturesButton(e.data.moduleElement);
|
||||
}
|
||||
});
|
||||
|
||||
// draw event for signature table -----------------------------------------------------------------------------
|
||||
signatureTableApi.on('draw.dt', function(){
|
||||
signatureTableApi.on('draw.dt', {moduleElement: moduleElement}, function(e, settings){
|
||||
// check delete button
|
||||
checkDeleteSignaturesButton();
|
||||
checkDeleteSignaturesButton(e.data.moduleElement);
|
||||
});
|
||||
|
||||
// event listener for global "paste" signatures into the page -------------------------------------------------
|
||||
@@ -2214,10 +2316,11 @@ define([
|
||||
/**
|
||||
* get module element
|
||||
* @param parentElement
|
||||
* @param mapId
|
||||
* @param systemData
|
||||
* @returns {*|HTMLElement}
|
||||
* @returns {*|jQuery|HTMLElement}
|
||||
*/
|
||||
let getModule = function(parentElement, systemData){
|
||||
let getModule = function(parentElement, mapId, systemData){
|
||||
|
||||
// create new module container
|
||||
let moduleElement = $('<div>', {
|
||||
@@ -2225,6 +2328,9 @@ define([
|
||||
css: {opacity: 0}
|
||||
});
|
||||
|
||||
moduleElement.data('mapId', mapId);
|
||||
moduleElement.data('systemId', systemData.id);
|
||||
|
||||
// headline
|
||||
let headline = $('<h5>', {
|
||||
text: 'Signatures'
|
||||
@@ -2239,7 +2345,7 @@ define([
|
||||
|
||||
// draw "new signature" add table -----------------------------------------------------------------------------
|
||||
|
||||
moduleElement.drawSignatureTableToolbar(systemData);
|
||||
moduleElement.drawSignatureTableToolbar(mapId, systemData);
|
||||
|
||||
// request signature data for system --------------------------------------------------------------------------
|
||||
|
||||
@@ -2253,14 +2359,14 @@ define([
|
||||
data: requestData,
|
||||
dataType: 'json',
|
||||
context: {
|
||||
mapId: mapId,
|
||||
systemData: systemData
|
||||
}
|
||||
}).done(function(signatureData){
|
||||
|
||||
let signatureTableData = formatSignatureData(this.systemData, signatureData, fullSignatureOptions);
|
||||
|
||||
// draw signature table
|
||||
moduleElement.drawSignatureTable(signatureTableData, this.systemData);
|
||||
moduleElement.drawSignatureTable(this.mapId, signatureTableData, this.systemData);
|
||||
|
||||
// set module observer
|
||||
setModuleObserver(moduleElement, this.systemData);
|
||||
@@ -2275,9 +2381,10 @@ define([
|
||||
|
||||
/**
|
||||
* main module load function
|
||||
* @param mapId
|
||||
* @param systemData
|
||||
*/
|
||||
$.fn.drawSignatureTableModule = function(systemData){
|
||||
$.fn.drawSignatureTableModule = function(mapId, systemData){
|
||||
let parentElement = $(this);
|
||||
|
||||
// show module
|
||||
@@ -2317,13 +2424,17 @@ define([
|
||||
moduleElement.velocity('transition.slideDownOut', {
|
||||
duration: Init.animationSpeed.mapModule,
|
||||
complete: function(tempElement){
|
||||
tempElement = $(tempElement);
|
||||
// Destroying the data tables throws
|
||||
// save remove of all dataTables
|
||||
signatureTable.api().destroy();
|
||||
let mapId = tempElement.data('mapId');
|
||||
let systemId = tempElement.data('systemId');
|
||||
deleteDataTableInstance(mapId, systemId, 'primary');
|
||||
deleteDataTableInstance(mapId, systemId, 'secondary');
|
||||
|
||||
$(tempElement).remove();
|
||||
tempElement.remove();
|
||||
|
||||
moduleElement = getModule(parentElement, systemData);
|
||||
moduleElement = getModule(parentElement, mapId, systemData);
|
||||
// make modules appear "nice"
|
||||
moduleElement.delay(150);
|
||||
showModule(moduleElement);
|
||||
@@ -2333,7 +2444,7 @@ define([
|
||||
// init array prototype functions
|
||||
initArrayFunctions();
|
||||
|
||||
moduleElement = getModule(parentElement, systemData);
|
||||
moduleElement = getModule(parentElement, mapId, systemData);
|
||||
showModule(moduleElement);
|
||||
}
|
||||
};
|
||||
|
||||
245
js/app/util.js
245
js/app/util.js
@@ -53,6 +53,9 @@ define([
|
||||
// map module
|
||||
mapModuleId: 'pf-map-module', // id for main map module
|
||||
mapTabBarId: 'pf-map-tabs', // id for map tab bar
|
||||
mapWrapperClass: 'pf-map-wrapper', // wrapper div (scrollable)
|
||||
mapClass: 'pf-map' , // class for all maps
|
||||
|
||||
|
||||
// animation
|
||||
animationPulseSuccessClass: 'pf-animation-pulse-success', // animation class
|
||||
@@ -79,40 +82,41 @@ define([
|
||||
* displays a loading indicator on an element
|
||||
*/
|
||||
$.fn.showLoadingAnimation = function(options){
|
||||
let loadingElement = $(this);
|
||||
return this.each(function(){
|
||||
let loadingElement = $(this);
|
||||
let iconSize = 'fa-lg';
|
||||
|
||||
let iconSize = 'fa-lg';
|
||||
// disable all events
|
||||
loadingElement.css('pointer-events', 'none');
|
||||
|
||||
// disable all events
|
||||
loadingElement.css('pointer-events', 'none');
|
||||
|
||||
if(options){
|
||||
if(options.icon){
|
||||
if(options.icon.size){
|
||||
iconSize = options.icon.size;
|
||||
if(options){
|
||||
if(options.icon){
|
||||
if(options.icon.size){
|
||||
iconSize = options.icon.size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let overlay = $('<div>', {
|
||||
class: config.ajaxOverlayClass
|
||||
}).append(
|
||||
$('<div>', {
|
||||
class: [config.ajaxOverlayWrapperClass].join(' ')
|
||||
let overlay = $('<div>', {
|
||||
class: config.ajaxOverlayClass
|
||||
}).append(
|
||||
$('<i>', {
|
||||
class: ['fa', 'fa-fw', iconSize, 'fa-refresh', 'fa-spin'].join(' ')
|
||||
})
|
||||
)
|
||||
);
|
||||
$('<div>', {
|
||||
class: [config.ajaxOverlayWrapperClass].join(' ')
|
||||
}).append(
|
||||
$('<i>', {
|
||||
class: ['fa', 'fa-fw', iconSize, 'fa-refresh', 'fa-spin'].join(' ')
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
loadingElement.append(overlay);
|
||||
loadingElement.append(overlay);
|
||||
|
||||
// fade in
|
||||
$(overlay).velocity({
|
||||
opacity: 0.6
|
||||
},{
|
||||
duration: 120
|
||||
// fade in
|
||||
$(overlay).velocity({
|
||||
opacity: 0.6
|
||||
},{
|
||||
duration: 120
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -120,16 +124,20 @@ define([
|
||||
* removes a loading indicator
|
||||
*/
|
||||
$.fn.hideLoadingAnimation = function(){
|
||||
let loadingElement = $(this);
|
||||
let overlay = loadingElement.find('.' + config.ajaxOverlayClass );
|
||||
return this.each(function(){
|
||||
let loadingElement = $(this);
|
||||
let overlay = loadingElement.find('.' + config.ajaxOverlayClass );
|
||||
|
||||
// important: "stop" is required to stop "show" animation
|
||||
// -> otherwise "complete" callback is not fired!
|
||||
$(overlay).velocity('stop').velocity('reverse', {
|
||||
complete: function(){
|
||||
$(this).remove();
|
||||
// enable all events
|
||||
loadingElement.css('pointer-events', 'auto');
|
||||
if(overlay.length){
|
||||
// important: "stop" is required to stop "show" animation
|
||||
// -> otherwise "complete" callback is not fired!
|
||||
overlay.velocity('stop').velocity('reverse', {
|
||||
complete: function(){
|
||||
$(this).remove();
|
||||
// enable all events
|
||||
loadingElement.css('pointer-events', 'auto');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1265,6 +1273,15 @@ define([
|
||||
return mapTabElements;
|
||||
};
|
||||
|
||||
/**
|
||||
* get mapElement from overlay or any child of that
|
||||
* @param mapOverlay
|
||||
* @returns {jQuery}
|
||||
*/
|
||||
let getMapElementFromOverlay = (mapOverlay) => {
|
||||
return $(mapOverlay).parents('.' + config.mapWrapperClass).find('.' + config.mapClass);
|
||||
};
|
||||
|
||||
/**
|
||||
* get the map module object or create a new module
|
||||
* @returns {*|HTMLElement}
|
||||
@@ -1797,6 +1814,132 @@ define([
|
||||
return userInfo;
|
||||
};
|
||||
|
||||
/**
|
||||
* get "nearBy" systemData based on a jump radius around a currentSystem
|
||||
* @param currentSystemData
|
||||
* @param currentMapData
|
||||
* @param jumps
|
||||
* @param foundSystemIds
|
||||
* @returns {{systemData: *, tree: {}}}
|
||||
*/
|
||||
let getNearBySystemData = (currentSystemData, currentMapData, jumps, foundSystemIds = {}) => {
|
||||
|
||||
// look for systemData by ID
|
||||
let getSystemData = (systemId) => {
|
||||
for(let j = 0; j < currentMapData.data.systems.length; j++){
|
||||
let systemData = currentMapData.data.systems[j];
|
||||
if(systemData.id === systemId){
|
||||
return systemData;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// skip systems that are already found in recursive calls
|
||||
foundSystemIds[currentSystemData.id] = {distance: jumps};
|
||||
|
||||
let nearBySystems = {
|
||||
systemData: currentSystemData,
|
||||
tree: {}
|
||||
};
|
||||
|
||||
jumps--;
|
||||
if(jumps >= 0){
|
||||
for(let i = 0; i < currentMapData.data.connections.length; i++){
|
||||
let connectionData = currentMapData.data.connections[i];
|
||||
let type = ''; // "source" OR "target"
|
||||
if(connectionData.source === currentSystemData.id){
|
||||
type = 'target';
|
||||
}else if(connectionData.target === currentSystemData.id){
|
||||
type = 'source';
|
||||
}
|
||||
|
||||
if(
|
||||
type &&
|
||||
(
|
||||
foundSystemIds[connectionData[type]] === undefined ||
|
||||
foundSystemIds[connectionData[type]].distance < jumps
|
||||
)
|
||||
){
|
||||
let newSystemData = getSystemData(connectionData[type]);
|
||||
if(newSystemData){
|
||||
nearBySystems.tree[connectionData[type]] = getNearBySystemData(newSystemData, currentMapData, jumps, foundSystemIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nearBySystems;
|
||||
};
|
||||
|
||||
/**
|
||||
* get current character data from all characters who are "nearby" the current user
|
||||
* -> see getNearBySystemData()
|
||||
* @param nearBySystems
|
||||
* @param userData
|
||||
* @param jumps
|
||||
* @param data
|
||||
* @returns {{}}
|
||||
*/
|
||||
let getNearByCharacterData = (nearBySystems, userData, jumps = 0, data = {}) => {
|
||||
|
||||
let getCharacterDataBySystemId = (systemId) => {
|
||||
for(let i = 0; i < userData.length; i++){
|
||||
if(userData[i].id === systemId){
|
||||
return userData[i].user;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
let filterFinalCharData = function(tmpFinalCharData){
|
||||
return this.id !== tmpFinalCharData.id;
|
||||
};
|
||||
|
||||
let characterData = getCharacterDataBySystemId(nearBySystems.systemData.systemId);
|
||||
|
||||
if(characterData.length){
|
||||
// filter (remove) characterData for "already" added chars
|
||||
characterData = characterData.filter(function(tmpCharacterData, index, allData){
|
||||
let keepData = true;
|
||||
|
||||
for(let tmpJump in data) {
|
||||
// just scan systems with > jumps than current system
|
||||
if(tmpJump > jumps){
|
||||
let filteredFinalData = data[tmpJump].filter(filterFinalCharData, tmpCharacterData);
|
||||
|
||||
if(filteredFinalData.length > 0){
|
||||
data[tmpJump] = filteredFinalData;
|
||||
}else{
|
||||
delete data[tmpJump];
|
||||
}
|
||||
}else{
|
||||
for(let k = 0; k < data[tmpJump].length; k++){
|
||||
if(data[tmpJump][k].id === tmpCharacterData.id){
|
||||
keepData = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return keepData;
|
||||
});
|
||||
|
||||
data[jumps] = data[jumps] ? data[jumps] : [];
|
||||
data[jumps] = [...data[jumps], ...characterData];
|
||||
}
|
||||
|
||||
jumps++;
|
||||
for(let prop in nearBySystems.tree) {
|
||||
if( nearBySystems.tree.hasOwnProperty(prop) ){
|
||||
let tmpSystemData = nearBySystems.tree[prop];
|
||||
data = getNearByCharacterData(tmpSystemData, userData, jumps, data);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* set new destination for a system
|
||||
* -> CREST request
|
||||
@@ -1894,6 +2037,34 @@ define([
|
||||
return $('.' + config.dialogClass).filter(':visible');
|
||||
};
|
||||
|
||||
/**
|
||||
* send Ajax request that remote opens an ingame Window
|
||||
* @param targetId
|
||||
*/
|
||||
let openIngameWindow = (targetId) => {
|
||||
targetId = parseInt(targetId);
|
||||
|
||||
if(targetId > 0){
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.openIngameWindow,
|
||||
data: {
|
||||
targetId: targetId
|
||||
},
|
||||
dataType: 'json'
|
||||
}).done(function(data){
|
||||
if(data.error.length > 0){
|
||||
showNotify({title: 'Open window in client', text: 'Remote window open failed', type: 'error'});
|
||||
}else{
|
||||
showNotify({title: 'Open window in client', text: 'Check your EVE client', type: 'success'});
|
||||
}
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
let reason = status + ' ' + error;
|
||||
showNotify({title: jqXHR.status + ': openWindow', text: reason, type: 'error'});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* formats a price string into an ISK Price
|
||||
* @param price
|
||||
@@ -2031,6 +2202,7 @@ define([
|
||||
setSyncStatus: setSyncStatus,
|
||||
getSyncType: getSyncType,
|
||||
isXHRAborted: isXHRAborted,
|
||||
getMapElementFromOverlay: getMapElementFromOverlay,
|
||||
getMapModule: getMapModule,
|
||||
getSystemEffectData: getSystemEffectData,
|
||||
getSystemEffectTable: getSystemEffectTable,
|
||||
@@ -2058,9 +2230,12 @@ define([
|
||||
getCurrentUserInfo: getCurrentUserInfo,
|
||||
getCurrentCharacterLog: getCurrentCharacterLog,
|
||||
flattenXEditableSelectArray: flattenXEditableSelectArray,
|
||||
getNearBySystemData: getNearBySystemData,
|
||||
getNearByCharacterData: getNearByCharacterData,
|
||||
setDestination: setDestination,
|
||||
convertDateToString: convertDateToString,
|
||||
getOpenDialogs: getOpenDialogs,
|
||||
openIngameWindow: openIngameWindow,
|
||||
formatPrice: formatPrice,
|
||||
getLocalStorage: getLocalStorage,
|
||||
getDocumentPath: getDocumentPath,
|
||||
|
||||
450
js/lib/bootstrap-confirmation.js
vendored
450
js/lib/bootstrap-confirmation.js
vendored
@@ -1,249 +1,263 @@
|
||||
/*!
|
||||
* Bootstrap Confirmation v1.0.5
|
||||
* https://github.com/tavicu/bs-confirmation
|
||||
*/
|
||||
+function ($) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
//var for check event at body can have only one.
|
||||
var event_body = false;
|
||||
//var for check event at body can have only one.
|
||||
var event_body = false;
|
||||
|
||||
// CONFIRMATION PUBLIC CLASS DEFINITION
|
||||
// ===============================
|
||||
var Confirmation = function (element, options) {
|
||||
var that = this;
|
||||
// CONFIRMATION PUBLIC CLASS DEFINITION
|
||||
// ===============================
|
||||
var Confirmation = function (element, options) {
|
||||
var that = this;
|
||||
|
||||
this.init('confirmation', element, options);
|
||||
this.init('confirmation', element, options);
|
||||
|
||||
$(element).on('show.bs.confirmation', function(e) {
|
||||
that.options.onShow(e, this);
|
||||
|
||||
$(this).addClass('open');
|
||||
|
||||
var options = that.options;
|
||||
var all = options.all_selector;
|
||||
|
||||
if(options.singleton)
|
||||
{
|
||||
$(all).not(that.$element).each(function()
|
||||
{
|
||||
if( $(this).hasClass('open') )
|
||||
{
|
||||
$(this).confirmation('hide');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$(element).on('hide.bs.confirmation', function(e) {
|
||||
that.options.onHide(e, this);
|
||||
|
||||
$(this).removeClass('open');
|
||||
});
|
||||
|
||||
$(element).on('shown.bs.confirmation', function(e) {
|
||||
var options = that.options;
|
||||
var all = options.all_selector;
|
||||
|
||||
if(that.isPopout()) {
|
||||
if(!event_body) {
|
||||
event_body = $('body').on('click', function (e) {
|
||||
if(that.$element.is(e.target)) return;
|
||||
if(that.$element.has(e.target).length) return;
|
||||
if($('.popover').has(e.target).length) return;
|
||||
|
||||
that.hide();
|
||||
that.inState.click = false;
|
||||
|
||||
$('body').unbind(e);
|
||||
|
||||
event_body = false;
|
||||
|
||||
return;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(options.selector) {
|
||||
$(element).on('click.bs.confirmation', options.selector, function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
} else {
|
||||
$(element).on('click.bs.confirmation', function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!$.fn.popover || !$.fn.tooltip) throw new Error('Confirmation requires popover.js and tooltip.js');
|
||||
|
||||
Confirmation.VERSION = '1.0.5'
|
||||
|
||||
Confirmation.DEFAULTS = $.extend({}, $.fn.popover.Constructor.DEFAULTS, {
|
||||
placement : 'right',
|
||||
title : 'Are you sure?',
|
||||
btnOkClass : 'btn btn-sm btn-danger',
|
||||
btnOkLabel : 'Delete',
|
||||
btnOkIcon : 'glyphicon glyphicon-ok',
|
||||
btnCancelClass : 'btn btn-sm btn-default',
|
||||
btnCancelLabel : 'Cancel',
|
||||
btnCancelIcon : 'glyphicon glyphicon-remove',
|
||||
href : '#',
|
||||
target : '_self',
|
||||
singleton : true,
|
||||
popout : true,
|
||||
onShow : function(event, element){},
|
||||
onHide : function(event, element){},
|
||||
onConfirm : function(event, element){},
|
||||
onCancel : function(event, element){},
|
||||
template : '<div class="popover"><div class="arrow"></div>'
|
||||
+ '<h3 class="popover-title"></h3>'
|
||||
+ '<div class="popover-content">'
|
||||
+ '<a data-apply="confirmation">Yes</a>'
|
||||
+ '<a data-dismiss="confirmation">No</a>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
});
|
||||
|
||||
|
||||
$(element).on('show.bs.confirmation', function(e) {
|
||||
that.options.onShow(e, this);
|
||||
// NOTE: CONFIRMATION EXTENDS popover.js
|
||||
// ================================
|
||||
Confirmation.prototype = $.extend({}, $.fn.popover.Constructor.prototype);
|
||||
|
||||
$(this).addClass('open');
|
||||
Confirmation.prototype.constructor = Confirmation;
|
||||
|
||||
var options = that.options;
|
||||
var all = options.all_selector;
|
||||
Confirmation.prototype.getDefaults = function () {
|
||||
return Confirmation.DEFAULTS;
|
||||
}
|
||||
|
||||
if(options.singleton)
|
||||
{
|
||||
$(all).not(that.$element).each(function()
|
||||
{
|
||||
if( $(this).hasClass('open') )
|
||||
{
|
||||
$(this).confirmation('hide');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
Confirmation.prototype.setContent = function () {
|
||||
var that = this;
|
||||
var $tip = this.tip();
|
||||
var title = this.getTitle();
|
||||
var $btnOk = $tip.find('[data-apply="confirmation"]');
|
||||
var $btnCancel = $tip.find('[data-dismiss="confirmation"]');
|
||||
var options = this.options
|
||||
|
||||
$(element).on('hide.bs.confirmation', function(e) {
|
||||
that.options.onHide(e, this);
|
||||
$btnOk.addClass(this.getBtnOkClass())
|
||||
.html(this.getBtnOkLabel())
|
||||
.prepend($('<i></i>').addClass(this.getBtnOkIcon()), " ")
|
||||
.attr('href', this.getHref())
|
||||
.attr('target', this.getTarget())
|
||||
.off('click').on('click', function(event) {
|
||||
options.onConfirm(event, that.$element);
|
||||
|
||||
$(this).removeClass('open');
|
||||
});
|
||||
// If the button is a submit one
|
||||
if (that.$element.attr('type') == 'submit')
|
||||
that.$element.closest('form:first').submit();
|
||||
|
||||
$(element).on('shown.bs.confirmation', function(e) {
|
||||
var options = that.options;
|
||||
var all = options.all_selector;
|
||||
that.hide();
|
||||
that.inState.click = false;
|
||||
});
|
||||
|
||||
that.$element.on('click.dismiss.bs.confirmation', '[data-dismiss="confirmation"]', $.proxy(that.hide, that));
|
||||
$btnCancel.addClass(this.getBtnCancelClass())
|
||||
.html(this.getBtnCancelLabel())
|
||||
.prepend($('<i></i>').addClass(this.getBtnCancelIcon()), " ")
|
||||
.off('click').on('click', function(event){
|
||||
options.onCancel(event, that.$element);
|
||||
|
||||
if(that.isPopout()) {
|
||||
if(!event_body) {
|
||||
event_body = $('body').on('click', function (e) {
|
||||
if(that.$element.is(e.target)) return;
|
||||
if(that.$element.has(e.target).length) return;
|
||||
if($('.popover').has(e.target).length) return;
|
||||
that.hide();
|
||||
that.inState.click = false;
|
||||
});
|
||||
|
||||
that.$element.confirmation('hide');
|
||||
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title);
|
||||
|
||||
$('body').unbind(e);
|
||||
$tip.removeClass('fade top bottom left right in');
|
||||
|
||||
event_body = false;
|
||||
// IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
|
||||
// this manually by checking the contents.
|
||||
if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide();
|
||||
}
|
||||
|
||||
return;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
Confirmation.prototype.getBtnOkClass = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
$(element).on('click', function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
return $e.attr('data-btnOkClass') || (typeof o.btnOkClass == 'function' ? o.btnOkClass.call(this, $e[0]) : o.btnOkClass);
|
||||
}
|
||||
|
||||
if (!$.fn.popover || !$.fn.tooltip) throw new Error('Confirmation requires popover.js and tooltip.js');
|
||||
Confirmation.prototype.getBtnOkLabel = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
Confirmation.DEFAULTS = $.extend({}, $.fn.popover.Constructor.DEFAULTS, {
|
||||
placement : 'right',
|
||||
title : 'Are you sure?',
|
||||
btnOkClass : 'btn btn-sm btn-danger',
|
||||
btnOkLabel : 'Delete',
|
||||
btnOkIcon : 'glyphicon glyphicon-ok',
|
||||
btnCancelClass : 'btn btn-sm btn-default',
|
||||
btnCancelLabel : 'Cancel',
|
||||
btnCancelIcon : 'glyphicon glyphicon-remove',
|
||||
href : '#',
|
||||
target : '_self',
|
||||
singleton : true,
|
||||
popout : true,
|
||||
onShow : function(event, element){},
|
||||
onHide : function(event, element){},
|
||||
onConfirm : function(event, element){},
|
||||
onCancel : function(event, element){},
|
||||
template : '<div class="popover"><div class="arrow"></div>'
|
||||
+ '<h3 class="popover-title"></h3>'
|
||||
+ '<div class="popover-content">'
|
||||
+ '<div class="btn-group">'
|
||||
+ '<a data-dismiss="confirmation">No</a>'
|
||||
+ '<a data-apply="confirmation">Yes</a>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
});
|
||||
return $e.attr('data-btnOkLabel') || (typeof o.btnOkLabel == 'function' ? o.btnOkLabel.call(this, $e[0]) : o.btnOkLabel);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnOkIcon = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnOkIcon') || (typeof o.btnOkIcon == 'function' ? o.btnOkIcon.call(this, $e[0]) : o.btnOkIcon);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelClass = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelClass') || (typeof o.btnCancelClass == 'function' ? o.btnCancelClass.call(this, $e[0]) : o.btnCancelClass);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelLabel = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelLabel') || (typeof o.btnCancelLabel == 'function' ? o.btnCancelLabel.call(this, $e[0]) : o.btnCancelLabel);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelIcon = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelIcon') || (typeof o.btnCancelIcon == 'function' ? o.btnCancelIcon.call(this, $e[0]) : o.btnCancelIcon);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getHref = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-href') || (typeof o.href == 'function' ? o.href.call(this, $e[0]) : o.href);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getTarget = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-target') || (typeof o.target == 'function' ? o.target.call(this, $e[0]) : o.target);
|
||||
}
|
||||
|
||||
Confirmation.prototype.isPopout = function () {
|
||||
var popout;
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
popout = $e.attr('data-popout') || (typeof o.popout == 'function' ? o.popout.call(this, $e[0]) : o.popout);
|
||||
|
||||
if(popout == 'false') popout = false;
|
||||
|
||||
return popout
|
||||
}
|
||||
|
||||
|
||||
// NOTE: CONFIRMATION EXTENDS popover.js
|
||||
// ================================
|
||||
Confirmation.prototype = $.extend({}, $.fn.popover.Constructor.prototype);
|
||||
// CONFIRMATION PLUGIN DEFINITION
|
||||
// =========================
|
||||
var old = $.fn.confirmation;
|
||||
|
||||
Confirmation.prototype.constructor = Confirmation;
|
||||
$.fn.confirmation = function (option) {
|
||||
var that = this;
|
||||
|
||||
Confirmation.prototype.getDefaults = function () {
|
||||
return Confirmation.DEFAULTS;
|
||||
}
|
||||
return this.each(function () {
|
||||
var $this = $(this);
|
||||
var data = $this.data('bs.confirmation');
|
||||
var options = typeof option == 'object' && option;
|
||||
|
||||
Confirmation.prototype.setContent = function () {
|
||||
var that = this;
|
||||
var $tip = this.tip();
|
||||
var title = this.getTitle();
|
||||
var $btnOk = $tip.find('[data-apply="confirmation"]');
|
||||
var $btnCancel = $tip.find('[data-dismiss="confirmation"]');
|
||||
var options = this.options
|
||||
options = options || {};
|
||||
options.all_selector = that.selector;
|
||||
|
||||
$btnOk.addClass(this.getBtnOkClass())
|
||||
.html(this.getBtnOkLabel())
|
||||
.prepend($('<i></i>').addClass(this.getBtnOkIcon()), " ")
|
||||
.attr('href', this.getHref())
|
||||
.attr('target', this.getTarget())
|
||||
.off('click').on('click', function(event) {
|
||||
that.$element.confirmation('hide');
|
||||
if (!data && option == 'destroy') return;
|
||||
if (!data) $this.data('bs.confirmation', (data = new Confirmation(this, options)));
|
||||
if (typeof option == 'string') data[option]();
|
||||
});
|
||||
}
|
||||
|
||||
options.onConfirm(event, that.$element);
|
||||
});
|
||||
|
||||
$btnCancel.addClass(this.getBtnCancelClass())
|
||||
.html(this.getBtnCancelLabel())
|
||||
.prepend($('<i></i>').addClass(this.getBtnCancelIcon()), " ")
|
||||
.off('click').on('click', function(event){
|
||||
options.onCancel(event, that.$element);
|
||||
|
||||
that.$element.confirmation('hide');
|
||||
});
|
||||
|
||||
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title);
|
||||
|
||||
$tip.removeClass('fade top bottom left right in');
|
||||
|
||||
// IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
|
||||
// this manually by checking the contents.
|
||||
if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide();
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnOkClass = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnOkClass') || (typeof o.btnOkClass == 'function' ? o.btnOkClass.call($e[0]) : o.btnOkClass);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnOkLabel = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnOkLabel') || (typeof o.btnOkLabel == 'function' ? o.btnOkLabel.call($e[0]) : o.btnOkLabel);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnOkIcon = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnOkIcon') || (typeof o.btnOkIcon == 'function' ? o.btnOkIcon.call($e[0]) : o.btnOkIcon);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelClass = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelClass') || (typeof o.btnCancelClass == 'function' ? o.btnCancelClass.call($e[0]) : o.btnCancelClass);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelLabel = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelLabel') || (typeof o.btnCancelLabel == 'function' ? o.btnCancelLabel.call($e[0]) : o.btnCancelLabel);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelIcon = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelIcon') || (typeof o.btnCancelIcon == 'function' ? o.btnCancelIcon.call($e[0]) : o.btnCancelIcon);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getHref = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-href') || (typeof o.href == 'function' ? o.href.call($e[0]) : o.href);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getTarget = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-target') || (typeof o.target == 'function' ? o.target.call($e[0]) : o.target);
|
||||
}
|
||||
|
||||
Confirmation.prototype.isPopout = function () {
|
||||
var popout;
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
popout = $e.attr('data-popout') || (typeof o.popout == 'function' ? o.popout.call($e[0]) : o.popout);
|
||||
|
||||
if(popout == 'false') popout = false;
|
||||
|
||||
return popout
|
||||
}
|
||||
$.fn.confirmation.Constructor = Confirmation
|
||||
|
||||
|
||||
// CONFIRMATION PLUGIN DEFINITION
|
||||
// =========================
|
||||
var old = $.fn.confirmation;
|
||||
// CONFIRMATION NO CONFLICT
|
||||
// ===================
|
||||
$.fn.confirmation.noConflict = function () {
|
||||
$.fn.confirmation = old;
|
||||
|
||||
$.fn.confirmation = function (option) {
|
||||
var that = this;
|
||||
|
||||
return this.each(function () {
|
||||
var $this = $(this);
|
||||
var data = $this.data('bs.confirmation');
|
||||
var options = typeof option == 'object' && option;
|
||||
|
||||
options = options || {};
|
||||
options.all_selector = that.selector;
|
||||
|
||||
if (!data && option == 'destroy') return;
|
||||
if (!data) $this.data('bs.confirmation', (data = new Confirmation(this, options)));
|
||||
if (typeof option == 'string') data[option]();
|
||||
});
|
||||
}
|
||||
|
||||
$.fn.confirmation.Constructor = Confirmation
|
||||
|
||||
|
||||
// CONFIRMATION NO CONFLICT
|
||||
// ===================
|
||||
$.fn.confirmation.noConflict = function () {
|
||||
$.fn.confirmation = old;
|
||||
|
||||
return this;
|
||||
}
|
||||
}(jQuery);
|
||||
return this;
|
||||
}
|
||||
}(jQuery);
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -48,7 +48,7 @@ requirejs.config({
|
||||
blueImpGallery: 'lib/blueimp-gallery', // v2.21.3 Image Gallery - https://github.com/blueimp/Gallery
|
||||
blueImpGalleryHelper: 'lib/blueimp-helper', // helper function for Blue Imp Gallery
|
||||
blueImpGalleryBootstrap: 'lib/bootstrap-image-gallery', // v3.4.2 Bootstrap extension for Blue Imp Gallery - https://blueimp.github.io/Bootstrap-Image-Gallery
|
||||
bootstrapConfirmation: 'lib/bootstrap-confirmation', // v1.0.1 Bootstrap extension for inline confirm dialog - https://github.com/tavicu/bs-confirmation
|
||||
bootstrapConfirmation: 'lib/bootstrap-confirmation', // v1.0.5 Bootstrap extension for inline confirm dialog - https://github.com/tavicu/bs-confirmation
|
||||
bootstrapToggle: 'lib/bootstrap2-toggle.min', // v2.2.0 Bootstrap Toggle (Checkbox) - http://www.bootstraptoggle.com
|
||||
lazyload: 'lib/jquery.lazyload.min', // v1.9.5 LazyLoader images - http://www.appelsiini.net/projects/lazyload
|
||||
|
||||
@@ -21,6 +21,7 @@ define('app/init',['jquery'], function($) {
|
||||
logIn: 'api/user/logIn', // ajax URL - login
|
||||
logout: 'api/user/logout', // ajax URL - logout
|
||||
deleteLog: 'api/user/deleteLog', // ajax URL - delete character log
|
||||
openIngameWindow: 'api/user/openIngameWindow', // ajax URL - open inGame Window
|
||||
saveUserConfig: 'api/user/saveAccount', // ajax URL - saves/update user account
|
||||
deleteAccount: 'api/user/deleteAccount', // ajax URL - delete Account data
|
||||
// access API
|
||||
@@ -70,6 +71,7 @@ define('app/init',['jquery'], function($) {
|
||||
splashOverlay: 300, // "splash" loading overlay
|
||||
headerLink: 100, // links in head bar
|
||||
mapOverlay: 200, // show/hide duration for map overlays
|
||||
mapOverlayLocal: 180, // show/hide duration for map "local" overlay
|
||||
mapMoveSystem: 180, // system position has changed animation
|
||||
mapDeleteSystem: 200, // remove system from map
|
||||
mapModule: 200, // show/hide of an map module
|
||||
@@ -1688,255 +1690,270 @@ define("xEditable", ["bootstrap"], function(){});
|
||||
(function($){$.fn.hoverIntent=function(handlerIn,handlerOut,selector){var cfg={interval:100,sensitivity:6,timeout:0};if(typeof handlerIn==="object"){cfg=$.extend(cfg,handlerIn)}else{if($.isFunction(handlerOut)){cfg=$.extend(cfg,{over:handlerIn,out:handlerOut,selector:selector})}else{cfg=$.extend(cfg,{over:handlerIn,out:handlerIn,selector:handlerOut})}}var cX,cY,pX,pY;var track=function(ev){cX=ev.pageX;cY=ev.pageY};var compare=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);if(Math.sqrt((pX-cX)*(pX-cX)+(pY-cY)*(pY-cY))<cfg.sensitivity){$(ob).off("mousemove.hoverIntent",track);ob.hoverIntent_s=true;return cfg.over.apply(ob,[ev])}else{pX=cX;pY=cY;ob.hoverIntent_t=setTimeout(function(){compare(ev,ob)},cfg.interval)}};var delay=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);ob.hoverIntent_s=false;return cfg.out.apply(ob,[ev])};var handleHover=function(e){var ev=$.extend({},e);var ob=this;if(ob.hoverIntent_t){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t)}if(e.type==="mouseenter"){pX=ev.pageX;pY=ev.pageY;$(ob).on("mousemove.hoverIntent",track);if(!ob.hoverIntent_s){ob.hoverIntent_t=setTimeout(function(){compare(ev,ob)},cfg.interval)}}else{$(ob).off("mousemove.hoverIntent",track);if(ob.hoverIntent_s){ob.hoverIntent_t=setTimeout(function(){delay(ev,ob)},cfg.timeout)}}};return this.on({"mouseenter.hoverIntent":handleHover,"mouseleave.hoverIntent":handleHover},cfg.selector)}})(jQuery);
|
||||
define("hoverIntent", ["jquery"], function(){});
|
||||
|
||||
/*!
|
||||
* Bootstrap Confirmation v1.0.5
|
||||
* https://github.com/tavicu/bs-confirmation
|
||||
*/
|
||||
+function ($) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
//var for check event at body can have only one.
|
||||
var event_body = false;
|
||||
//var for check event at body can have only one.
|
||||
var event_body = false;
|
||||
|
||||
// CONFIRMATION PUBLIC CLASS DEFINITION
|
||||
// ===============================
|
||||
var Confirmation = function (element, options) {
|
||||
var that = this;
|
||||
// CONFIRMATION PUBLIC CLASS DEFINITION
|
||||
// ===============================
|
||||
var Confirmation = function (element, options) {
|
||||
var that = this;
|
||||
|
||||
this.init('confirmation', element, options);
|
||||
this.init('confirmation', element, options);
|
||||
|
||||
$(element).on('show.bs.confirmation', function(e) {
|
||||
that.options.onShow(e, this);
|
||||
|
||||
$(this).addClass('open');
|
||||
|
||||
var options = that.options;
|
||||
var all = options.all_selector;
|
||||
|
||||
if(options.singleton)
|
||||
{
|
||||
$(all).not(that.$element).each(function()
|
||||
{
|
||||
if( $(this).hasClass('open') )
|
||||
{
|
||||
$(this).confirmation('hide');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$(element).on('hide.bs.confirmation', function(e) {
|
||||
that.options.onHide(e, this);
|
||||
|
||||
$(this).removeClass('open');
|
||||
});
|
||||
|
||||
$(element).on('shown.bs.confirmation', function(e) {
|
||||
var options = that.options;
|
||||
var all = options.all_selector;
|
||||
|
||||
if(that.isPopout()) {
|
||||
if(!event_body) {
|
||||
event_body = $('body').on('click', function (e) {
|
||||
if(that.$element.is(e.target)) return;
|
||||
if(that.$element.has(e.target).length) return;
|
||||
if($('.popover').has(e.target).length) return;
|
||||
|
||||
that.hide();
|
||||
that.inState.click = false;
|
||||
|
||||
$('body').unbind(e);
|
||||
|
||||
event_body = false;
|
||||
|
||||
return;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(options.selector) {
|
||||
$(element).on('click.bs.confirmation', options.selector, function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
} else {
|
||||
$(element).on('click.bs.confirmation', function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!$.fn.popover || !$.fn.tooltip) throw new Error('Confirmation requires popover.js and tooltip.js');
|
||||
|
||||
Confirmation.VERSION = '1.0.5'
|
||||
|
||||
Confirmation.DEFAULTS = $.extend({}, $.fn.popover.Constructor.DEFAULTS, {
|
||||
placement : 'right',
|
||||
title : 'Are you sure?',
|
||||
btnOkClass : 'btn btn-sm btn-danger',
|
||||
btnOkLabel : 'Delete',
|
||||
btnOkIcon : 'glyphicon glyphicon-ok',
|
||||
btnCancelClass : 'btn btn-sm btn-default',
|
||||
btnCancelLabel : 'Cancel',
|
||||
btnCancelIcon : 'glyphicon glyphicon-remove',
|
||||
href : '#',
|
||||
target : '_self',
|
||||
singleton : true,
|
||||
popout : true,
|
||||
onShow : function(event, element){},
|
||||
onHide : function(event, element){},
|
||||
onConfirm : function(event, element){},
|
||||
onCancel : function(event, element){},
|
||||
template : '<div class="popover"><div class="arrow"></div>'
|
||||
+ '<h3 class="popover-title"></h3>'
|
||||
+ '<div class="popover-content">'
|
||||
+ '<a data-apply="confirmation">Yes</a>'
|
||||
+ '<a data-dismiss="confirmation">No</a>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
});
|
||||
|
||||
|
||||
$(element).on('show.bs.confirmation', function(e) {
|
||||
that.options.onShow(e, this);
|
||||
// NOTE: CONFIRMATION EXTENDS popover.js
|
||||
// ================================
|
||||
Confirmation.prototype = $.extend({}, $.fn.popover.Constructor.prototype);
|
||||
|
||||
$(this).addClass('open');
|
||||
Confirmation.prototype.constructor = Confirmation;
|
||||
|
||||
var options = that.options;
|
||||
var all = options.all_selector;
|
||||
Confirmation.prototype.getDefaults = function () {
|
||||
return Confirmation.DEFAULTS;
|
||||
}
|
||||
|
||||
if(options.singleton)
|
||||
{
|
||||
$(all).not(that.$element).each(function()
|
||||
{
|
||||
if( $(this).hasClass('open') )
|
||||
{
|
||||
$(this).confirmation('hide');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
Confirmation.prototype.setContent = function () {
|
||||
var that = this;
|
||||
var $tip = this.tip();
|
||||
var title = this.getTitle();
|
||||
var $btnOk = $tip.find('[data-apply="confirmation"]');
|
||||
var $btnCancel = $tip.find('[data-dismiss="confirmation"]');
|
||||
var options = this.options
|
||||
|
||||
$(element).on('hide.bs.confirmation', function(e) {
|
||||
that.options.onHide(e, this);
|
||||
$btnOk.addClass(this.getBtnOkClass())
|
||||
.html(this.getBtnOkLabel())
|
||||
.prepend($('<i></i>').addClass(this.getBtnOkIcon()), " ")
|
||||
.attr('href', this.getHref())
|
||||
.attr('target', this.getTarget())
|
||||
.off('click').on('click', function(event) {
|
||||
options.onConfirm(event, that.$element);
|
||||
|
||||
$(this).removeClass('open');
|
||||
});
|
||||
// If the button is a submit one
|
||||
if (that.$element.attr('type') == 'submit')
|
||||
that.$element.closest('form:first').submit();
|
||||
|
||||
$(element).on('shown.bs.confirmation', function(e) {
|
||||
var options = that.options;
|
||||
var all = options.all_selector;
|
||||
that.hide();
|
||||
that.inState.click = false;
|
||||
});
|
||||
|
||||
that.$element.on('click.dismiss.bs.confirmation', '[data-dismiss="confirmation"]', $.proxy(that.hide, that));
|
||||
$btnCancel.addClass(this.getBtnCancelClass())
|
||||
.html(this.getBtnCancelLabel())
|
||||
.prepend($('<i></i>').addClass(this.getBtnCancelIcon()), " ")
|
||||
.off('click').on('click', function(event){
|
||||
options.onCancel(event, that.$element);
|
||||
|
||||
if(that.isPopout()) {
|
||||
if(!event_body) {
|
||||
event_body = $('body').on('click', function (e) {
|
||||
if(that.$element.is(e.target)) return;
|
||||
if(that.$element.has(e.target).length) return;
|
||||
if($('.popover').has(e.target).length) return;
|
||||
that.hide();
|
||||
that.inState.click = false;
|
||||
});
|
||||
|
||||
that.$element.confirmation('hide');
|
||||
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title);
|
||||
|
||||
$('body').unbind(e);
|
||||
$tip.removeClass('fade top bottom left right in');
|
||||
|
||||
event_body = false;
|
||||
// IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
|
||||
// this manually by checking the contents.
|
||||
if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide();
|
||||
}
|
||||
|
||||
return;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
Confirmation.prototype.getBtnOkClass = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
$(element).on('click', function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
return $e.attr('data-btnOkClass') || (typeof o.btnOkClass == 'function' ? o.btnOkClass.call(this, $e[0]) : o.btnOkClass);
|
||||
}
|
||||
|
||||
if (!$.fn.popover || !$.fn.tooltip) throw new Error('Confirmation requires popover.js and tooltip.js');
|
||||
Confirmation.prototype.getBtnOkLabel = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
Confirmation.DEFAULTS = $.extend({}, $.fn.popover.Constructor.DEFAULTS, {
|
||||
placement : 'right',
|
||||
title : 'Are you sure?',
|
||||
btnOkClass : 'btn btn-sm btn-danger',
|
||||
btnOkLabel : 'Delete',
|
||||
btnOkIcon : 'glyphicon glyphicon-ok',
|
||||
btnCancelClass : 'btn btn-sm btn-default',
|
||||
btnCancelLabel : 'Cancel',
|
||||
btnCancelIcon : 'glyphicon glyphicon-remove',
|
||||
href : '#',
|
||||
target : '_self',
|
||||
singleton : true,
|
||||
popout : true,
|
||||
onShow : function(event, element){},
|
||||
onHide : function(event, element){},
|
||||
onConfirm : function(event, element){},
|
||||
onCancel : function(event, element){},
|
||||
template : '<div class="popover"><div class="arrow"></div>'
|
||||
+ '<h3 class="popover-title"></h3>'
|
||||
+ '<div class="popover-content">'
|
||||
+ '<div class="btn-group">'
|
||||
+ '<a data-dismiss="confirmation">No</a>'
|
||||
+ '<a data-apply="confirmation">Yes</a>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
});
|
||||
return $e.attr('data-btnOkLabel') || (typeof o.btnOkLabel == 'function' ? o.btnOkLabel.call(this, $e[0]) : o.btnOkLabel);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnOkIcon = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnOkIcon') || (typeof o.btnOkIcon == 'function' ? o.btnOkIcon.call(this, $e[0]) : o.btnOkIcon);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelClass = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelClass') || (typeof o.btnCancelClass == 'function' ? o.btnCancelClass.call(this, $e[0]) : o.btnCancelClass);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelLabel = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelLabel') || (typeof o.btnCancelLabel == 'function' ? o.btnCancelLabel.call(this, $e[0]) : o.btnCancelLabel);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelIcon = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelIcon') || (typeof o.btnCancelIcon == 'function' ? o.btnCancelIcon.call(this, $e[0]) : o.btnCancelIcon);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getHref = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-href') || (typeof o.href == 'function' ? o.href.call(this, $e[0]) : o.href);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getTarget = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-target') || (typeof o.target == 'function' ? o.target.call(this, $e[0]) : o.target);
|
||||
}
|
||||
|
||||
Confirmation.prototype.isPopout = function () {
|
||||
var popout;
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
popout = $e.attr('data-popout') || (typeof o.popout == 'function' ? o.popout.call(this, $e[0]) : o.popout);
|
||||
|
||||
if(popout == 'false') popout = false;
|
||||
|
||||
return popout
|
||||
}
|
||||
|
||||
|
||||
// NOTE: CONFIRMATION EXTENDS popover.js
|
||||
// ================================
|
||||
Confirmation.prototype = $.extend({}, $.fn.popover.Constructor.prototype);
|
||||
// CONFIRMATION PLUGIN DEFINITION
|
||||
// =========================
|
||||
var old = $.fn.confirmation;
|
||||
|
||||
Confirmation.prototype.constructor = Confirmation;
|
||||
$.fn.confirmation = function (option) {
|
||||
var that = this;
|
||||
|
||||
Confirmation.prototype.getDefaults = function () {
|
||||
return Confirmation.DEFAULTS;
|
||||
}
|
||||
return this.each(function () {
|
||||
var $this = $(this);
|
||||
var data = $this.data('bs.confirmation');
|
||||
var options = typeof option == 'object' && option;
|
||||
|
||||
Confirmation.prototype.setContent = function () {
|
||||
var that = this;
|
||||
var $tip = this.tip();
|
||||
var title = this.getTitle();
|
||||
var $btnOk = $tip.find('[data-apply="confirmation"]');
|
||||
var $btnCancel = $tip.find('[data-dismiss="confirmation"]');
|
||||
var options = this.options
|
||||
options = options || {};
|
||||
options.all_selector = that.selector;
|
||||
|
||||
$btnOk.addClass(this.getBtnOkClass())
|
||||
.html(this.getBtnOkLabel())
|
||||
.prepend($('<i></i>').addClass(this.getBtnOkIcon()), " ")
|
||||
.attr('href', this.getHref())
|
||||
.attr('target', this.getTarget())
|
||||
.off('click').on('click', function(event) {
|
||||
that.$element.confirmation('hide');
|
||||
if (!data && option == 'destroy') return;
|
||||
if (!data) $this.data('bs.confirmation', (data = new Confirmation(this, options)));
|
||||
if (typeof option == 'string') data[option]();
|
||||
});
|
||||
}
|
||||
|
||||
options.onConfirm(event, that.$element);
|
||||
});
|
||||
|
||||
$btnCancel.addClass(this.getBtnCancelClass())
|
||||
.html(this.getBtnCancelLabel())
|
||||
.prepend($('<i></i>').addClass(this.getBtnCancelIcon()), " ")
|
||||
.off('click').on('click', function(event){
|
||||
options.onCancel(event, that.$element);
|
||||
|
||||
that.$element.confirmation('hide');
|
||||
});
|
||||
|
||||
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title);
|
||||
|
||||
$tip.removeClass('fade top bottom left right in');
|
||||
|
||||
// IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
|
||||
// this manually by checking the contents.
|
||||
if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide();
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnOkClass = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnOkClass') || (typeof o.btnOkClass == 'function' ? o.btnOkClass.call($e[0]) : o.btnOkClass);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnOkLabel = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnOkLabel') || (typeof o.btnOkLabel == 'function' ? o.btnOkLabel.call($e[0]) : o.btnOkLabel);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnOkIcon = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnOkIcon') || (typeof o.btnOkIcon == 'function' ? o.btnOkIcon.call($e[0]) : o.btnOkIcon);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelClass = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelClass') || (typeof o.btnCancelClass == 'function' ? o.btnCancelClass.call($e[0]) : o.btnCancelClass);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelLabel = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelLabel') || (typeof o.btnCancelLabel == 'function' ? o.btnCancelLabel.call($e[0]) : o.btnCancelLabel);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelIcon = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelIcon') || (typeof o.btnCancelIcon == 'function' ? o.btnCancelIcon.call($e[0]) : o.btnCancelIcon);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getHref = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-href') || (typeof o.href == 'function' ? o.href.call($e[0]) : o.href);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getTarget = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-target') || (typeof o.target == 'function' ? o.target.call($e[0]) : o.target);
|
||||
}
|
||||
|
||||
Confirmation.prototype.isPopout = function () {
|
||||
var popout;
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
popout = $e.attr('data-popout') || (typeof o.popout == 'function' ? o.popout.call($e[0]) : o.popout);
|
||||
|
||||
if(popout == 'false') popout = false;
|
||||
|
||||
return popout
|
||||
}
|
||||
$.fn.confirmation.Constructor = Confirmation
|
||||
|
||||
|
||||
// CONFIRMATION PLUGIN DEFINITION
|
||||
// =========================
|
||||
var old = $.fn.confirmation;
|
||||
// CONFIRMATION NO CONFLICT
|
||||
// ===================
|
||||
$.fn.confirmation.noConflict = function () {
|
||||
$.fn.confirmation = old;
|
||||
|
||||
$.fn.confirmation = function (option) {
|
||||
var that = this;
|
||||
|
||||
return this.each(function () {
|
||||
var $this = $(this);
|
||||
var data = $this.data('bs.confirmation');
|
||||
var options = typeof option == 'object' && option;
|
||||
|
||||
options = options || {};
|
||||
options.all_selector = that.selector;
|
||||
|
||||
if (!data && option == 'destroy') return;
|
||||
if (!data) $this.data('bs.confirmation', (data = new Confirmation(this, options)));
|
||||
if (typeof option == 'string') data[option]();
|
||||
});
|
||||
}
|
||||
|
||||
$.fn.confirmation.Constructor = Confirmation
|
||||
|
||||
|
||||
// CONFIRMATION NO CONFLICT
|
||||
// ===================
|
||||
$.fn.confirmation.noConflict = function () {
|
||||
$.fn.confirmation = old;
|
||||
|
||||
return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}(jQuery);
|
||||
|
||||
define("bootstrapConfirmation", ["bootstrap"], function(){});
|
||||
|
||||
/*! ========================================================================
|
||||
@@ -2004,6 +2021,9 @@ define('app/util',[
|
||||
// map module
|
||||
mapModuleId: 'pf-map-module', // id for main map module
|
||||
mapTabBarId: 'pf-map-tabs', // id for map tab bar
|
||||
mapWrapperClass: 'pf-map-wrapper', // wrapper div (scrollable)
|
||||
mapClass: 'pf-map' , // class for all maps
|
||||
|
||||
|
||||
// animation
|
||||
animationPulseSuccessClass: 'pf-animation-pulse-success', // animation class
|
||||
@@ -2030,40 +2050,41 @@ define('app/util',[
|
||||
* displays a loading indicator on an element
|
||||
*/
|
||||
$.fn.showLoadingAnimation = function(options){
|
||||
let loadingElement = $(this);
|
||||
return this.each(function(){
|
||||
let loadingElement = $(this);
|
||||
let iconSize = 'fa-lg';
|
||||
|
||||
let iconSize = 'fa-lg';
|
||||
// disable all events
|
||||
loadingElement.css('pointer-events', 'none');
|
||||
|
||||
// disable all events
|
||||
loadingElement.css('pointer-events', 'none');
|
||||
|
||||
if(options){
|
||||
if(options.icon){
|
||||
if(options.icon.size){
|
||||
iconSize = options.icon.size;
|
||||
if(options){
|
||||
if(options.icon){
|
||||
if(options.icon.size){
|
||||
iconSize = options.icon.size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let overlay = $('<div>', {
|
||||
class: config.ajaxOverlayClass
|
||||
}).append(
|
||||
$('<div>', {
|
||||
class: [config.ajaxOverlayWrapperClass].join(' ')
|
||||
let overlay = $('<div>', {
|
||||
class: config.ajaxOverlayClass
|
||||
}).append(
|
||||
$('<i>', {
|
||||
class: ['fa', 'fa-fw', iconSize, 'fa-refresh', 'fa-spin'].join(' ')
|
||||
})
|
||||
)
|
||||
);
|
||||
$('<div>', {
|
||||
class: [config.ajaxOverlayWrapperClass].join(' ')
|
||||
}).append(
|
||||
$('<i>', {
|
||||
class: ['fa', 'fa-fw', iconSize, 'fa-refresh', 'fa-spin'].join(' ')
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
loadingElement.append(overlay);
|
||||
loadingElement.append(overlay);
|
||||
|
||||
// fade in
|
||||
$(overlay).velocity({
|
||||
opacity: 0.6
|
||||
},{
|
||||
duration: 120
|
||||
// fade in
|
||||
$(overlay).velocity({
|
||||
opacity: 0.6
|
||||
},{
|
||||
duration: 120
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2071,16 +2092,20 @@ define('app/util',[
|
||||
* removes a loading indicator
|
||||
*/
|
||||
$.fn.hideLoadingAnimation = function(){
|
||||
let loadingElement = $(this);
|
||||
let overlay = loadingElement.find('.' + config.ajaxOverlayClass );
|
||||
return this.each(function(){
|
||||
let loadingElement = $(this);
|
||||
let overlay = loadingElement.find('.' + config.ajaxOverlayClass );
|
||||
|
||||
// important: "stop" is required to stop "show" animation
|
||||
// -> otherwise "complete" callback is not fired!
|
||||
$(overlay).velocity('stop').velocity('reverse', {
|
||||
complete: function(){
|
||||
$(this).remove();
|
||||
// enable all events
|
||||
loadingElement.css('pointer-events', 'auto');
|
||||
if(overlay.length){
|
||||
// important: "stop" is required to stop "show" animation
|
||||
// -> otherwise "complete" callback is not fired!
|
||||
overlay.velocity('stop').velocity('reverse', {
|
||||
complete: function(){
|
||||
$(this).remove();
|
||||
// enable all events
|
||||
loadingElement.css('pointer-events', 'auto');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -3216,6 +3241,15 @@ define('app/util',[
|
||||
return mapTabElements;
|
||||
};
|
||||
|
||||
/**
|
||||
* get mapElement from overlay or any child of that
|
||||
* @param mapOverlay
|
||||
* @returns {jQuery}
|
||||
*/
|
||||
let getMapElementFromOverlay = (mapOverlay) => {
|
||||
return $(mapOverlay).parents('.' + config.mapWrapperClass).find('.' + config.mapClass);
|
||||
};
|
||||
|
||||
/**
|
||||
* get the map module object or create a new module
|
||||
* @returns {*|HTMLElement}
|
||||
@@ -3748,6 +3782,132 @@ define('app/util',[
|
||||
return userInfo;
|
||||
};
|
||||
|
||||
/**
|
||||
* get "nearBy" systemData based on a jump radius around a currentSystem
|
||||
* @param currentSystemData
|
||||
* @param currentMapData
|
||||
* @param jumps
|
||||
* @param foundSystemIds
|
||||
* @returns {{systemData: *, tree: {}}}
|
||||
*/
|
||||
let getNearBySystemData = (currentSystemData, currentMapData, jumps, foundSystemIds = {}) => {
|
||||
|
||||
// look for systemData by ID
|
||||
let getSystemData = (systemId) => {
|
||||
for(let j = 0; j < currentMapData.data.systems.length; j++){
|
||||
let systemData = currentMapData.data.systems[j];
|
||||
if(systemData.id === systemId){
|
||||
return systemData;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// skip systems that are already found in recursive calls
|
||||
foundSystemIds[currentSystemData.id] = {distance: jumps};
|
||||
|
||||
let nearBySystems = {
|
||||
systemData: currentSystemData,
|
||||
tree: {}
|
||||
};
|
||||
|
||||
jumps--;
|
||||
if(jumps >= 0){
|
||||
for(let i = 0; i < currentMapData.data.connections.length; i++){
|
||||
let connectionData = currentMapData.data.connections[i];
|
||||
let type = ''; // "source" OR "target"
|
||||
if(connectionData.source === currentSystemData.id){
|
||||
type = 'target';
|
||||
}else if(connectionData.target === currentSystemData.id){
|
||||
type = 'source';
|
||||
}
|
||||
|
||||
if(
|
||||
type &&
|
||||
(
|
||||
foundSystemIds[connectionData[type]] === undefined ||
|
||||
foundSystemIds[connectionData[type]].distance < jumps
|
||||
)
|
||||
){
|
||||
let newSystemData = getSystemData(connectionData[type]);
|
||||
if(newSystemData){
|
||||
nearBySystems.tree[connectionData[type]] = getNearBySystemData(newSystemData, currentMapData, jumps, foundSystemIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nearBySystems;
|
||||
};
|
||||
|
||||
/**
|
||||
* get current character data from all characters who are "nearby" the current user
|
||||
* -> see getNearBySystemData()
|
||||
* @param nearBySystems
|
||||
* @param userData
|
||||
* @param jumps
|
||||
* @param data
|
||||
* @returns {{}}
|
||||
*/
|
||||
let getNearByCharacterData = (nearBySystems, userData, jumps = 0, data = {}) => {
|
||||
|
||||
let getCharacterDataBySystemId = (systemId) => {
|
||||
for(let i = 0; i < userData.length; i++){
|
||||
if(userData[i].id === systemId){
|
||||
return userData[i].user;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
let filterFinalCharData = function(tmpFinalCharData){
|
||||
return this.id !== tmpFinalCharData.id;
|
||||
};
|
||||
|
||||
let characterData = getCharacterDataBySystemId(nearBySystems.systemData.systemId);
|
||||
|
||||
if(characterData.length){
|
||||
// filter (remove) characterData for "already" added chars
|
||||
characterData = characterData.filter(function(tmpCharacterData, index, allData){
|
||||
let keepData = true;
|
||||
|
||||
for(let tmpJump in data) {
|
||||
// just scan systems with > jumps than current system
|
||||
if(tmpJump > jumps){
|
||||
let filteredFinalData = data[tmpJump].filter(filterFinalCharData, tmpCharacterData);
|
||||
|
||||
if(filteredFinalData.length > 0){
|
||||
data[tmpJump] = filteredFinalData;
|
||||
}else{
|
||||
delete data[tmpJump];
|
||||
}
|
||||
}else{
|
||||
for(let k = 0; k < data[tmpJump].length; k++){
|
||||
if(data[tmpJump][k].id === tmpCharacterData.id){
|
||||
keepData = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return keepData;
|
||||
});
|
||||
|
||||
data[jumps] = data[jumps] ? data[jumps] : [];
|
||||
data[jumps] = [...data[jumps], ...characterData];
|
||||
}
|
||||
|
||||
jumps++;
|
||||
for(let prop in nearBySystems.tree) {
|
||||
if( nearBySystems.tree.hasOwnProperty(prop) ){
|
||||
let tmpSystemData = nearBySystems.tree[prop];
|
||||
data = getNearByCharacterData(tmpSystemData, userData, jumps, data);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* set new destination for a system
|
||||
* -> CREST request
|
||||
@@ -3845,6 +4005,34 @@ define('app/util',[
|
||||
return $('.' + config.dialogClass).filter(':visible');
|
||||
};
|
||||
|
||||
/**
|
||||
* send Ajax request that remote opens an ingame Window
|
||||
* @param targetId
|
||||
*/
|
||||
let openIngameWindow = (targetId) => {
|
||||
targetId = parseInt(targetId);
|
||||
|
||||
if(targetId > 0){
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.openIngameWindow,
|
||||
data: {
|
||||
targetId: targetId
|
||||
},
|
||||
dataType: 'json'
|
||||
}).done(function(data){
|
||||
if(data.error.length > 0){
|
||||
showNotify({title: 'Open window in client', text: 'Remote window open failed', type: 'error'});
|
||||
}else{
|
||||
showNotify({title: 'Open window in client', text: 'Check your EVE client', type: 'success'});
|
||||
}
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
let reason = status + ' ' + error;
|
||||
showNotify({title: jqXHR.status + ': openWindow', text: reason, type: 'error'});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* formats a price string into an ISK Price
|
||||
* @param price
|
||||
@@ -3982,6 +4170,7 @@ define('app/util',[
|
||||
setSyncStatus: setSyncStatus,
|
||||
getSyncType: getSyncType,
|
||||
isXHRAborted: isXHRAborted,
|
||||
getMapElementFromOverlay: getMapElementFromOverlay,
|
||||
getMapModule: getMapModule,
|
||||
getSystemEffectData: getSystemEffectData,
|
||||
getSystemEffectTable: getSystemEffectTable,
|
||||
@@ -4009,9 +4198,12 @@ define('app/util',[
|
||||
getCurrentUserInfo: getCurrentUserInfo,
|
||||
getCurrentCharacterLog: getCurrentCharacterLog,
|
||||
flattenXEditableSelectArray: flattenXEditableSelectArray,
|
||||
getNearBySystemData: getNearBySystemData,
|
||||
getNearByCharacterData: getNearByCharacterData,
|
||||
setDestination: setDestination,
|
||||
convertDateToString: convertDateToString,
|
||||
getOpenDialogs: getOpenDialogs,
|
||||
openIngameWindow: openIngameWindow,
|
||||
formatPrice: formatPrice,
|
||||
getLocalStorage: getLocalStorage,
|
||||
getDocumentPath: getDocumentPath,
|
||||
@@ -7066,6 +7258,9 @@ define('login',[
|
||||
// cookie hint
|
||||
cookieHintId: 'pf-cookie-hint', // id for "cookie hint" element
|
||||
|
||||
// login
|
||||
ssoButtonClass: 'pf-sso-login-button', // class for SSO login button
|
||||
|
||||
// character select
|
||||
characterSelectionClass: 'pf-character-selection', // class for character panel wrapper
|
||||
characterRowAnimateClass: 'pf-character-row-animate', // class for character panel row during animation
|
||||
@@ -7086,7 +7281,9 @@ define('login',[
|
||||
serverPanelId: 'pf-server-panel', // id for EVE Online server status panel
|
||||
|
||||
// animation
|
||||
animateElementClass: 'pf-animate-on-visible' // class for elements that will be animated to show
|
||||
animateElementClass: 'pf-animate-on-visible', // class for elements that will be animated to show
|
||||
|
||||
defaultAcceptCookieExpire: 365 // default expire for "accept coolies" cookie
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -7143,10 +7340,39 @@ define('login',[
|
||||
if(getCookie('cookie') !== '1'){
|
||||
// hint not excepted
|
||||
$('#' + config.cookieHintId).collapse('show');
|
||||
|
||||
// show Cookie accept hint on SSO login button
|
||||
let confirmationSettings = {
|
||||
container: 'body',
|
||||
placement: 'bottom',
|
||||
btnOkClass: 'btn btn-sm btn-default',
|
||||
btnOkLabel: 'dismiss',
|
||||
btnOkIcon: 'fa fa-fw fa-sign-in',
|
||||
title: 'Accept cookies',
|
||||
btnCancelClass: 'btn btn-sm btn-success',
|
||||
btnCancelLabel: 'accept',
|
||||
btnCancelIcon: 'fa fa-fw fa-check',
|
||||
onCancel: function(e, target){
|
||||
// "Accept cookies"
|
||||
setCookie('cookie', 1, config.defaultAcceptCookieExpire);
|
||||
|
||||
// set "default" href
|
||||
let href = $(target).data('bs.confirmation').getHref();
|
||||
$(e.target).attr('href', href);
|
||||
},
|
||||
onConfirm : function(e, target){
|
||||
// "NO cookies" => trigger "default" href link action
|
||||
},
|
||||
href: function(target){
|
||||
return $(target).attr('href');
|
||||
}
|
||||
};
|
||||
|
||||
$('.' + config.ssoButtonClass).confirmation(confirmationSettings);
|
||||
}
|
||||
|
||||
$('#' + config.cookieHintId + ' .btn-success').on('click', function(){
|
||||
setCookie('cookie', 1, 365);
|
||||
setCookie('cookie', 1, config.defaultAcceptCookieExpire);
|
||||
});
|
||||
|
||||
// manual -------------------------------------------------------------
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -16,6 +16,7 @@ define('app/init',['jquery'], function($) {
|
||||
logIn: 'api/user/logIn', // ajax URL - login
|
||||
logout: 'api/user/logout', // ajax URL - logout
|
||||
deleteLog: 'api/user/deleteLog', // ajax URL - delete character log
|
||||
openIngameWindow: 'api/user/openIngameWindow', // ajax URL - open inGame Window
|
||||
saveUserConfig: 'api/user/saveAccount', // ajax URL - saves/update user account
|
||||
deleteAccount: 'api/user/deleteAccount', // ajax URL - delete Account data
|
||||
// access API
|
||||
@@ -65,6 +66,7 @@ define('app/init',['jquery'], function($) {
|
||||
splashOverlay: 300, // "splash" loading overlay
|
||||
headerLink: 100, // links in head bar
|
||||
mapOverlay: 200, // show/hide duration for map overlays
|
||||
mapOverlayLocal: 180, // show/hide duration for map "local" overlay
|
||||
mapMoveSystem: 180, // system position has changed animation
|
||||
mapDeleteSystem: 200, // remove system from map
|
||||
mapModule: 200, // show/hide of an map module
|
||||
File diff suppressed because one or more lines are too long
@@ -21,6 +21,7 @@ define('app/init',['jquery'], function($) {
|
||||
logIn: 'api/user/logIn', // ajax URL - login
|
||||
logout: 'api/user/logout', // ajax URL - logout
|
||||
deleteLog: 'api/user/deleteLog', // ajax URL - delete character log
|
||||
openIngameWindow: 'api/user/openIngameWindow', // ajax URL - open inGame Window
|
||||
saveUserConfig: 'api/user/saveAccount', // ajax URL - saves/update user account
|
||||
deleteAccount: 'api/user/deleteAccount', // ajax URL - delete Account data
|
||||
// access API
|
||||
@@ -70,6 +71,7 @@ define('app/init',['jquery'], function($) {
|
||||
splashOverlay: 300, // "splash" loading overlay
|
||||
headerLink: 100, // links in head bar
|
||||
mapOverlay: 200, // show/hide duration for map overlays
|
||||
mapOverlayLocal: 180, // show/hide duration for map "local" overlay
|
||||
mapMoveSystem: 180, // system position has changed animation
|
||||
mapDeleteSystem: 200, // remove system from map
|
||||
mapModule: 200, // show/hide of an map module
|
||||
@@ -1688,255 +1690,270 @@ define("xEditable", ["bootstrap"], function(){});
|
||||
(function($){$.fn.hoverIntent=function(handlerIn,handlerOut,selector){var cfg={interval:100,sensitivity:6,timeout:0};if(typeof handlerIn==="object"){cfg=$.extend(cfg,handlerIn)}else{if($.isFunction(handlerOut)){cfg=$.extend(cfg,{over:handlerIn,out:handlerOut,selector:selector})}else{cfg=$.extend(cfg,{over:handlerIn,out:handlerIn,selector:handlerOut})}}var cX,cY,pX,pY;var track=function(ev){cX=ev.pageX;cY=ev.pageY};var compare=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);if(Math.sqrt((pX-cX)*(pX-cX)+(pY-cY)*(pY-cY))<cfg.sensitivity){$(ob).off("mousemove.hoverIntent",track);ob.hoverIntent_s=true;return cfg.over.apply(ob,[ev])}else{pX=cX;pY=cY;ob.hoverIntent_t=setTimeout(function(){compare(ev,ob)},cfg.interval)}};var delay=function(ev,ob){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t);ob.hoverIntent_s=false;return cfg.out.apply(ob,[ev])};var handleHover=function(e){var ev=$.extend({},e);var ob=this;if(ob.hoverIntent_t){ob.hoverIntent_t=clearTimeout(ob.hoverIntent_t)}if(e.type==="mouseenter"){pX=ev.pageX;pY=ev.pageY;$(ob).on("mousemove.hoverIntent",track);if(!ob.hoverIntent_s){ob.hoverIntent_t=setTimeout(function(){compare(ev,ob)},cfg.interval)}}else{$(ob).off("mousemove.hoverIntent",track);if(ob.hoverIntent_s){ob.hoverIntent_t=setTimeout(function(){delay(ev,ob)},cfg.timeout)}}};return this.on({"mouseenter.hoverIntent":handleHover,"mouseleave.hoverIntent":handleHover},cfg.selector)}})(jQuery);
|
||||
define("hoverIntent", ["jquery"], function(){});
|
||||
|
||||
/*!
|
||||
* Bootstrap Confirmation v1.0.5
|
||||
* https://github.com/tavicu/bs-confirmation
|
||||
*/
|
||||
+function ($) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
//var for check event at body can have only one.
|
||||
var event_body = false;
|
||||
//var for check event at body can have only one.
|
||||
var event_body = false;
|
||||
|
||||
// CONFIRMATION PUBLIC CLASS DEFINITION
|
||||
// ===============================
|
||||
var Confirmation = function (element, options) {
|
||||
var that = this;
|
||||
// CONFIRMATION PUBLIC CLASS DEFINITION
|
||||
// ===============================
|
||||
var Confirmation = function (element, options) {
|
||||
var that = this;
|
||||
|
||||
this.init('confirmation', element, options);
|
||||
this.init('confirmation', element, options);
|
||||
|
||||
$(element).on('show.bs.confirmation', function(e) {
|
||||
that.options.onShow(e, this);
|
||||
|
||||
$(this).addClass('open');
|
||||
|
||||
var options = that.options;
|
||||
var all = options.all_selector;
|
||||
|
||||
if(options.singleton)
|
||||
{
|
||||
$(all).not(that.$element).each(function()
|
||||
{
|
||||
if( $(this).hasClass('open') )
|
||||
{
|
||||
$(this).confirmation('hide');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$(element).on('hide.bs.confirmation', function(e) {
|
||||
that.options.onHide(e, this);
|
||||
|
||||
$(this).removeClass('open');
|
||||
});
|
||||
|
||||
$(element).on('shown.bs.confirmation', function(e) {
|
||||
var options = that.options;
|
||||
var all = options.all_selector;
|
||||
|
||||
if(that.isPopout()) {
|
||||
if(!event_body) {
|
||||
event_body = $('body').on('click', function (e) {
|
||||
if(that.$element.is(e.target)) return;
|
||||
if(that.$element.has(e.target).length) return;
|
||||
if($('.popover').has(e.target).length) return;
|
||||
|
||||
that.hide();
|
||||
that.inState.click = false;
|
||||
|
||||
$('body').unbind(e);
|
||||
|
||||
event_body = false;
|
||||
|
||||
return;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(options.selector) {
|
||||
$(element).on('click.bs.confirmation', options.selector, function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
} else {
|
||||
$(element).on('click.bs.confirmation', function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!$.fn.popover || !$.fn.tooltip) throw new Error('Confirmation requires popover.js and tooltip.js');
|
||||
|
||||
Confirmation.VERSION = '1.0.5'
|
||||
|
||||
Confirmation.DEFAULTS = $.extend({}, $.fn.popover.Constructor.DEFAULTS, {
|
||||
placement : 'right',
|
||||
title : 'Are you sure?',
|
||||
btnOkClass : 'btn btn-sm btn-danger',
|
||||
btnOkLabel : 'Delete',
|
||||
btnOkIcon : 'glyphicon glyphicon-ok',
|
||||
btnCancelClass : 'btn btn-sm btn-default',
|
||||
btnCancelLabel : 'Cancel',
|
||||
btnCancelIcon : 'glyphicon glyphicon-remove',
|
||||
href : '#',
|
||||
target : '_self',
|
||||
singleton : true,
|
||||
popout : true,
|
||||
onShow : function(event, element){},
|
||||
onHide : function(event, element){},
|
||||
onConfirm : function(event, element){},
|
||||
onCancel : function(event, element){},
|
||||
template : '<div class="popover"><div class="arrow"></div>'
|
||||
+ '<h3 class="popover-title"></h3>'
|
||||
+ '<div class="popover-content">'
|
||||
+ '<a data-apply="confirmation">Yes</a>'
|
||||
+ '<a data-dismiss="confirmation">No</a>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
});
|
||||
|
||||
|
||||
$(element).on('show.bs.confirmation', function(e) {
|
||||
that.options.onShow(e, this);
|
||||
// NOTE: CONFIRMATION EXTENDS popover.js
|
||||
// ================================
|
||||
Confirmation.prototype = $.extend({}, $.fn.popover.Constructor.prototype);
|
||||
|
||||
$(this).addClass('open');
|
||||
Confirmation.prototype.constructor = Confirmation;
|
||||
|
||||
var options = that.options;
|
||||
var all = options.all_selector;
|
||||
Confirmation.prototype.getDefaults = function () {
|
||||
return Confirmation.DEFAULTS;
|
||||
}
|
||||
|
||||
if(options.singleton)
|
||||
{
|
||||
$(all).not(that.$element).each(function()
|
||||
{
|
||||
if( $(this).hasClass('open') )
|
||||
{
|
||||
$(this).confirmation('hide');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
Confirmation.prototype.setContent = function () {
|
||||
var that = this;
|
||||
var $tip = this.tip();
|
||||
var title = this.getTitle();
|
||||
var $btnOk = $tip.find('[data-apply="confirmation"]');
|
||||
var $btnCancel = $tip.find('[data-dismiss="confirmation"]');
|
||||
var options = this.options
|
||||
|
||||
$(element).on('hide.bs.confirmation', function(e) {
|
||||
that.options.onHide(e, this);
|
||||
$btnOk.addClass(this.getBtnOkClass())
|
||||
.html(this.getBtnOkLabel())
|
||||
.prepend($('<i></i>').addClass(this.getBtnOkIcon()), " ")
|
||||
.attr('href', this.getHref())
|
||||
.attr('target', this.getTarget())
|
||||
.off('click').on('click', function(event) {
|
||||
options.onConfirm(event, that.$element);
|
||||
|
||||
$(this).removeClass('open');
|
||||
});
|
||||
// If the button is a submit one
|
||||
if (that.$element.attr('type') == 'submit')
|
||||
that.$element.closest('form:first').submit();
|
||||
|
||||
$(element).on('shown.bs.confirmation', function(e) {
|
||||
var options = that.options;
|
||||
var all = options.all_selector;
|
||||
that.hide();
|
||||
that.inState.click = false;
|
||||
});
|
||||
|
||||
that.$element.on('click.dismiss.bs.confirmation', '[data-dismiss="confirmation"]', $.proxy(that.hide, that));
|
||||
$btnCancel.addClass(this.getBtnCancelClass())
|
||||
.html(this.getBtnCancelLabel())
|
||||
.prepend($('<i></i>').addClass(this.getBtnCancelIcon()), " ")
|
||||
.off('click').on('click', function(event){
|
||||
options.onCancel(event, that.$element);
|
||||
|
||||
if(that.isPopout()) {
|
||||
if(!event_body) {
|
||||
event_body = $('body').on('click', function (e) {
|
||||
if(that.$element.is(e.target)) return;
|
||||
if(that.$element.has(e.target).length) return;
|
||||
if($('.popover').has(e.target).length) return;
|
||||
that.hide();
|
||||
that.inState.click = false;
|
||||
});
|
||||
|
||||
that.$element.confirmation('hide');
|
||||
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title);
|
||||
|
||||
$('body').unbind(e);
|
||||
$tip.removeClass('fade top bottom left right in');
|
||||
|
||||
event_body = false;
|
||||
// IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
|
||||
// this manually by checking the contents.
|
||||
if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide();
|
||||
}
|
||||
|
||||
return;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
Confirmation.prototype.getBtnOkClass = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
$(element).on('click', function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
return $e.attr('data-btnOkClass') || (typeof o.btnOkClass == 'function' ? o.btnOkClass.call(this, $e[0]) : o.btnOkClass);
|
||||
}
|
||||
|
||||
if (!$.fn.popover || !$.fn.tooltip) throw new Error('Confirmation requires popover.js and tooltip.js');
|
||||
Confirmation.prototype.getBtnOkLabel = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
Confirmation.DEFAULTS = $.extend({}, $.fn.popover.Constructor.DEFAULTS, {
|
||||
placement : 'right',
|
||||
title : 'Are you sure?',
|
||||
btnOkClass : 'btn btn-sm btn-danger',
|
||||
btnOkLabel : 'Delete',
|
||||
btnOkIcon : 'glyphicon glyphicon-ok',
|
||||
btnCancelClass : 'btn btn-sm btn-default',
|
||||
btnCancelLabel : 'Cancel',
|
||||
btnCancelIcon : 'glyphicon glyphicon-remove',
|
||||
href : '#',
|
||||
target : '_self',
|
||||
singleton : true,
|
||||
popout : true,
|
||||
onShow : function(event, element){},
|
||||
onHide : function(event, element){},
|
||||
onConfirm : function(event, element){},
|
||||
onCancel : function(event, element){},
|
||||
template : '<div class="popover"><div class="arrow"></div>'
|
||||
+ '<h3 class="popover-title"></h3>'
|
||||
+ '<div class="popover-content">'
|
||||
+ '<div class="btn-group">'
|
||||
+ '<a data-dismiss="confirmation">No</a>'
|
||||
+ '<a data-apply="confirmation">Yes</a>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
+ '</div>'
|
||||
});
|
||||
return $e.attr('data-btnOkLabel') || (typeof o.btnOkLabel == 'function' ? o.btnOkLabel.call(this, $e[0]) : o.btnOkLabel);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnOkIcon = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnOkIcon') || (typeof o.btnOkIcon == 'function' ? o.btnOkIcon.call(this, $e[0]) : o.btnOkIcon);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelClass = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelClass') || (typeof o.btnCancelClass == 'function' ? o.btnCancelClass.call(this, $e[0]) : o.btnCancelClass);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelLabel = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelLabel') || (typeof o.btnCancelLabel == 'function' ? o.btnCancelLabel.call(this, $e[0]) : o.btnCancelLabel);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelIcon = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelIcon') || (typeof o.btnCancelIcon == 'function' ? o.btnCancelIcon.call(this, $e[0]) : o.btnCancelIcon);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getHref = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-href') || (typeof o.href == 'function' ? o.href.call(this, $e[0]) : o.href);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getTarget = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-target') || (typeof o.target == 'function' ? o.target.call(this, $e[0]) : o.target);
|
||||
}
|
||||
|
||||
Confirmation.prototype.isPopout = function () {
|
||||
var popout;
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
popout = $e.attr('data-popout') || (typeof o.popout == 'function' ? o.popout.call(this, $e[0]) : o.popout);
|
||||
|
||||
if(popout == 'false') popout = false;
|
||||
|
||||
return popout
|
||||
}
|
||||
|
||||
|
||||
// NOTE: CONFIRMATION EXTENDS popover.js
|
||||
// ================================
|
||||
Confirmation.prototype = $.extend({}, $.fn.popover.Constructor.prototype);
|
||||
// CONFIRMATION PLUGIN DEFINITION
|
||||
// =========================
|
||||
var old = $.fn.confirmation;
|
||||
|
||||
Confirmation.prototype.constructor = Confirmation;
|
||||
$.fn.confirmation = function (option) {
|
||||
var that = this;
|
||||
|
||||
Confirmation.prototype.getDefaults = function () {
|
||||
return Confirmation.DEFAULTS;
|
||||
}
|
||||
return this.each(function () {
|
||||
var $this = $(this);
|
||||
var data = $this.data('bs.confirmation');
|
||||
var options = typeof option == 'object' && option;
|
||||
|
||||
Confirmation.prototype.setContent = function () {
|
||||
var that = this;
|
||||
var $tip = this.tip();
|
||||
var title = this.getTitle();
|
||||
var $btnOk = $tip.find('[data-apply="confirmation"]');
|
||||
var $btnCancel = $tip.find('[data-dismiss="confirmation"]');
|
||||
var options = this.options
|
||||
options = options || {};
|
||||
options.all_selector = that.selector;
|
||||
|
||||
$btnOk.addClass(this.getBtnOkClass())
|
||||
.html(this.getBtnOkLabel())
|
||||
.prepend($('<i></i>').addClass(this.getBtnOkIcon()), " ")
|
||||
.attr('href', this.getHref())
|
||||
.attr('target', this.getTarget())
|
||||
.off('click').on('click', function(event) {
|
||||
that.$element.confirmation('hide');
|
||||
if (!data && option == 'destroy') return;
|
||||
if (!data) $this.data('bs.confirmation', (data = new Confirmation(this, options)));
|
||||
if (typeof option == 'string') data[option]();
|
||||
});
|
||||
}
|
||||
|
||||
options.onConfirm(event, that.$element);
|
||||
});
|
||||
|
||||
$btnCancel.addClass(this.getBtnCancelClass())
|
||||
.html(this.getBtnCancelLabel())
|
||||
.prepend($('<i></i>').addClass(this.getBtnCancelIcon()), " ")
|
||||
.off('click').on('click', function(event){
|
||||
options.onCancel(event, that.$element);
|
||||
|
||||
that.$element.confirmation('hide');
|
||||
});
|
||||
|
||||
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title);
|
||||
|
||||
$tip.removeClass('fade top bottom left right in');
|
||||
|
||||
// IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
|
||||
// this manually by checking the contents.
|
||||
if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide();
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnOkClass = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnOkClass') || (typeof o.btnOkClass == 'function' ? o.btnOkClass.call($e[0]) : o.btnOkClass);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnOkLabel = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnOkLabel') || (typeof o.btnOkLabel == 'function' ? o.btnOkLabel.call($e[0]) : o.btnOkLabel);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnOkIcon = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnOkIcon') || (typeof o.btnOkIcon == 'function' ? o.btnOkIcon.call($e[0]) : o.btnOkIcon);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelClass = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelClass') || (typeof o.btnCancelClass == 'function' ? o.btnCancelClass.call($e[0]) : o.btnCancelClass);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelLabel = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelLabel') || (typeof o.btnCancelLabel == 'function' ? o.btnCancelLabel.call($e[0]) : o.btnCancelLabel);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getBtnCancelIcon = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-btnCancelIcon') || (typeof o.btnCancelIcon == 'function' ? o.btnCancelIcon.call($e[0]) : o.btnCancelIcon);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getHref = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-href') || (typeof o.href == 'function' ? o.href.call($e[0]) : o.href);
|
||||
}
|
||||
|
||||
Confirmation.prototype.getTarget = function () {
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
return $e.attr('data-target') || (typeof o.target == 'function' ? o.target.call($e[0]) : o.target);
|
||||
}
|
||||
|
||||
Confirmation.prototype.isPopout = function () {
|
||||
var popout;
|
||||
var $e = this.$element;
|
||||
var o = this.options;
|
||||
|
||||
popout = $e.attr('data-popout') || (typeof o.popout == 'function' ? o.popout.call($e[0]) : o.popout);
|
||||
|
||||
if(popout == 'false') popout = false;
|
||||
|
||||
return popout
|
||||
}
|
||||
$.fn.confirmation.Constructor = Confirmation
|
||||
|
||||
|
||||
// CONFIRMATION PLUGIN DEFINITION
|
||||
// =========================
|
||||
var old = $.fn.confirmation;
|
||||
// CONFIRMATION NO CONFLICT
|
||||
// ===================
|
||||
$.fn.confirmation.noConflict = function () {
|
||||
$.fn.confirmation = old;
|
||||
|
||||
$.fn.confirmation = function (option) {
|
||||
var that = this;
|
||||
|
||||
return this.each(function () {
|
||||
var $this = $(this);
|
||||
var data = $this.data('bs.confirmation');
|
||||
var options = typeof option == 'object' && option;
|
||||
|
||||
options = options || {};
|
||||
options.all_selector = that.selector;
|
||||
|
||||
if (!data && option == 'destroy') return;
|
||||
if (!data) $this.data('bs.confirmation', (data = new Confirmation(this, options)));
|
||||
if (typeof option == 'string') data[option]();
|
||||
});
|
||||
}
|
||||
|
||||
$.fn.confirmation.Constructor = Confirmation
|
||||
|
||||
|
||||
// CONFIRMATION NO CONFLICT
|
||||
// ===================
|
||||
$.fn.confirmation.noConflict = function () {
|
||||
$.fn.confirmation = old;
|
||||
|
||||
return this;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}(jQuery);
|
||||
|
||||
define("bootstrapConfirmation", ["bootstrap"], function(){});
|
||||
|
||||
/*! ========================================================================
|
||||
@@ -2004,6 +2021,9 @@ define('app/util',[
|
||||
// map module
|
||||
mapModuleId: 'pf-map-module', // id for main map module
|
||||
mapTabBarId: 'pf-map-tabs', // id for map tab bar
|
||||
mapWrapperClass: 'pf-map-wrapper', // wrapper div (scrollable)
|
||||
mapClass: 'pf-map' , // class for all maps
|
||||
|
||||
|
||||
// animation
|
||||
animationPulseSuccessClass: 'pf-animation-pulse-success', // animation class
|
||||
@@ -2030,40 +2050,41 @@ define('app/util',[
|
||||
* displays a loading indicator on an element
|
||||
*/
|
||||
$.fn.showLoadingAnimation = function(options){
|
||||
let loadingElement = $(this);
|
||||
return this.each(function(){
|
||||
let loadingElement = $(this);
|
||||
let iconSize = 'fa-lg';
|
||||
|
||||
let iconSize = 'fa-lg';
|
||||
// disable all events
|
||||
loadingElement.css('pointer-events', 'none');
|
||||
|
||||
// disable all events
|
||||
loadingElement.css('pointer-events', 'none');
|
||||
|
||||
if(options){
|
||||
if(options.icon){
|
||||
if(options.icon.size){
|
||||
iconSize = options.icon.size;
|
||||
if(options){
|
||||
if(options.icon){
|
||||
if(options.icon.size){
|
||||
iconSize = options.icon.size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let overlay = $('<div>', {
|
||||
class: config.ajaxOverlayClass
|
||||
}).append(
|
||||
$('<div>', {
|
||||
class: [config.ajaxOverlayWrapperClass].join(' ')
|
||||
let overlay = $('<div>', {
|
||||
class: config.ajaxOverlayClass
|
||||
}).append(
|
||||
$('<i>', {
|
||||
class: ['fa', 'fa-fw', iconSize, 'fa-refresh', 'fa-spin'].join(' ')
|
||||
})
|
||||
)
|
||||
);
|
||||
$('<div>', {
|
||||
class: [config.ajaxOverlayWrapperClass].join(' ')
|
||||
}).append(
|
||||
$('<i>', {
|
||||
class: ['fa', 'fa-fw', iconSize, 'fa-refresh', 'fa-spin'].join(' ')
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
loadingElement.append(overlay);
|
||||
loadingElement.append(overlay);
|
||||
|
||||
// fade in
|
||||
$(overlay).velocity({
|
||||
opacity: 0.6
|
||||
},{
|
||||
duration: 120
|
||||
// fade in
|
||||
$(overlay).velocity({
|
||||
opacity: 0.6
|
||||
},{
|
||||
duration: 120
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
@@ -2071,16 +2092,20 @@ define('app/util',[
|
||||
* removes a loading indicator
|
||||
*/
|
||||
$.fn.hideLoadingAnimation = function(){
|
||||
let loadingElement = $(this);
|
||||
let overlay = loadingElement.find('.' + config.ajaxOverlayClass );
|
||||
return this.each(function(){
|
||||
let loadingElement = $(this);
|
||||
let overlay = loadingElement.find('.' + config.ajaxOverlayClass );
|
||||
|
||||
// important: "stop" is required to stop "show" animation
|
||||
// -> otherwise "complete" callback is not fired!
|
||||
$(overlay).velocity('stop').velocity('reverse', {
|
||||
complete: function(){
|
||||
$(this).remove();
|
||||
// enable all events
|
||||
loadingElement.css('pointer-events', 'auto');
|
||||
if(overlay.length){
|
||||
// important: "stop" is required to stop "show" animation
|
||||
// -> otherwise "complete" callback is not fired!
|
||||
overlay.velocity('stop').velocity('reverse', {
|
||||
complete: function(){
|
||||
$(this).remove();
|
||||
// enable all events
|
||||
loadingElement.css('pointer-events', 'auto');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -3216,6 +3241,15 @@ define('app/util',[
|
||||
return mapTabElements;
|
||||
};
|
||||
|
||||
/**
|
||||
* get mapElement from overlay or any child of that
|
||||
* @param mapOverlay
|
||||
* @returns {jQuery}
|
||||
*/
|
||||
let getMapElementFromOverlay = (mapOverlay) => {
|
||||
return $(mapOverlay).parents('.' + config.mapWrapperClass).find('.' + config.mapClass);
|
||||
};
|
||||
|
||||
/**
|
||||
* get the map module object or create a new module
|
||||
* @returns {*|HTMLElement}
|
||||
@@ -3748,6 +3782,132 @@ define('app/util',[
|
||||
return userInfo;
|
||||
};
|
||||
|
||||
/**
|
||||
* get "nearBy" systemData based on a jump radius around a currentSystem
|
||||
* @param currentSystemData
|
||||
* @param currentMapData
|
||||
* @param jumps
|
||||
* @param foundSystemIds
|
||||
* @returns {{systemData: *, tree: {}}}
|
||||
*/
|
||||
let getNearBySystemData = (currentSystemData, currentMapData, jumps, foundSystemIds = {}) => {
|
||||
|
||||
// look for systemData by ID
|
||||
let getSystemData = (systemId) => {
|
||||
for(let j = 0; j < currentMapData.data.systems.length; j++){
|
||||
let systemData = currentMapData.data.systems[j];
|
||||
if(systemData.id === systemId){
|
||||
return systemData;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// skip systems that are already found in recursive calls
|
||||
foundSystemIds[currentSystemData.id] = {distance: jumps};
|
||||
|
||||
let nearBySystems = {
|
||||
systemData: currentSystemData,
|
||||
tree: {}
|
||||
};
|
||||
|
||||
jumps--;
|
||||
if(jumps >= 0){
|
||||
for(let i = 0; i < currentMapData.data.connections.length; i++){
|
||||
let connectionData = currentMapData.data.connections[i];
|
||||
let type = ''; // "source" OR "target"
|
||||
if(connectionData.source === currentSystemData.id){
|
||||
type = 'target';
|
||||
}else if(connectionData.target === currentSystemData.id){
|
||||
type = 'source';
|
||||
}
|
||||
|
||||
if(
|
||||
type &&
|
||||
(
|
||||
foundSystemIds[connectionData[type]] === undefined ||
|
||||
foundSystemIds[connectionData[type]].distance < jumps
|
||||
)
|
||||
){
|
||||
let newSystemData = getSystemData(connectionData[type]);
|
||||
if(newSystemData){
|
||||
nearBySystems.tree[connectionData[type]] = getNearBySystemData(newSystemData, currentMapData, jumps, foundSystemIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nearBySystems;
|
||||
};
|
||||
|
||||
/**
|
||||
* get current character data from all characters who are "nearby" the current user
|
||||
* -> see getNearBySystemData()
|
||||
* @param nearBySystems
|
||||
* @param userData
|
||||
* @param jumps
|
||||
* @param data
|
||||
* @returns {{}}
|
||||
*/
|
||||
let getNearByCharacterData = (nearBySystems, userData, jumps = 0, data = {}) => {
|
||||
|
||||
let getCharacterDataBySystemId = (systemId) => {
|
||||
for(let i = 0; i < userData.length; i++){
|
||||
if(userData[i].id === systemId){
|
||||
return userData[i].user;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
let filterFinalCharData = function(tmpFinalCharData){
|
||||
return this.id !== tmpFinalCharData.id;
|
||||
};
|
||||
|
||||
let characterData = getCharacterDataBySystemId(nearBySystems.systemData.systemId);
|
||||
|
||||
if(characterData.length){
|
||||
// filter (remove) characterData for "already" added chars
|
||||
characterData = characterData.filter(function(tmpCharacterData, index, allData){
|
||||
let keepData = true;
|
||||
|
||||
for(let tmpJump in data) {
|
||||
// just scan systems with > jumps than current system
|
||||
if(tmpJump > jumps){
|
||||
let filteredFinalData = data[tmpJump].filter(filterFinalCharData, tmpCharacterData);
|
||||
|
||||
if(filteredFinalData.length > 0){
|
||||
data[tmpJump] = filteredFinalData;
|
||||
}else{
|
||||
delete data[tmpJump];
|
||||
}
|
||||
}else{
|
||||
for(let k = 0; k < data[tmpJump].length; k++){
|
||||
if(data[tmpJump][k].id === tmpCharacterData.id){
|
||||
keepData = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return keepData;
|
||||
});
|
||||
|
||||
data[jumps] = data[jumps] ? data[jumps] : [];
|
||||
data[jumps] = [...data[jumps], ...characterData];
|
||||
}
|
||||
|
||||
jumps++;
|
||||
for(let prop in nearBySystems.tree) {
|
||||
if( nearBySystems.tree.hasOwnProperty(prop) ){
|
||||
let tmpSystemData = nearBySystems.tree[prop];
|
||||
data = getNearByCharacterData(tmpSystemData, userData, jumps, data);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
/**
|
||||
* set new destination for a system
|
||||
* -> CREST request
|
||||
@@ -3845,6 +4005,34 @@ define('app/util',[
|
||||
return $('.' + config.dialogClass).filter(':visible');
|
||||
};
|
||||
|
||||
/**
|
||||
* send Ajax request that remote opens an ingame Window
|
||||
* @param targetId
|
||||
*/
|
||||
let openIngameWindow = (targetId) => {
|
||||
targetId = parseInt(targetId);
|
||||
|
||||
if(targetId > 0){
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.openIngameWindow,
|
||||
data: {
|
||||
targetId: targetId
|
||||
},
|
||||
dataType: 'json'
|
||||
}).done(function(data){
|
||||
if(data.error.length > 0){
|
||||
showNotify({title: 'Open window in client', text: 'Remote window open failed', type: 'error'});
|
||||
}else{
|
||||
showNotify({title: 'Open window in client', text: 'Check your EVE client', type: 'success'});
|
||||
}
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
let reason = status + ' ' + error;
|
||||
showNotify({title: jqXHR.status + ': openWindow', text: reason, type: 'error'});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* formats a price string into an ISK Price
|
||||
* @param price
|
||||
@@ -3982,6 +4170,7 @@ define('app/util',[
|
||||
setSyncStatus: setSyncStatus,
|
||||
getSyncType: getSyncType,
|
||||
isXHRAborted: isXHRAborted,
|
||||
getMapElementFromOverlay: getMapElementFromOverlay,
|
||||
getMapModule: getMapModule,
|
||||
getSystemEffectData: getSystemEffectData,
|
||||
getSystemEffectTable: getSystemEffectTable,
|
||||
@@ -4009,9 +4198,12 @@ define('app/util',[
|
||||
getCurrentUserInfo: getCurrentUserInfo,
|
||||
getCurrentCharacterLog: getCurrentCharacterLog,
|
||||
flattenXEditableSelectArray: flattenXEditableSelectArray,
|
||||
getNearBySystemData: getNearBySystemData,
|
||||
getNearByCharacterData: getNearByCharacterData,
|
||||
setDestination: setDestination,
|
||||
convertDateToString: convertDateToString,
|
||||
getOpenDialogs: getOpenDialogs,
|
||||
openIngameWindow: openIngameWindow,
|
||||
formatPrice: formatPrice,
|
||||
getLocalStorage: getLocalStorage,
|
||||
getDocumentPath: getDocumentPath,
|
||||
File diff suppressed because one or more lines are too long
@@ -61,13 +61,13 @@ app/util.js
|
||||
lib/mustache.min.js
|
||||
app/render.js
|
||||
app/logging.js
|
||||
app/map/util.js
|
||||
lib/requirejs/text.js
|
||||
text!img/logo.svg!strip
|
||||
text!templates/modules/header.html
|
||||
text!templates/modules/footer.html
|
||||
app/ui/dialog/notification.js
|
||||
app/ui/dialog/stats.js
|
||||
app/map/util.js
|
||||
app/ui/dialog/map_info.js
|
||||
app/ui/dialog/account_settings.js
|
||||
app/ui/dialog/manual.js
|
||||
@@ -90,6 +90,7 @@ lib/jquery.dragToSelect.js
|
||||
lib/select2.min.js
|
||||
app/map/contextmenu.js
|
||||
app/map/overlay.js
|
||||
app/map/local.js
|
||||
app/map/map.js
|
||||
app/counter.js
|
||||
app/ui/system_info.js
|
||||
@@ -1,12 +1,12 @@
|
||||
<nav class="navbar navbar-default" role="navigation">
|
||||
<div class="navbar-header pull-left">
|
||||
<ul class="nav navbar-nav {{dialogNavigationClass}}" role="tablist">
|
||||
<li class="active">
|
||||
<li class="{{#openTabInformation}}active{{/openTabInformation}}">
|
||||
<a role="tab" data-toggle="tab" data-name="infoSummary" href="#{{dialogSummaryContainerId}}">
|
||||
<i class="fa fa-street-view fa-fw"></i> Information
|
||||
</a>
|
||||
</li>
|
||||
<li class="">
|
||||
<li class="{{#openTabActivity}}active{{/openTabActivity}}">
|
||||
<a role="tab" data-toggle="tab" data-name="infoUsers" href="#{{dialogUsersContainerId}}">
|
||||
<i class="fa fa-fighter-jet fa-fw"></i> Activity
|
||||
</a>
|
||||
@@ -28,7 +28,7 @@
|
||||
<div class="tab-content">
|
||||
|
||||
{{! "summary" tab ------------------------------------------------------ }}
|
||||
<div role="tabpanel" class="tab-pane fade in active" id="{{dialogSummaryContainerId}}">
|
||||
<div role="tabpanel" class="tab-pane fade {{#openTabInformation}}in active{{/openTabInformation}}" id="{{dialogSummaryContainerId}}">
|
||||
<div class="alert alert-info fade in hidden-md hidden-lg">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><i class="fa fa-close"></i></button>
|
||||
<span class="txt-color txt-color-information">Info</span>
|
||||
@@ -52,7 +52,7 @@
|
||||
</div>
|
||||
|
||||
{{! "users" tab -------------------------------------------------------- }}
|
||||
<div role="tabpanel" class="tab-pane fade" id="{{dialogUsersContainerId}}">
|
||||
<div role="tabpanel" class="tab-pane fade {{#openTabActivity}}in active{{/openTabActivity}}" id="{{dialogUsersContainerId}}">
|
||||
<h4><i class="fa fa-male fa-lg fa-fw"></i> Active pilots</h4>
|
||||
|
||||
<div id="{{mapInfoUsersId}}" class="pf-dynamic-area">
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
<option value="{{id}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/mapSelectOptions}}
|
||||
</select>
|
||||
<span class="help-block with-errors">Set maps from search</span>
|
||||
<span class="help-block with-errors">Set maps for search</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -105,7 +105,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4 col-sm-offset-8">
|
||||
<div class="col-sm-4 col-sm-offset-4">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-11">
|
||||
<div class="col-sm-12 col-xs-6 checkbox checkbox checkbox-circle" title="include frigate connections">
|
||||
<input id="form_wormholes_frigate" name="wormholesFrigate" value="1" type="checkbox" checked>
|
||||
<label for="form_wormholes_frigate">Frigate</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<div class="form-group">
|
||||
<div class="col-sm-offset-1 col-sm-11">
|
||||
<div class="col-sm-12 col-xs-6 checkbox checkbox-danger checkbox-circle" title="include EOL connections">
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<div class="pf-dynamic-area pf-system-info-description-area">
|
||||
<i class="fa fa-fw fa-lg fa-pencil pull-right pf-module-icon-button {{descriptionButtonClass}}" data-toggle="tooltip" data-container="body" title="edit description"></i>
|
||||
|
||||
<div id="{{moduleToolbarActionId}}" class="pf-table-tools-action">
|
||||
<div class="{{tableToolsActionClass}}">
|
||||
<a href="#" class="{{descriptionTextareaClass}}"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<div class="panel-body no-padding text-align-center">
|
||||
<div class="price-features" style="min-height: inherit;">
|
||||
<ul class="list-unstyled text-left">
|
||||
<li><i class="fa fa-fw fa-angle-right"></i>NEW signature overlays (signatures can be bind to connections) <a target="_blank" href="https://www.youtube.com/watch?v=5kp3CBx6998">Youtube</a></li>
|
||||
<li><i class="fa fa-fw fa-angle-right"></i>NEW wormhole overlays ("updated"/"created" information)</li>
|
||||
<li><i class="fa fa-fw fa-angle-right"></i>NEW keyboard shortcuts (beta)</li>
|
||||
<li><i class="fa fa-fw fa-angle-right"></i>Added ~80 missing static WHs for "Shattered wormholes"</li>
|
||||
<li><i class="fa fa-fw fa-angle-right"></i>New "<em><a target="_blank" href="https://github.com/exodus4d/pathfinder/issues/481#issue-223584078">Nearby</a></em>" map overlay shows active pilots within 3 jumps around your current location</li>
|
||||
<li><i class="fa fa-fw fa-angle-right"></i>Switch to <em>CCPs</em> new <a target="_blank" href="https://community.eveonline.com/news/dev-blogs/introducing-esi/">ESI API</a>. Replaces CREST API.</li>
|
||||
<li><i class="fa fa-fw fa-angle-right"></i>New UI options added. E.g. Remote open inGame information windows</li>
|
||||
<li><i class="fa fa-fw fa-angle-right"></i>Added new filter option for "<em>Frigat wormholes</em>" to route finder</li>
|
||||
<li><i class="fa fa-fw fa-angle-double-right"></i>Complete <a href="javascript:void(0)" class="pf-navbar-version-info">changelog</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -4,8 +4,14 @@
|
||||
{{#serviceStatus}}
|
||||
<li><i class="fa-li fa fa-server " aria-hidden="true"></i><span class="txt-color {{ style }}">{{ eve }}</span></li>
|
||||
{{/serviceStatus}}
|
||||
{{#userCounts}}
|
||||
<li><i class="fa-li fa fa-users" aria-hidden="true"></i>{{ userCounts }}</li>
|
||||
{{/userCounts}}
|
||||
{{#playerCount}}
|
||||
<li><i class="fa-li fa fa-users" aria-hidden="true"></i>{{ playerCount }}</li>
|
||||
{{/playerCount}}
|
||||
{{#startTime}}
|
||||
<li><i class="fa-li fa fa-clock-o" aria-hidden="true"></i>up {{ startTime }}</li>
|
||||
{{/startTime}}
|
||||
{{#serverVersion}}
|
||||
<li><i class="fa-li fa fa-certificate" aria-hidden="true"></i>v. {{ serverVersion }}</li>
|
||||
{{/serverVersion}}
|
||||
</ul>
|
||||
</div>
|
||||
@@ -53,7 +53,25 @@
|
||||
{* Youtube verification code *}
|
||||
<meta name="google-site-verification" content="sHoh0gfMw3x1wiwLTK5OsKsxt7kRgxi69hRgWEGh9DQ" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="{{ @BASE }}/public/css/pathfinder.css?{{ @PATHFINDER.VERSION }}">
|
||||
{* Resources *}
|
||||
<set pathCSS="{{ @BASE . '/public/css/pathfinder.css?' . @PATHFINDER.VERSION }}" />
|
||||
<set pathJSApp="{{ @BASE . '/' . @pathJs . '/app' }}" />
|
||||
<set pathJSRequire="{{ @BASE . '/' . @pathJs . '/lib/require.js' }}" />
|
||||
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="{{@pathCSS}}">
|
||||
|
||||
{* Prefetch / Preload *}
|
||||
<link rel="preload" href="{{@pathCSS}}" as="style">
|
||||
<link rel="preload" href="{{@pathJSRequire}}" as="script">
|
||||
<link rel="preload" href="{{@pathJSApp}}.js" as="script">
|
||||
<link rel="preload" href="{{@pathJSApp}}/{{@jsView}}.js" as="script">
|
||||
<link rel="dns-prefetch" href="https://login.eveonline.com">
|
||||
<link rel="dns-prefetch" href="https://image.eveonline.com">
|
||||
<link rel="dns-prefetch" href="https://i.ytimg.com">
|
||||
|
||||
<check if="{{ @jsView != 'mappage' }}">
|
||||
<link rel="prefetch" href="{{@pathJSApp}}/mappage.js" as="script">
|
||||
</check>
|
||||
|
||||
</head>
|
||||
<body class="{{ @bodyClass }}" data-js-path="{{ @BASE }}/{{ @pathJs }}" data-script="{{ @jsView }}" data-version="{{ @PATHFINDER.VERSION }}">
|
||||
@@ -61,7 +79,7 @@
|
||||
|
||||
<!-- Hey dude! Where is all the magic? -->
|
||||
|
||||
<script data-main="{{ @BASE }}/{{ @pathJs }}/app" src="{{ @BASE }}/{{ @pathJs }}/lib/require.js" ></script>
|
||||
<script data-main="{{@pathJSApp}}" src="{{@pathJSRequire}}" ></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -905,7 +905,8 @@
|
||||
Pathfinder requires cookies to maintain your login state between browser sessions. Read <a target="_blank" href="https://github.com/exodus4d/pathfinder/issues/138">more</a>.
|
||||
</p>
|
||||
<div class="pull-right">
|
||||
<button type="button" class="btn btn-default navbar-btn btn-success" data-toggle="collapse" data-target="#pf-cookie-hint" aria-expanded="false">That´s fine</button>
|
||||
<button type="button" class="btn btn-default navbar-btn btn-success" data-toggle="collapse" data-target="#pf-cookie-hint" aria-expanded="false">
|
||||
<i class="fa fa-fw fa-check"></i> accept cookies</button>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -987,6 +987,27 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6 pf-landing-pricing-panel">
|
||||
{* Cookie *}
|
||||
<div class="panel panel-default pricing-big">
|
||||
<div class="panel-heading text-left">
|
||||
<h3 class="panel-title">Cookies
|
||||
<i class="fa fa-fw fa-question-circle pf-help-light" title="Force all users to re-login through SSO. "></i>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="panel-body no-padding">
|
||||
<div class="btn-group btn-group-justified">
|
||||
<span class="btn btn-default disabled btn-fake">Invalidate all Cookie data</span>
|
||||
<a href="?invalidateCookies=1#pf-setup-administration" class="btn btn-warning" role="button">
|
||||
<i class="fa fa-fw fa-times"></i> Clear authentication data
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -867,30 +867,23 @@ input[type="email"]{
|
||||
overflow: hidden;
|
||||
height: 18px;
|
||||
background: $gray-lighter;
|
||||
box-shadow: 0 1px 0 transparent, 0 0 0 1px lighten( $gray-light, 29%) inset;
|
||||
-webkit-box-shadow: 0 1px 0 transparent, 0 0 0 1px lighten( $gray-light, 29%) inset;
|
||||
-moz-box-shadow: 0 1px 0 transparent, 0 0 0 1px lighten( $gray-light, 29%) inset;
|
||||
|
||||
border-radius:$progressbar-radius;
|
||||
-moz-border-radius:$progressbar-radius;
|
||||
-webkit-border-radius:$progressbar-radius;
|
||||
@include box-shadow( 0 1px 0 transparent, 0 0 0 1px lighten( $gray-light, 29%) inset);
|
||||
@include border-radius($progressbar-radius);
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
float: left;
|
||||
width: 0;
|
||||
height: 100%;
|
||||
font-size: 11px;
|
||||
color: $white;
|
||||
text-align: center;
|
||||
background-color: $blue;
|
||||
-webkit-box-shadow: inset 0 -1px 0 rgba(red($black), green($black), blue($black), 0.15);
|
||||
box-shadow: inset 0 -1px 0 rgba(red($black), green($black), blue($black), 0.15);
|
||||
font-weight:bold;
|
||||
text-shadow: 0 -1px 0 rgba(red($black), green($black), blue($black), 0.25);
|
||||
//background-image:url("#{$base-url}/overlay-pattern.png");
|
||||
-webkit-transition: width 1.5s ease-in-out;
|
||||
transition: width 1.5s ease-in-out;
|
||||
float: left;
|
||||
width: 0;
|
||||
height: 100%;
|
||||
font-size: 11px;
|
||||
color: $white;
|
||||
text-align: center;
|
||||
background-color: $blue;
|
||||
font-weight: bold;
|
||||
text-shadow: 0 -1px 0 rgba(red($black), green($black), blue($black), 0.25);
|
||||
//background-image:url("#{$base-url}/overlay-pattern.png");
|
||||
@include box-shadow( inset 0 -1px 0 rgba(red($black), green($black), blue($black), 0.15));
|
||||
@include transition(width 1s ease-in-out) ;
|
||||
}
|
||||
|
||||
.progress-striped .progress-bar {
|
||||
|
||||
@@ -552,7 +552,7 @@ $modal-header-border-color: #e5e5e5;
|
||||
$modal-footer-border-color: $modal-header-border-color;
|
||||
|
||||
$modal-lg: 1100px;
|
||||
$modal-md: 600px;
|
||||
$modal-md: 700px;
|
||||
$modal-sm: 300px;
|
||||
|
||||
|
||||
|
||||
@@ -216,6 +216,19 @@ select:active, select:hover {
|
||||
td{
|
||||
&.pf-table-action-cell{
|
||||
cursor: pointer;
|
||||
|
||||
// icon within <td> cell content that should be highlighted on hover
|
||||
> .pf-table-action-icon-cell{
|
||||
@extend .txt-color;
|
||||
@extend .txt-color-gray;
|
||||
@include transition( color 0.08s ease-out );
|
||||
}
|
||||
|
||||
&:hover{
|
||||
> .pf-table-action-icon-cell{
|
||||
@extend .txt-color-orange;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.pf-table-image-cell{
|
||||
|
||||
@@ -69,23 +69,24 @@ $mapWidth: 2500px ;
|
||||
position: absolute;
|
||||
display: none; // triggered by js
|
||||
z-index: 10000;
|
||||
height: 36px;
|
||||
right: 10px;
|
||||
background: rgba($black, 0.25);
|
||||
@include border-radius(5px);
|
||||
|
||||
&.pf-map-overlay-timer{
|
||||
width: 36px;
|
||||
bottom: 23px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
&.pf-map-overlay-info{
|
||||
top: 8px;
|
||||
height: 36px;
|
||||
min-height: 36px;
|
||||
min-width: 36px;
|
||||
color: $gray-darker;
|
||||
padding: 3px;
|
||||
line-height: 26px;
|
||||
min-height: 36px;
|
||||
min-width: 36px;
|
||||
|
||||
i{
|
||||
margin: 0; // overwrite default
|
||||
@@ -115,6 +116,93 @@ $mapWidth: 2500px ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.pf-map-overlay-local{
|
||||
top: 54px;
|
||||
min-height: 80px;
|
||||
width: 32px;
|
||||
display: block;
|
||||
will-change: width;
|
||||
|
||||
.pf-map-overlay-local-content {
|
||||
margin-right: 36px;
|
||||
padding: 5px 0 5px 5px;
|
||||
overflow: hidden;
|
||||
|
||||
.pf-map-overlay-headline{
|
||||
font-size: 12px;
|
||||
font-family: $font-family-bold;
|
||||
white-space: nowrap;
|
||||
|
||||
.badge{
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.pf-system-sec{
|
||||
cursor: default; // overwrite
|
||||
}
|
||||
}
|
||||
|
||||
.pf-local-table {
|
||||
font-size: 10px;
|
||||
|
||||
td {
|
||||
white-space: nowrap;
|
||||
|
||||
.pf-table-cell-ellipsis{
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.pf-table-cell-80{
|
||||
width: 90px; // 100 + padding for "order" icons
|
||||
}
|
||||
|
||||
.pf-table-cell-90{
|
||||
width: 100px; // 100 + padding for "order" icons
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dataTables_paginate,
|
||||
.dataTables_empty{
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.pf-map-overlay-local-main{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
padding: 3px;
|
||||
width: 32px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
border-left: 1px solid $gray-darker;
|
||||
|
||||
.pf-map-overlay-local-trigger{
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
i{
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.pf-map-overlay-local-jumps{
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
width: calc(100% - 6px);
|
||||
}
|
||||
|
||||
.badge{
|
||||
font-family: Arial, sans-serif; // fix for element width on custom font family
|
||||
background-color: $gray-darker;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 20x20px grid background
|
||||
|
||||
@@ -117,7 +117,7 @@ table.dataTable.order-column tbody tr > .sorting_2,
|
||||
table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,
|
||||
table.dataTable.display tbody tr > .sorting_2,
|
||||
table.dataTable.display tbody tr > .sorting_3 {
|
||||
background-color: #fafafa;
|
||||
background-color: $gray-darker;
|
||||
}
|
||||
table.dataTable.order-column tbody tr.selected > .sorting_1,
|
||||
table.dataTable.order-column tbody tr.selected > .sorting_2,
|
||||
@@ -186,9 +186,13 @@ table.dataTable.no-footer {
|
||||
table.dataTable.nowrap th, table.dataTable.nowrap td {
|
||||
white-space: nowrap;
|
||||
}
|
||||
table.dataTable.compact thead th:not(.sorting_disabled),
|
||||
table.dataTable.compact thead td:not(.sorting_disabled) {
|
||||
padding: 4px 17px 4px 4px;
|
||||
}
|
||||
table.dataTable.compact thead th,
|
||||
table.dataTable.compact thead td {
|
||||
padding: 4px 17px 4px 4px;
|
||||
padding: 4px 4px 4px 4px;
|
||||
}
|
||||
table.dataTable.compact tfoot th,
|
||||
table.dataTable.compact tfoot td {
|
||||
|
||||
Reference in New Issue
Block a user