userData implementation

This commit is contained in:
exodus4d
2015-04-11 18:46:54 +02:00
parent 3b27517daa
commit 1be444cc32
54 changed files with 2628 additions and 1025 deletions

View File

@@ -26,7 +26,7 @@ class AccessController extends Controller {
$accessRoute = true;
}else{
$userName = 'user_exodus';
$password = 'password';
$password = '1234567';
// try to verify user
$accessRoute = $this->_verifyUser($userName, $password);
@@ -65,7 +65,7 @@ class AccessController extends Controller {
$user = Model\BasicModel::getNew('UserModel');
$user->name = $username;
$user->password = $user::generatePasswordHash($password);
$user->password = $password;
$user->save();
return $user;
@@ -151,7 +151,7 @@ class AccessController extends Controller {
$this->f3->set('SESSION.user.id', $user->id);
// update/check api data
$this->_updateCharacterData();
// $this->_updateCharacterData();
}
/**
@@ -170,24 +170,4 @@ class AccessController extends Controller {
return $user;
}
/**
* updates character data for all characters the current user has
* API access
* @return bool
*/
protected function _updateCharacterData(){
$user = $this->_getUser();
$characters = false;
if($user){
$apiController = new CcpApiController();
$apiController->addUser($user);
$characters = $apiController->updateCharacterData();
}
return $characters;
}
}

View File

@@ -16,13 +16,6 @@ use Model;
*/
class CcpApiController extends Controller{
/**
* array with all user models
* that will be taken into account by this controller
* @var
*/
protected $users = [];
/**
* get a custom userAgent string for API calls
* (recommended by CCP)
@@ -54,44 +47,16 @@ class CcpApiController extends Controller{
}
/**
* get API models for this controller
* request Character data for given api models
* @param $apiModels
* @return array
*/
protected function _getApiModels(){
$apiModels = [];
foreach($this->users as $user){
$tempApiModels = $user->getAPIs();
foreach($tempApiModels as $apiModel){
array_push($apiModels, $apiModel);
}
}
return $apiModels;
}
/**
* add a user model for this controller
* @param $user
*/
public function addUser($user){
if($user){
array_push($this->users, $user);
}
}
/**
* update all character data for this controller
*/
public function updateCharacterData(){
public function getCharacters($apiModels){
$apiPath = $this->f3->get('api_path.CCP_XML') . '/account/APIKeyInfo.xml.aspx';
$characterModel = Model\BasicModel::getNew('UserCharacterModel');
$apiModels = $this->_getApiModels();
$characters = [];
foreach($apiModels as $apiModel){
// build request URL
$options = $this->getRequestOptions();
$options['content'] = http_build_query( [
@@ -104,53 +69,49 @@ class CcpApiController extends Controller{
if($apiResponse['body']){
$xml = simplexml_load_string($apiResponse['body']);
$rowApiData = $xml->result->key->rowset;
// request successful --------------------------------------------
// deactivate all chars in case one of them is removed from this API
$currentCharacterModels = $apiModel->getCharacters();
foreach($currentCharacterModels as $currentCharacterModel){
$currentCharacterModel->setActive(false);
$currentCharacterModel->save();
};
if($rowApiData->children()){
$characterModel = Model\BasicModel::getNew('CharacterModel');
foreach($rowApiData->children() as $characterApiData){
// map attributes to array
$attributeData = current( $characterApiData->attributes() );
// check if record exist -> search
// load active = 0 records as well! (they have been de-activated before)
$characterModel->load(array(
'userId = :userId AND characterId = :characterId',
':userId' => $apiModel->userId->id,
':characterId' => $attributeData['characterID']
));
// search for existing user character model
$userCharacterModel = $apiModel->getUserCharacterById($attributeData['characterID']);
if(is_null($userCharacterModel)){
$userCharacterModel = Model\BasicModel::getNew('UserCharacterModel');
}
$characterModel = $characterModel->getByForeignKey( 'characterId', $attributeData['characterID']);
$characterModel->setActive(true);
$characterModel->userId = $apiModel->userId;
$characterModel->apiId = $apiModel;
$characterModel->characterId = $attributeData['characterID'];
$characterModel->characterName = $attributeData['characterName'];
$characterModel->name = $attributeData['characterName'];
$characterModel->corporationId = $attributeData['corporationID'];
$characterModel->corporationName = $attributeData['corporationName'];
$characterModel->allianceId = $attributeData['allianceID'];
$characterModel->allianceName = $attributeData['allianceName'];
$characterModel->factionId = $attributeData['factionID'];
$characterModel->factionName = $attributeData['factionName'];
// save/update character
$characterModel->save();
// store "temp" character obj until obj is saved for the first time
$userCharacterModel->characterId = $characterModel;
$characters[] = $userCharacterModel;
$characterModel->reset();
}
}
}else{
print_r( 'ERROR FUFU');
var_dump($apiResponse);
}
}
return $characters;
}
}

View File

@@ -41,7 +41,7 @@ class Map extends \Controller\AccessController {
$initData = [];
// get all available map types -------------------------------------
// get all available map types ----------------------------------------
$mapType = Model\BasicModel::getNew('MapTypeModel');
$rows = $mapType->find('active = 1', null, $expireTimeSQL);
@@ -58,7 +58,7 @@ class Map extends \Controller\AccessController {
}
$initData['mapTypes'] = $mapTypeData;
// get all available map scopes ------------------------------------
// get all available map scopes ---------------------------------------
$mapScope = Model\BasicModel::getNew('MapScopeModel');
$rows = $mapScope->find('active = 1', null, $expireTimeSQL);
$mapScopeData = [];
@@ -98,7 +98,7 @@ class Map extends \Controller\AccessController {
}
$initData['systemType'] = $systemTypeData;
// get available connection scopes ---------------------------------
// get available connection scopes ------------------------------------
$connectionScope = Model\BasicModel::getNew('ConnectionScopeModel');
$rows = $connectionScope->find('active = 1', null, $expireTimeSQL);
$connectionScopeData = [];
@@ -111,6 +111,20 @@ class Map extends \Controller\AccessController {
}
$initData['connectionScopes'] = $connectionScopeData;
// get available character status -------------------------------------
$characterStatus = Model\BasicModel::getNew('CharacterStatusModel');
$rows = $characterStatus->find('active = 1', null, $expireTimeSQL);
$characterStatusData = [];
foreach((array)$rows as $rowData){
$data = [
'id' => $rowData->id,
'name' => $rowData->name,
'class' => $rowData->class
];
$characterStatusData[$rowData->name] = $data;
}
$initData['characterStatus'] = $characterStatusData;
echo json_encode($initData);
}
@@ -287,10 +301,11 @@ class Map extends \Controller\AccessController {
if($f3->exists($cacheKey) === false){
$userData = (object) [];
$userData->currentUserData = $user->getData();
$userData->userData = $user->getData();
// get user Data for each map ========================================
$activeMaps = $user->getMaps();
foreach($activeMaps as $mapModel){
$userData->mapUserData[] = $mapModel->getUserData();
}

View File

@@ -63,38 +63,43 @@ class Signature extends \Controller\AccessController{
$signatureData = $f3->get('POST');
$user = $this->_getUser();
$system = Model\BasicModel::getNew('SystemModel');
$system->getById($signatureData['systemId']);
$newSignatureData = false;
if(!$system->dry()){
// update/save signature
$signature = $system->getSignatureById($user, $signatureData['pk']);
if($user){
$system = Model\BasicModel::getNew('SystemModel');
$system->getById($signatureData['systemId']);
if($signature){
if($signature->dry()){
// new signature
$signature->systemId = $system;
$signature->createdUserId = $user;
$signature->setData($signatureData);
}else{
// update signature (single data)
$newData = [
$signatureData['name'] => $signatureData['value']
];
$signature->setData($newData);
$activeCharacter = $user->getActiveCharacter();
if(!$system->dry()){
// update/save signature
$signature = $system->getSignatureById($user, $signatureData['pk']);
if($signature){
if($signature->dry()){
// new signature
$signature->systemId = $system;
$signature->createdCharacterId = $activeCharacter->characterId;
$signature->setData($signatureData);
}else{
// update signature (single data)
$newData = [
$signatureData['name'] => $signatureData['value']
];
$signature->setData($newData);
}
$signature->updatedCharacterId = $activeCharacter->characterId;
$signature->save();
$newSignatureData = $signature->getData();
}
}
$signature->updatedUserId = $user;
$signature->save();
$newSignatureData = $signature->getData();
if(!$newSignatureData){
$this->f3->error(401, 'Signature could not be saved.');
}
}
if(!$newSignatureData){
$this->f3->error(401, 'Signature could not be saved.');
}
echo json_encode($newSignatureData);
}

View File

@@ -7,22 +7,143 @@
*/
namespace Controller\Api;
use Model;
class User extends \Controller\AccessController{
public function saveConfig($f3){
$data = $f3->get('POST');
if($data['configData']){
$configData = $data['configData'];
$return = new \stdClass();
if($data['settingsData']){
$settingsData = $data['settingsData'];
$user = $this->_getUser();
if($user){
$user->setMainCharacterId((int)$configData['mainCharacterId']);
// change/set email
if(
array_key_exists('email', $settingsData) &&
array_key_exists('email_confirm', $settingsData) &&
!empty($settingsData['email']) &&
!empty($settingsData['email_confirm']) &&
$settingsData['email'] == $settingsData['email_confirm']
){
$user->email = $settingsData['email'];
}
// change/set password
if(
array_key_exists('password', $settingsData) &&
array_key_exists('password_confirm', $settingsData) &&
!empty($settingsData['password']) &&
!empty($settingsData['password_confirm']) &&
$settingsData['password'] == $settingsData['password_confirm']
){
$user->password = $settingsData['password'];
}
// save API data
if(
array_key_exists('keyId', $settingsData) &&
array_key_exists('vCode', $settingsData) &&
is_array($settingsData['keyId']) &&
is_array($settingsData['vCode'])
){
// get all existing API models for this user
$apiModels = $user->getAPIs();
foreach($settingsData['keyId'] as $i => $keyId){
$api = null;
$userCharacters = [];
// search for existing API model
foreach($apiModels as $key => $apiModel){
if($apiModel->keyId == $keyId){
$api = $apiModel;
// get existing characters in case api model already exists
$userCharacters = $api->getUserCharacters();
unset($apiModels[$key]);
break;
}
}
if(is_null($api)){
// new API Key
$api = Model\BasicModel::getNew('UserApiModel');
}
$api->userId = $user;
$api->keyId = $keyId;
$api->vCode = $settingsData['vCode'][$i];
// check each API Model if valid
$newUserCharacters = $api->requestCharacters();
if(empty($newUserCharacters)){
// no characters found
$return->error = [];
$characterError = new \stdClass();
$characterError->type = 'api';
$characterError->keyId = $api->keyId;
$characterError->vCode = $api->vCode;
$characterError->message = 'No characters found';
$return->error[] = $characterError;
}else{
$api->save();
// find existing character
foreach($newUserCharacters as $newUserCharacter){
$matchedUserCharacter = $newUserCharacter;
foreach($userCharacters as $key => $userCharacter){
if($userCharacter->characterId == $newUserCharacter->characterId){
$matchedUserCharacter = $userCharacter;
unset($userCharacters[$key]);
break;
}
}
$matchedUserCharacter->apiId = $api;
$matchedUserCharacter->userId = $user;
$matchedUserCharacter->save();
}
}
// delete characters that are no longer in this API
foreach($userCharacters as $userCharacter){
print_r('delete Character: ' . $userCharacter->id);
}
}
// delete API models that no longer exists
foreach($apiModels as $apiModel){
$apiModel->delete();
}
}
// set main character
if(
array_key_exists('mainCharacterId', $settingsData)
){
$user->setMainCharacterId((int)$settingsData['mainCharacterId']);
}
// save user model
$user->save();
// return new/updated user data
$return->userData = $user->getData();
}
}
echo json_encode([]);
echo json_encode($return);
}
}

View File

@@ -47,12 +47,13 @@ class BasicModel extends \DB\Cortex{
$valid = $this->_validateField($col, $val);
if(!$valid){
throw new Exception\ValidationException('Field validation: "' . $this->table . '->' . $col . '" not valid', Exception\BaseException::VALIDATION_FAILED);
$this->_throwValidationError($col);
}else{
parent::__set($col, $val);
}
}
/**
* validates a table column based on validation settings
* @param $col
@@ -108,6 +109,16 @@ class BasicModel extends \DB\Cortex{
return $valid;
}
/**
* Throws a validation error for a giben column
* @param $col
* @throws \Exception\ValidationException
*/
protected function _throwValidationError($col){
throw new Exception\ValidationException('Field validation: "' . $this->table . '->' . $col . '" not valid', Exception\BaseException::VALIDATION_FAILED);
}
/**
* get single dataSet by id
* @param $id

View File

@@ -0,0 +1,53 @@
<?php
/**
* Created by PhpStorm.
* User: exodus4d
* Date: 11.04.15
* Time: 15:20
*/
namespace Model;
class CharacterModel extends BasicModel {
protected $table = 'character';
protected $ttl = 0;
protected $rel_ttl = 0;
protected $fieldConf = array(
/* wirft fehler
'characterId' => array(
'has-one' => array('Model\CharacterLogModel', 'characterId')
)
*/
);
/**
* get character data
* @return object
*/
public function getData(){
$characterData = (object) [];
$characterData->characterId = $this->characterId;
$characterData->name = $this->name;
// check for corporation
if($this->corporationId){
$characterData->corporation = (object) [];
$characterData->corporation->id = $this->corporationId;
$characterData->corporation->name = $this->corporationName;
}
// check for alliance
if($this->allianceId){
$characterData->alliance = (object) [];
$characterData->alliance->id = $this->allianceId;
$characterData->alliance->name = $this->allianceName;
}
return $characterData;
}
}

View File

@@ -0,0 +1,15 @@
<?php
/**
* Created by PhpStorm.
* User: exodus4d
* Date: 01.04.15
* Time: 21:12
*/
namespace Model;
class CharacterStatusModel extends BasicModel {
protected $table = 'character_status';
}

View File

@@ -288,13 +288,13 @@ class MapModel extends BasicModel{
// get users with map access
$users = $this->getUsers();
$characterLogsData = [];
$activeUserCharactersData = [];
foreach($users as $user){
// get all active character logs for a user
$activeCharacters = $user->getActiveCharacters();
$tempActiveUserCharacters = $user->getActiveUserCharacters();
foreach($activeCharacters as $activeCharacter){
$characterLogsData[] = $activeCharacter->getData(true);
foreach($tempActiveUserCharacters as $tempActiveUserCharacter){
$activeUserCharactersData[] = $tempActiveUserCharacter->getData(true);
}
}
@@ -304,19 +304,21 @@ class MapModel extends BasicModel{
$mapUserData->data = (object) [];
$mapUserData->data->systems = [];
foreach($systems as $system){
$systemUserData = (object) [];
$systemUserData->id = $system->id;
$systemUserData->user = [];
// check if a system has active characters
foreach($characterLogsData as $characterLogData){
if($characterLogData->log->system->Id == $system->systemId){
$systemUserData->user[] = $characterLogData;
foreach($activeUserCharactersData as $key => $activeUserCharacterData){
if($activeUserCharacterData->log->system->Id == $system->systemId){
$systemUserData->user[] = $activeUserCharacterData;
// remove user from array -> speed up looping over characters.
// each userCharacter can only be active in a SINGLE system
unset($activeUserCharactersData[$key]);
}
}
// add system if active users were found
if(count($systemUserData->user) > 0){
$mapUserData->data->systems[] = $systemUserData;
@@ -324,7 +326,6 @@ class MapModel extends BasicModel{
}
return $mapUserData;
}

View File

@@ -19,11 +19,11 @@ class SystemSignatureModel extends BasicModel {
'systemId' => array(
'belongs-to-one' => 'Model\SystemModel'
),
'createdUserId' => array(
'belongs-to-one' => 'Model\UserModel'
'createdCharacterId' => array(
'belongs-to-one' => 'Model\CharacterModel'
),
'updatedUserId' => array(
'belongs-to-one' => 'Model\UserModel'
'updatedCharacterId' => array(
'belongs-to-one' => 'Model\CharacterModel'
)
);
@@ -63,11 +63,11 @@ class SystemSignatureModel extends BasicModel {
'typeId' => $this->typeId,
'name' => $this->name,
'created' => [
'userName' => is_object($this->createdUserId) ? $this->createdUserId->name : '',
'character' => $this->createdCharacterId->getData(),
'created' => strtotime($this->created)
],
'updated' => [
'userName' => is_object($this->updatedUserId) ? $this->updatedUserId->name : '',
'character' => $this->updatedCharacterId->getData(),
'updated' => strtotime($this->updated)
]

View File

@@ -7,7 +7,7 @@
*/
namespace Model;
use Controller;
class UserApiModel extends BasicModel {
@@ -19,24 +19,102 @@ class UserApiModel extends BasicModel {
'userId' => array(
'belongs-to-one' => 'Model\UserModel'
),
'characters' => array(
'userCharacters' => array(
'has-many' => array('Model\UserCharacterModel', 'apiId')
)
);
/**
* get all data for this api
* @return object
*/
public function getData(){
$apiData = (object) [];
$apiData->keyId = $this->keyId;
$apiData->vCode = $this->vCode;
return $apiData;
}
/**
* request CCP API and get all characters for this API
* @return array
*/
public function requestCharacters(){
$apiController = new Controller\CcpApiController();
return $apiController->getCharacters([$this]);
}
/**
* get all characters for this API
* @return array|mixed
*/
public function getCharacters(){
$this->filter('characters', array('active = ?', 1));
public function getUserCharacters(){
$this->filter('userCharacters', array('active = ?', 1));
$characters = [];
if($this->characters){
$characters = $this->characters;
$userCharacters = [];
if($this->userCharacters){
$userCharacters = $this->userCharacters;
}
return $userCharacters;
}
/**
* search for a user character model by a characterId
* @param $characterId
* @return null
*/
public function getUserCharacterById($characterId){
$userCharacters = $this->getUserCharacters();
$returnUserCharacter = null;
foreach($userCharacters as $userCharacter){
if($userCharacter->characterId->characterId == $characterId){
$returnUserCharacter = $userCharacter;
break;
}
}
return $returnUserCharacter;
}
/**
* check if this api model has a main character
* @return bool
*/
public function hasMainCharacter(){
$hasMain = false;
$characters = $this->getCharacters();
foreach($characters as $character){
if($character->isMain()){
$hasMain = true;
break;
}
}
return $hasMain;
}
/**
* delete this api model
*/
public function delete(){
// check if this api model had a main character
$user = $this->userId;
$setNewMain = false;
if($this->hasMainCharacter()){
$setNewMain = true;
}
$this->erase();
if($setNewMain){
$user->setMainCharacterId();
}
return $characters;
}
}

View File

@@ -15,6 +15,8 @@ class UserCharacterModel extends BasicModel {
protected $ttl = 0;
protected $rel_ttl = 0;
private $character = null;
protected $fieldConf = array(
'userId' => array(
'belongs-to-one' => 'Model\UserModel'
@@ -22,9 +24,16 @@ class UserCharacterModel extends BasicModel {
'apiId' => array(
'belongs-to-one' => 'Model\UserApiModel'
),
'characterId' => array(
'belongs-to-one' => 'Model\CharacterModel'
)
/*
,
'log' => array(
'has-one' => array('Model\CharacterLogModel', 'userCharacterId')
)
) */
);
/**
@@ -50,23 +59,27 @@ class UserCharacterModel extends BasicModel {
*/
public function getData($addCharacterLogData = false){
// get characterModel
$characterModel = $this->characterId;
$characterData = (object) [];
$characterData->characterId = $this->characterId;
$characterData->name = $this->characterName;
$characterData->characterId = $characterModel->characterId;
$characterData->name = $characterModel->name;
$characterData->isMain = $this->isMain;
// check for corporation
if($this->corporationId){
$characterData->coorporation = (object) [];
$characterData->coorporation->id = $this->corporationId;
$characterData->coorporation->name = $this->characterName;
if($characterModel->corporationId){
$characterData->corporation = (object) [];
$characterData->corporation->id = $characterModel->corporationId;
$characterData->corporation->name = $characterModel->corporationName;
}
// check for alliance
if($this->allianceId){
if($characterModel->allianceId){
$characterData->alliance = (object) [];
$characterData->alliance->id = $this->allianceId;
$characterData->alliance->name = $this->allianceName;
$characterData->alliance->id = $characterModel->allianceId;
$characterData->alliance->name = $characterModel->allianceName;
}
// add character Log (current pilot data)
@@ -78,10 +91,29 @@ class UserCharacterModel extends BasicModel {
}
return $characterData;
}
/**
* check if this character is Main character or not
* @return bool
*/
public function isMain(){
$isMain = false;
if($this->isMain == 1){
$isMain = true;
}
return $isMain;
}
/**
* set this character as main character
*/
public function setMain($value = 0){
$this->isMain = $value;
}
/**
* get character log model (if exists)
* @return bool|mixed
@@ -96,5 +128,4 @@ class UserCharacterModel extends BasicModel {
return $characterLog;
}
}

View File

@@ -15,10 +15,10 @@ class UserModel extends BasicModel {
protected $rel_ttl = 0;
protected $fieldConf = array(
'api' => array(
'apis' => array(
'has-many' => array('Model\UserApiModel', 'userId')
),
'characters' => array(
'userCharacters' => array(
'has-many' => array('Model\UserCharacterModel', 'userId')
)
);
@@ -30,12 +30,6 @@ class UserModel extends BasicModel {
'max' => 20
],
'regex' => '/^[ \w-_]+$/'
],
'password' => [
'length' => [
'min' => 5,
'max' => 255
]
]
];
@@ -47,49 +41,54 @@ class UserModel extends BasicModel {
$userData = (object) [];
$userData->id = $this->id;
$userData->name = $this->name;
$userData->email = $this->email;
// active char
$userData->character = null;
// api data
$APIs = $this->getAPIs();
foreach($APIs as $api){
$userData->api[] = $api->getData();
}
// all chars
$userData->characters = [];
$characters = $this->getCharacters();
$activeCharacter = null;
$mainCharacter = null;
foreach($characters as $character){
// find main
if($character->isMain){
$mainCharacter = $character;
}
// find active
// TODO replace with HTTP-HEADER IGB values
if($character->id == 2){
$activeCharacter = $character;
}
$userData->characters[] = $character->getData();
$userCharacters = $this->getUserCharacters();
foreach($userCharacters as $userCharacter){
$userData->characters[] = $userCharacter->getData();
}
// set active character with log data
if($activeCharacter){
$userData->character = $activeCharacter->getData(true);
}elseif($mainCharacter){
$userData->character = $mainCharacter->getData(true);
$activeUserCharacter = $this->getActiveUserCharacter();
if($activeUserCharacter){
$userData->character = $activeUserCharacter->getData(true);
}
return $userData;
}
/**
* validate and set a email address for this user
* @param $email
* @return mixed
*/
public function set_email($email){
if (\Audit::instance()->email($email) == false) {
// no valid email address
$this->_throwValidationError('email');
}
return $email;
}
/**
* generate password hash
* set a password hash for this user
* @param $password
* @return FALSE|string
*/
public static function generatePasswordHash($password){
// generate random id (23 chars)
public function set_password($password){
if(strlen($password) < 6){
$this->_throwValidationError('password');
}
$salt = uniqid('', true);
return \Bcrypt::instance()->hash($password, $salt);
}
@@ -140,83 +139,124 @@ class UserModel extends BasicModel {
* @return array|mixed
*/
public function getAPIs(){
$this->filter('api', array('active = ?', 1));
$this->filter('apis', array('active = ?', 1));
$api = [];
if($this->api){
$api = $this->api;
$apis = [];
if($this->apis){
$apis = $this->apis;
}
return $api;
return $apis;
}
/**
* set main character ID for this user.
* If id does not match with his API chars -> select "random" main character
* @param $characterId
* @return null
* @param int $characterId
*/
public function setMainCharacterId($characterId){
public function setMainCharacterId($characterId = 0){
$mainCharacter = null;
if(is_int($characterId)){
$characters = $this->getCharacters();
$userCharacters = $this->getUserCharacters();
if(count($characters) > 0){
foreach($characters as $character){
$isMain = 0;
if($characterId == $character->characterId){
$isMain = 1;
$mainCharacter = $character;
if(count($userCharacters) > 0){
$mainSet = false;
foreach($userCharacters as $userCharacter){
if($characterId == $userCharacter->characterId->characterId){
$mainSet = true;
$userCharacter->setMain(1);
}else{
$userCharacter->setMain(0);
}
$character->isMain = $isMain;
$character->save();
$userCharacter->save();
}
// set random main character
if(is_null($mainCharacter)){
$characters[0]->isMain = 1;
$characters[0]->save();
if(! $mainSet ){
$userCharacters[0]->setMain(1);
$userCharacters[0]->save();
}
}
}
return $mainCharacter;
}
/**
* get all characters for a user
* get all userCharacters models for a user
* characters will be checked/updated on login by CCP API call
* @return array|mixed
*/
public function getCharacters(){
$this->filter('characters', array('active = ?', 1));
public function getUserCharacters(){
$this->filter('userCharacters', array('active = ?', 1));
$characters = [];
if($this->characters){
$characters = $this->characters;
$userCharacters = [];
if($this->userCharacters){
$userCharacters = $this->userCharacters;
}
return $characters;
return $userCharacters;
}
/**
* get all active characters (with log entry)
* @return array
* Get the main user character for this user
* @return null
*/
public function getActiveCharacters(){
$characters = $this->getCharacters();
public function getMainUserCharacter(){
$mainUserCharacter = null;
$userCharacters = $this->getUserCharacters();
$activeCharacters = [];
foreach($characters as $character){
$characterLog = $character->getLog();
if($characterLog){
$activeCharacters[] = $character;
foreach($userCharacters as $userCharacter){
if($userCharacter->isMain()){
$mainUserCharacter = $userCharacter;
break;
}
}
return $activeCharacters;
return $mainUserCharacter;
}
/**
* get the active user character for this user
* either there is an active Character (IGB) or the character labeled as "main"
* @return null
*/
public function getActiveUserCharacter(){
$activeUserCharacter = null;
$userCharacters = $this->getUserCharacters();
foreach($userCharacters as $userCharacter){
// find active
// TODO replace with HTTP-HEADER IGB values
if($userCharacter->id == 2){
$activeUserCharacter = $userCharacter;
break;
}
}
// if no active character is found -> get main Character
if(is_null($activeUserCharacter)){
$activeUserCharacter = $this->getMainUserCharacter();
}
return $activeUserCharacter;
}
/**
* get all active user characters (with log entry)
* @return array
*/
public function getActiveUserCharacters(){
$userCharacters = $this->getUserCharacters();
$activeUserCharacters = [];
foreach($userCharacters as $userCharacter){
$characterLog = $userCharacter->getLog();
if($characterLog){
$activeUserCharacters[] = $userCharacter;
}
}
return $activeUserCharacters;
}

View File

@@ -4,6 +4,7 @@ requirejs.config({
stubModules: ['text'], // Exclude these modules on build
paths: {
layout: 'layout',
dialog: 'app/ui/dialog',
jquery: 'lib/jquery-1.11.2.min', // v1.11.2 jQuery
//jquery: "lib/jquery-2.1.1.min", // v2.1.1 jQuery
bootstrap: 'lib/bootstrap.min', // v3.3.0 Bootstrap js code - http://getbootstrap.com/javascript/
@@ -28,6 +29,7 @@ requirejs.config({
fullScreen: 'lib/jquery.fullscreen.min', // v0.5.0 Full screen mode - https://github.com/private-face/jquery.fullscreen
select2: 'lib/select2.min', // v4.0.0 Drop Down customization - https://select2.github.io/
validator: 'lib/validator.min', // v0.7.2 Validator for Bootstrap 3 - https://github.com/1000hz/bootstrap-validator
lazylinepainter: 'lib/jquery.lazylinepainter-1.5.1.min', //
pnotify: 'lib/pnotify/pnotify.core', // v2.0.1 PNotify - notification core file
@@ -97,6 +99,9 @@ requirejs.config({
},
validator: {
deps : ['jquery', 'bootstrap']
},
lazylinepainter: {
deps : ['jquery', 'bootstrap']
}
}
});

View File

@@ -44,6 +44,7 @@ define(['jquery'], function($) {
deleteSignatureData: 'api/signature/delete' // ajax URL - delete signature data for system
},
url: {
ccpImageServer: 'https://image.eveonline.com/', // CCP image Server
zKillboard: 'https://zkillboard.com/api/', // killboard api
eveCentral: 'http://api.eve-central.com/api/' // jump rout api
},

View File

@@ -35,6 +35,63 @@ define([
// Map init options
var mapData = [];
// TEST =============================================
/*
* Lazy Line Painter - Path Object
* Generated using 'SVG to Lazy Line Converter'
*
* http://lazylinepainter.info
* Copyright 2013, Cam O'Connell
*
*/
/*
var pathObj = {
"test-line": {
"strokepath": [
{
"path": "M 393.7 195.2 442.6 649.1 643.6 756.3 394.1 195.6",
"strokeColor": '#477372',
"duration": 800
},
{
"path": "M 87.1 750.5 201.1 629.8 366.3 632.7 87.9 750.6",
"strokeColor": '#4f9e4f',
"duration": 800
},
{
"path": "M 389 632.7 275.8 683.1 614.2 753.9 389.7 632.7",
"strokeColor": '#375959',
"duration": 800
},
{
"path": "M 404.5 404 84.7 736.7 383 181.2 404.5 403.1",
"strokeColor": '#63676a',
"duration": 800
}
],
"dimensions": {
"width": 745,
"height": 1053
}
}
};
$(document).ready(function(){
$('#test-line').lazylinepainter(
{
"svgData": pathObj,
"strokeWidth": 2,
"drawSequential": false
}).lazylinepainter('paint');
});
*/
/*
var mapData =[{
map: {},
@@ -525,10 +582,10 @@ define([
}
}];
*/
/*
// current user Data for a map
var tempUserData ={
currentUserData: {
userData: {
id: 1262,
character: [{
id: 12,
@@ -639,7 +696,7 @@ define([
}
}
]};
*/
// update map module ========================================
$('#' + config.mapModuleId).on('pf:initModule', function(){
@@ -653,13 +710,12 @@ define([
Init.connectionScopes = initData.connectionScopes;
Init.systemStatus = initData.systemStatus;
Init.systemType = initData.systemType;
Init.characterStatus = initData.characterStatus;
// init map module
mapModule.initMapModule();
}).fail(function( jqXHR, status, error) {
console.log(jqXHR);
var reason = status + ' ' + jqXHR.status + ': ' + error;
Util.emergencyShutdown(reason);
});
@@ -742,7 +798,7 @@ define([
triggerMapUpdatePing();
// ping for user data update -------------------------------------------------------
var triggerUserUpdatePing = function(userData){
var triggerUserUpdatePing = function(){
var updatedUserData = {};
@@ -753,24 +809,34 @@ define([
url: Init.path.updateUserData,
data: updatedUserData,
dataType: 'json'
}).done(function(userData){
}).done(function(data){
$(document).setProgramStatus('online');
if(userData.length === 0){
mapModule.updateMapModuleData(userData);
if(data.userData !== undefined){
// store current user data global (cache)
var userData = Util.setCurrentUserData(data.userData);
if(userData.character === undefined){
// no active character found -> show settings dialog
$(document).triggerMenuEvent('ShowSettingsDialog');
}else{
// active character data found
mapModule.updateMapModuleData(data);
var duration = Util.timeStop(mapUserUpdateKey);
// log execution time
Util.log(mapUserUpdateKey, {duration: duration, description:'updateMapModuleData'});
// init new trigger
setTimeout(function(){
triggerUserUpdatePing();
}, mapUserUpdateDelay);
}
}
var duration = Util.timeStop(mapUserUpdateKey);
// log execution time
Util.log(mapUserUpdateKey, {duration: duration, description:'updateMapModuleData'});
// init new trigger
setTimeout(function(){
triggerUserUpdatePing(tempUserData);
}, mapUserUpdateDelay);
}).fail(function( jqXHR, status, error) {
var reason = status + ' ' + jqXHR.status + ': ' + error;
@@ -782,7 +848,7 @@ define([
// start user update trigger after map loaded
setTimeout(function(){
triggerUserUpdatePing(tempUserData);
triggerUserUpdatePing();
}, 2000);
};

View File

@@ -71,18 +71,6 @@ define([
systemSecWHHeigh: 'pf-system-sec-high',
systemSecWHMid: 'pf-system-sec-mid',
systemSecWHLow: 'pf-system-sec-low',
// user status
userStatus: {
'corp': {
class: 'pf-user-status-corp'
},
'ally': {
class: 'pf-user-status-ally'
}
}
};
// active jsPlumb instances currently running
@@ -141,23 +129,6 @@ define([
connectionTypes: Init.connectionTypes
};
/**
* get status class for a user
* @param status
* @returns {string}
*/
var getStatusClassForUser = function(status){
var statusClass = '';
if(config.userStatus[status]){
statusClass = config.userStatus[status].class;
}
return statusClass;
};
/**
* updates a system with current information
* @param map
@@ -197,7 +168,7 @@ define([
for(var i = 0; i < data.user.length; i++){
userCounter++;
var tempUserData = data.user[i];
cacheArray.push(tempUserData.id + '_' + tempUserData.ship.name);
cacheArray.push(tempUserData.id + '_' + tempUserData.log.ship.name);
}
var cacheKey = cacheArray.join('_');
@@ -214,14 +185,14 @@ define([
for(var j = 0; j < data.user.length; j++){
var userData = data.user[j];
var statusClass = getStatusClassForUser(userData.status);
var statusClass = Util.getStatusInfoForCharacter(userData, 'class');
var userName = userData.name;
var item = $('<div>', {
class: config.systemBodyItemClass
}).append(
$('<span>', {
text: userData.ship.name,
text: userData.log.ship.name,
class: config.systemBodyRightClass
})
).append(
@@ -305,6 +276,12 @@ define([
}
};
/**
* show/hide system body element
* @param type
* @param map
* @param callback
*/
$.fn.toggleBody = function(type, map, callback){
var system = $(this);
var systemBody = system.find('.' + config.systemBodyClass);
@@ -2772,13 +2749,11 @@ define([
/**
* updates all systems on map with current user Data (all users on this map)
* update the Data of the user that is currently viewing the map (if available) -> In - game info
* update the Data of the user that is currently viewing the map (if available)
* @param userData
* @param currentUserData
* @returns {boolean}
*/
$.fn.updateUserData = function(userData, currentUserData){
$.fn.updateUserData = function(userData){
var returnStatus = true;
@@ -2790,6 +2765,13 @@ define([
var mapElement = map.getContainer();
// get global user data
var currentUserData = Init.currentUserData;
var currentCharacterData = null;
if(currentUserData.character){
currentCharacterData = currentUserData.character;
}
// container must exist! otherwise systems cant be updated
if(mapElement !== undefined){
@@ -2827,14 +2809,16 @@ define([
// check if user is currently in this system
var tempCurrentUserData = null;
if(
currentUserData &&
currentUserData.system.id === systemId
currentCharacterData &&
currentCharacterData.log &&
currentCharacterData.log.system &&
currentCharacterData.log.system.id === systemId
){
tempCurrentUserData = currentUserData;
// set current location data for header update
headerUpdateData.currentSystemId = systemId;
headerUpdateData.currentSystemName = system.getSystemInfo(['alias']);
headerUpdateData.currentSystemId = currentCharacterData.log.system.id;
headerUpdateData.currentSystemName = tempCurrentUserData.system.name;
}
if(tempUserData){
@@ -2845,7 +2829,7 @@ define([
}
// trigger document event -> update header
$(document).trigger('pf:updateHeaderData', headerUpdateData);
$(document).trigger('pf:updateHeaderMapData', headerUpdateData);
}
return returnStatus;

View File

@@ -199,64 +199,33 @@ define([
* @param userData
* @returns {boolean}
*/
var test = 1
$.fn.updateMapModuleData = function(userData){
$.fn.updateMapModuleData = function(userData){
var mapModule = $(this);
test++;
// get all active map elements for module
var mapElement = mapModule.getActiveMap();
var currentUserData = null;
// current user data
if(userData.currentUserData){
currentUserData = userData.currentUserData;
}
if(mapElement !== false){
var mapId = mapElement.data('id');
// save static user data
Config.currentUserData = userData.currentUserData;
//var tempMapUserData = null;
// get user data for each active map
var tempMapUserDataClone = null;
var mapUserData = null;
for(var j = 0; j < userData.mapUserData.length; j++){
//var tempMapData = userData.mapUserData[j];
var tempMapData = JSON.parse(JSON.stringify(userData.mapUserData[j]));
if(tempMapData.config.id === mapId){
var tempMapUserData = userData.mapUserData[j];
if(tempMapUserData.config.id === mapId){
// map userData found
// clone object (pass by value) due to object manipulation
tempMapUserDataClone = JSON.parse(JSON.stringify(tempMapData));
// TODO remove !!!!
if( (test % 2) === 0){
tempMapUserDataClone.data.systems[0].user.push({
id: 7,
name: 'Lijama',
ship: {
id: 59,
name: 'Archon'
},
status: 'corp'
})
}else if((test % 3) === 0){
tempMapUserDataClone.data.systems = new Array();
}
mapUserData = tempMapUserData;
break;
}
}
// update map
if(tempMapUserDataClone){
mapElement.updateUserData(tempMapUserDataClone, currentUserData);
if(mapUserData){
mapElement.updateUserData(mapUserData);
}
}

View File

@@ -1,23 +1,28 @@
/**
* page structure
*/
define([
'jquery',
'app/init',
'app/util',
'app/render',
'bootbox',
'app/ccp',
'app/ui/map_info',
'app/logging',
'dialog/map_info',
'dialog/settings',
'dialog/manual',
'dialog/map',
'dialog/system_effects',
'dialog/jump_info',
'dialog/credit',
'slidebars',
'app/module_map'
], function($, Init, Util, Render, bootbox, CCP, MapInfo, Logging) {
], function($, Init, Util, Render, CCP, Logging) {
'use strict';
var config = {
// page structure slidebars-menu classes
pageId: 'sb-site',
pageSlidebarClass: 'sb-slidebar',
@@ -35,48 +40,24 @@ define([
headClass: 'pf-head', // class for page head
headMenuClass: 'pf-head-menu', // class for page head menu button (left)
headMapClass: 'pf-head-map', // class for page head map button (right)
headMainCharacterClass: 'pf-head-main-character', // class for "main character" link
headUserCharacterClass: 'pf-head-user-character', // class for "user settings" link
userCharacterImageClass: 'pf-head-user-character-image', // class for "current user image"
headActiveUserClass: 'pf-head-active-user', // class for "active user" link
headCurrentLocationClass: 'pf-head-current-location', // class for "show current location" link
headProgramStatusClass: 'pf-head-program-status', // class for "program status" notification
// footer
pageFooterId: 'pf-footer', // id for page footer
footerLicenceLinkClass: 'pf-footer-licence', // class for "licence" link
// menu
menuHeadMenuLogoClass: 'pf-head-menu-logo', // class for main menu logo
menuButtonFullScreenId: 'pf-menu-button-fullscreen', // id for menu button "full screen"
// global dialog
dialogNavigationClass: 'pf-dialog-navigation-list', // class for dialog navigation bar
dialogNavigationListItemClass: 'pf-dialog-navigation-list-item', // class for map manual li main navigation elements
// map dialog
newMapDialogId: 'pf-map-new-dialog', // id for edit/update map dialog
// select character dialog
characterSelectDialogId: 'pf-select-character-dialog', // id for "select character" dialog
characterSelectImageWrapperClass: 'pf-dialog-image-wrapper', // class for image wrapper (animated)
characterSelectImageInfoClass: 'pf-dialog-character-info', // class for character info layer (visible on hover)
characterSelectMainClass: 'pf-dialog-character-main', // class for main character highlighting
// system effect dialog
systemEffectDialogWrapperClass: 'pf-system-effect-dialog-wrapper', // class for system effect dialog
// jump info dialog
jumpInfoDialogClass: 'pf-jump-info-dialog', // class for jump info dialog
// map manual dialog
mapManualScrollspyId: 'pf-manual-scrollspy', // id for map manual scrollspy
// helper element
dynamicElementWrapperId: 'pf-dialog-wrapper'
};
var cache = {
systemEffectDialog: false // system effect info dialog
};
var programStatusCounter = 0; // current count down in s until next status change is possible
var programStatusInterval = false; // interval timer until next status change is possible
@@ -329,9 +310,9 @@ define([
slideMenu.slidebars.toggle('right');
});
// active pilots
$('.' + config.headMainCharacterClass).find('a').on('click', function(){
$(document).triggerMenuEvent('ShowCharacterDialog');
// settings
$('.' + config.headUserCharacterClass).find('a').on('click', function(){
$(document).triggerMenuEvent('ShowSettingsDialog');
});
// active pilots
@@ -356,7 +337,13 @@ define([
// init all tooltips
var tooltipElements = $('#' + config.pageHeaderId).find('[title]');
tooltipElements.tooltip({placement: 'bottom'});
tooltipElements.tooltip({
placement: 'bottom',
delay: {
show: 500,
hide: 0
}
});
// trigger load main map module -> header is required for "System" drag&drop position
Util.getMapModule().trigger('pf:initModule');
@@ -368,7 +355,8 @@ define([
var moduleData = {
id: config.pageHeaderId,
brandLogo: config.menuHeadMenuLogoClass,
userName: 'Exodus 4D'
userCharacterClass: config.headUserCharacterClass,
userCharacterImageClass: config.userCharacterImageClass
};
Render.showModule(moduleConfig, moduleData);
@@ -387,13 +375,17 @@ define([
link: 'append',
functions: {
after: function(){
pageElement.find('.' + config.footerLicenceLinkClass).on('click', function(){
//show credits info dialog
$.fn.showCreditsDialog();
});
}
}
};
var moduleData = {
id: config.pageFooterId
id: config.pageFooterId,
footerLicenceLinkClass: config.footerLicenceLinkClass
};
Render.showModule(moduleConfig, moduleData);
@@ -419,13 +411,13 @@ define([
$(document).on('pf:menuShowSystemEffectInfo', function(e){
// show system effects info box
showSystemEffectInfoDialog();
$.fn.showSystemEffectInfoDialog();
return false;
});
$(document).on('pf:menuShowJumpInfo', function(e){
// show system effects info box
showJumpInfoDialog();
$.fn.showJumpInfoDialog();
return false;
});
@@ -437,19 +429,19 @@ define([
$(document).on('pf:menuManual', function(e){
// show map manual
showMapManual();
$.fn.showMapManual();
return false;
});
$(document).on('pf:menuShowCharacterDialog', function(e){
$(document).on('pf:menuShowSettingsDialog', function(e){
// show character select dialog
showCharacterSelectDialog();
$.fn.showSettingsDialog();
return false;
});
$(document).on('pf:menuShowMapInfo', function(e){
// show map information dialog
MapInfo.showDialog();
$.fn.showMapInfoDialog();
return false;
});
@@ -465,7 +457,7 @@ define([
}
}
showNewMapDialog(mapData);
$.fn.showNewMapDialog(mapData);
return false;
});
@@ -479,7 +471,7 @@ define([
mapData = activeMap.getMapData(true);
}
showDeleteMapDialog(mapData);
$.fn.showDeleteMapDialog(mapData);
return false;
});
@@ -518,7 +510,7 @@ define([
});
// update header links with current map data
$(document).on('pf:updateHeaderData', function(e, data){
$(document).on('pf:updateHeaderMapData', function(e, data){
var activeMap = Util.getMapModule().getActiveMap();
var userCount = 0;
@@ -537,6 +529,42 @@ define([
});
};
/**
* updates the header with current user data
*/
$.fn.updateHeaderUserData = function(){
var userData = Util.getCurrentUserData();
if(
userData &&
userData.character
){
var userInfoElement = $('.' + config.headUserCharacterClass);
// hide element
userInfoElement.velocity('stop').velocity({
opacity: 0
},{
visibility : 'hidden',
duration: 500,
complete: function(){
// set new data
userInfoElement.find('span').text(userData.character.name);
userInfoElement.find('img').attr('src', Init.url.ccpImageServer + '/Character/' + userData.character.characterId + '_32.jpg' );
userInfoElement.velocity({
opacity: 1
}, {
visibility : 'visible',
duration: 500
});
}
});
}
};
/**
* update the "active user" badge in header
* @param userCount
@@ -550,7 +578,7 @@ define([
badge.text(userCount);
badge.toggleClass('txt-color-green', (userCount > 0) );
badge.toggleClass('txt-color-greenLight', (userCount > 0) );
badge.toggleClass('txt-color-red', (userCount === 0) );
if(! activeUserElement.is(':visible')){
@@ -599,402 +627,6 @@ define([
}
};
/**
* shows the add/edit map dialog
*/
var showNewMapDialog = function(mapData){
var formData = {};
// check if dialog is already open
var mapInfoDialogElement = $('#' + config.newMapDialogId);
if(!mapInfoDialogElement.is(':visible')){
requirejs(['text!templates/modules/map_dialog.html', 'mustache'], function(template, Mustache) {
var data = {
id: config.newMapDialogId,
scope: Util.getMapScopes(),
type: Util.getMapTypes(),
icon: Util.getMapIcons(),
formData: formData
};
var content = Mustache.render(template, data);
var dialogTitle = 'Create new map';
var dialogSaveButton = 'add map';
if(mapData !== false){
dialogTitle = 'Edit map';
dialogSaveButton = 'save map';
content = $(content);
content.find('input[name="id"]').val( mapData.config.id );
content.find('select[name="icon"]').val( mapData.config.icon );
content.find('input[name="name"]').val( mapData.config.name );
content.find('select[name="scopeId"]').val( mapData.config.scope.id );
content.find('select[name="typeId"]').val( mapData.config.type.id );
}
var mapInfoDialog = bootbox.dialog({
title: dialogTitle,
message: content,
buttons: {
close: {
label: 'cancel',
className: 'btn-default'
},
success: {
label: '<i class="fa fa-code-fork fa-fw"></i>' + dialogSaveButton,
className: 'btn-primary',
callback: function() {
// get form Values
var form = $('#' + config.newMapDialogId).find('form');
// validate form
form.validator('validate');
// check weather the form is valid
var formValid = form.isValidForm();
if(formValid === true){
var newMapData = {mapData: form.getFormValues()};
$.ajax({
type: 'POST',
url: Init.path.saveMap,
data: newMapData,
dataType: 'json'
}).done(function(data){
Util.showNotify({title: dialogTitle, text: 'Map: ' + data.name, type: 'success'});
$(mapInfoDialog).modal('hide');
$(document).trigger('pf:closeMenu', [{}]);
}).fail(function( jqXHR, status, error) {
var reason = status + ' ' + error;
Util.showNotify({title: jqXHR.status + ': saveMap', text: reason, type: 'warning'});
$(document).setProgramStatus('problem');
});
}
return false;
}
}
}
});
});
}
};
/**
* shows the delete map Dialog
* @param mapElement
*/
var showDeleteMapDialog = function(mapData){
var mapName = mapData.config.name;
var mapDeleteDialog = bootbox.confirm('Delete map "' + mapName + '"?', function(result){
if(result){
var data = {mapData: mapData.config};
$.ajax({
type: 'POST',
url: Init.path.deleteMap,
data: data,
dataType: 'json'
}).done(function(data){
Util.showNotify({title: 'Map deleted', text: 'Map: ' + mapName, type: 'success'});
$(mapDeleteDialog).modal('hide');
}).fail(function( jqXHR, status, error) {
var reason = status + ' ' + error;
Util.showNotify({title: jqXHR.status + ': deleteMap', text: reason, type: 'warning'});
$(document).setProgramStatus('problem');
});
return false;
}
});
};
/**
* show main character select dialog
*/
var showCharacterSelectDialog = function(){
if(Init.currentUserData){
requirejs(['text!templates/modules/character_select_dialog.html', 'mustache'], function(template, Mustache) {
// calculate grid class
var characterCount = Init.currentUserData.character.length;
var gridClass = ((12 / characterCount) < 4)? 4 : 12 / characterCount ;
var data = {
id: config.characterSelectDialogId,
imageWrapperClass: config.characterSelectImageWrapperClass,
imageInfoClass: config.characterSelectImageInfoClass,
imageWrapperMainClass: config.characterSelectMainClass,
currentUserData: Init.currentUserData,
gridClass: 'col-sm-' + gridClass
};
var content = Mustache.render(template, data);
var selectCharacterDialog = bootbox.dialog({
title: 'Set main character',
message: content
});
selectCharacterDialog.on('shown.bs.modal', function(e) {
var imageWrapperElements = $(this).find('.' + config.characterSelectImageWrapperClass);
// save event =================================================
imageWrapperElements.on('click', function(e){
var wrapperElement = $(this);
var characterId = wrapperElement.data('id');
// remove not selected characters
if(characterId > 0){
wrapperElement.showLoadingAnimation();
var notClickedImageWrapperElements = imageWrapperElements.filter(':not([data-id=' + characterId + '])').parents('.col');
notClickedImageWrapperElements.velocity('transition.whirlOut', {
stagger: 60,
drag: true,
duration: 400,
complete: function(){
// center remaining character element
wrapperElement.parents('.col').addClass('col-sm-12');
// save configuration
var requestData = {
configData: {
mainCharacterId: characterId
}
};
$.ajax({
type: 'POST',
url: Init.path.saveUserConfig,
data: requestData,
dataType: 'json'
}).done(function(responseData){
Util.showNotify({title: 'Config saved', type: 'success'});
$(selectCharacterDialog).modal('hide');
}).fail(function( jqXHR, status, error) {
var reason = status + ' ' + error;
Util.showNotify({title: jqXHR.status + ': saveConfig', text: reason, type: 'warning'});
$(document).setProgramStatus('problem');
});
}
});
}
});
// initial show effect of all chars
imageWrapperElements.velocity('stop').delay(100).velocity('transition.flipBounceXIn', {
display: 'inline-block',
stagger: 60,
drag: true,
duration: 400
});
// Hover effect
imageWrapperElements.hoverIntent(function(e){
var characterInfoElement = $(this).find('.' + config.characterSelectImageInfoClass);
characterInfoElement.velocity('finish').velocity({
width: ['100%', [ 400, 15 ] ]
},{
easing: 'easeInSine'
});
}, function(e){
var characterInfoElement = $(this).find('.' + config.characterSelectImageInfoClass);
characterInfoElement.velocity('finish').velocity({
width: 0
},{
duration: 150,
easing: 'easeInOutSine'
});
});
});
});
}
};
/**
* shows the map manual modal dialog
*/
var showMapManual = function(){
requirejs(['text!templates/modules/map_manual_dialog.html', 'mustache'], function(template, Mustache) {
var data = {
dialogNavigationClass: config.dialogNavigationClass,
dialogNavLiClass: config.dialogNavigationListItemClass,
scrollspyId: config.mapManualScrollspyId,
pieChartClass : Init.classes.pieChart.pieChartMapCounterClass,
mapCounterClass : Init.classes.pieChart.pieChartMapCounterClass,
mapTypeGlobalClass: Util.getInfoForMap( 'global', 'class'),
mapTypeGlobalLabel: Util.getInfoForMap( 'global', 'label'),
mapTypeAllianceClass: Util.getInfoForMap( 'alliance', 'class'),
mapTypeAllianceLabel: Util.getInfoForMap( 'alliance', 'label'),
mapTypePrivateClass: Util.getInfoForMap( 'private', 'class'),
mapTypePrivateLabel: Util.getInfoForMap( 'private', 'label')
};
var content = Mustache.render(template, data);
// show dialog
var mapManualDialog = bootbox.dialog({
title: 'Pathfinder manual',
message: content,
buttons: {
success: {
label: 'close',
className: "btn-primary",
callback: function() {
$(mapManualDialog).modal('hide');
}
}
},
show: false
});
mapManualDialog.modal('show');
// modal offset top
var modalOffsetTop = 200;
// disable on scroll event
var disableOnScrollEvent = false;
// scroll breakpoints
var scrolLBreakpointElements = null;
// scroll navigation links
var scrollNavLiElements = null;
mapManualDialog.on('shown.bs.modal', function(e) {
// modal on open
scrolLBreakpointElements = $('.pf-manual-scroll-break');
scrollNavLiElements = $('.' + config.dialogNavigationListItemClass);
});
var scrollspyElement = $('#' + config.mapManualScrollspyId);
var whileScrolling = function(){
if(disableOnScrollEvent === false){
for(var i = 0; i < scrolLBreakpointElements.length; i++){
var offset = $(scrolLBreakpointElements[i]).offset().top;
if( (offset - modalOffsetTop) > 0){
if(! $( scrollNavLiElements[i]).hasClass('active')){
// remove all active classes
scrollNavLiElements.removeClass('active');
// remove focus on links
scrollNavLiElements.find('a').blur();
$( scrollNavLiElements[i]).addClass('active');
}
break;
}
}
}
};
// init scrollbar
scrollspyElement.mCustomScrollbar({
axis: 'y',
theme: 'light-thick',
scrollInertia: 200,
autoExpandScrollbar: false,
scrollButtons:{
scrollAmount: 30,
enable: true
},
advanced: {
updateOnBrowserResize: true,
updateOnContentResize: true
},
callbacks:{
onInit: function(){
// init fake-map update counter
scrollspyElement.find('.' + data.mapCounterClass).initMapUpdateCounter();
// set navigation button observer
var mainNavigationLinks = $('.' + config.dialogNavigationClass).find('a');
// text anchor links
var subNavigationLinks = scrollspyElement.find('a[data-target]');
var navigationLinks = mainNavigationLinks.add(subNavigationLinks);
navigationLinks.on('click', function(e){
e.preventDefault();
disableOnScrollEvent = true;
// scroll to anchor
scrollspyElement.mCustomScrollbar("scrollTo", $(this).attr('data-target'));
var mainNavigationLiElement = $(this).parent('.' + config.dialogNavigationListItemClass);
whileScrolling();
// if link is a main navigation link (not an anchor link)
if(mainNavigationLiElement.length > 0){
// remove all active classes
scrollNavLiElements.removeClass('active');
// set new active class
$(this).parent().addClass('active');
}
});
},
onScroll: function(){
disableOnScrollEvent = false;
whileScrolling();
},
whileScrolling: whileScrolling
},
mouseWheel:{
enable: true,
scrollAmount: 200,
axis: 'y',
preventDefault: true // do not scroll parent at the end
},
scrollbarPosition: 'outsite',
autoDraggerLength: true
});
});
};
/**
* shows a test notification for desktop messages
@@ -1010,107 +642,6 @@ define([
);
};
/**
* show jump info dialog
*/
var showJumpInfoDialog = function(){
requirejs(['text!templates/modules/jump_info_dialog.html', 'mustache'], function(template, Mustache) {
var data = {};
var content = Mustache.render(template, data);
var signatureReaderDialog = bootbox.dialog({
className: config.jumpInfoDialogClass,
title: 'Wormhole jump information',
message: content
});
});
};
/**
* show system effect dialog
*/
var showSystemEffectInfoDialog = function(){
// cache table structure
if(!cache.systemEffectDialog){
var dialogWrapperElement = $('<div>', {
class: config.systemEffectDialogWrapperClass
});
$.each( Init.systemEffects.wh, function( effectName, effectData ) {
var table = $('<table>', {
class: ['table', 'table-condensed'].join(' ')
});
var tbody = $('<tbody>');
var thead = $('<thead>');
var rows = [];
// get formatted system effect name
var systemEffectName = Util.getEffectInfoForSystem(effectName, 'name');
var systemEffectClass = Util.getEffectInfoForSystem(effectName, 'class');
$.each( effectData, function( areaId, areaData ) {
if(areaId === '1'){
rows.push( $('<tr>') );
thead.append( rows[0] );
rows[0].append(
$('<td>').html( '&nbsp;&nbsp;' + systemEffectName).prepend(
$('<i>', {
class: ['fa', 'fa-square', 'fa-fw', systemEffectClass].join(' ')
})
)
);
}
rows[0].append( $('<td>', {
class: ['text-right', 'col-xs-1'].join(' ')
}).text( 'C' + areaId ));
$.each( areaData, function( i, data ) {
if(areaId === '1'){
rows.push( $('<tr>') );
tbody.append(rows[i + 1]);
// add label
rows[i + 1].append( $('<td>').text( data.effect ));
}
rows[i + 1].append( $('<td>', {
class: 'text-right'
}).text( data.value ));
});
});
dialogWrapperElement.append( table.append( thead ).append( tbody ) );
cache.systemEffectDialog = dialogWrapperElement;
});
}
bootbox.dialog({
title: 'System effect information',
message: cache.systemEffectDialog
});
};
/**
* trigger "program status" in head
* @param status

119
js/app/ui/dialog/credit.js Normal file
View File

@@ -0,0 +1,119 @@
/**
* credits dialog
*/
define([
'jquery',
'app/init',
'app/util',
'app/render',
'bootbox',
'app/ui/logo'
], function($, Init, Util, Render, bootbox) {
'use strict';
var config = {
// jump info dialog
creditsDialogClass: 'pf-credits-dialog', // class for credits dialog
creditsDialogLogoContainerId: 'pf-credits-logo-container', // id for logo element
creditsDialogLogoSVGId: 'pf-credits-logo-svg', // id for logo SVG
// logo party
logoPartTopRightClass: 'logo-ploygon-top-right', // class for logo part "top right"
logoPartBottomLeftClass: 'logo-ploygon-bottom-left', // class for logo part "bottom left"
logoPartBottomRightClass: 'logo-ploygon-bottom-right', // class for logo part "bottom right"
logoPartTopLeftClass: 'logo-ploygon-top-left' // class for logo part "top left"
};
/**
* show jump info dialog
*/
$.fn.showCreditsDialog = function(){
requirejs(['text!templates/dialog/credit.html', 'mustache'], function(template, Mustache) {
var data = {
logoContainerId: config.creditsDialogLogoContainerId,
logoSVGId: config.creditsDialogLogoSVGId,
logoPartTopRightClass: config.logoPartTopRightClass,
logoPartBottomLeftClass: config.logoPartBottomLeftClass,
logoPartBottomRightClass: config.logoPartBottomRightClass,
logoPartTopLeftClass: config.logoPartTopLeftClass
};
var content = Mustache.render(template, data);
var creditDialog = bootbox.dialog({
className: config.creditsDialogClass,
title: 'Licence',
message: content
});
// after modal is shown =======================================================================
creditDialog.on('shown.bs.modal', function(e) {
var dialogElement = $(this);
$('#' + config.creditsDialogLogoContainerId).drawLogo(function(){
// hide lines
dialogElement.find('svg:not(#' + config.creditsDialogLogoSVGId + ')').velocity({
opacity: 0
},{
delay: 100
});
// show full logo
$('#' + config.creditsDialogLogoSVGId).velocity({
opacity: 1
},{
delay: 100,
duration: 200,
complete: function(){
var logoElements = $('#' + config.creditsDialogLogoSVGId + ' path');
var animate = [];
logoElements.on('mouseover', function(e){
var currentLogoElement = $(e.target);
var currentLogoElementIndex = logoElements.index(currentLogoElement);
var animationXValue = currentLogoElement.attr('data-animationX');
var animationYValue = currentLogoElement.attr('data-animationY');
var animationConfig = {};
animationConfig.opacity = [1, 1];
animationConfig.translateZ = [0, 0];
animationConfig.translateX = [animationXValue, 0 ];
animationConfig.translateY = [animationYValue, 0];
if(animate[currentLogoElementIndex] !== false){
$(this).velocity(animationConfig,{
duration: 150,
// easing: 'easeInOutCubic',
begin: function(){
animate[currentLogoElementIndex] = false;
}
}).velocity('reverse',{
delay: 250,
complete: function(){
animate[currentLogoElementIndex] = true;
}
});
}
});
}
});
});
});
});
};
});

View File

@@ -0,0 +1,39 @@
/**
* jump info dialog
*/
define([
'jquery',
'app/init',
'app/util',
'app/render',
'bootbox',
], function($, Init, Util, Render, bootbox) {
'use strict';
var config = {
// jump info dialog
jumpInfoDialogClass: 'pf-jump-info-dialog' // class for jump info dialog
};
/**
* show jump info dialog
*/
$.fn.showJumpInfoDialog = function(){
requirejs(['text!templates/dialog/jump_info.html', 'mustache'], function(template, Mustache) {
var data = {};
var content = Mustache.render(template, data);
var signatureReaderDialog = bootbox.dialog({
className: config.jumpInfoDialogClass,
title: 'Wormhole jump information',
message: content
});
});
};
});

180
js/app/ui/dialog/manual.js Normal file
View File

@@ -0,0 +1,180 @@
/**
* map manual dialog
*/
define([
'jquery',
'app/init',
'app/util',
'app/render',
'bootbox',
], function($, Init, Util, Render, bootbox) {
'use strict';
var config = {
// global dialog
dialogNavigationClass: 'pf-dialog-navigation-list', // class for dialog navigation bar
dialogNavigationListItemClass: 'pf-dialog-navigation-list-item', // class for map manual li main navigation elements
// map manual dialog
mapManualScrollspyId: 'pf-manual-scrollspy' // id for map manual scrollspy
};
/**
* shows the map manual modal dialog
*/
$.fn.showMapManual = function(){
requirejs(['text!templates/dialog/map_manual.html', 'mustache'], function(template, Mustache) {
var data = {
dialogNavigationClass: config.dialogNavigationClass,
dialogNavLiClass: config.dialogNavigationListItemClass,
scrollspyId: config.mapManualScrollspyId,
pieChartClass : Init.classes.pieChart.pieChartMapCounterClass,
mapCounterClass : Init.classes.pieChart.pieChartMapCounterClass,
mapTypeGlobalClass: Util.getInfoForMap( 'global', 'class'),
mapTypeGlobalLabel: Util.getInfoForMap( 'global', 'label'),
mapTypeAllianceClass: Util.getInfoForMap( 'alliance', 'class'),
mapTypeAllianceLabel: Util.getInfoForMap( 'alliance', 'label'),
mapTypePrivateClass: Util.getInfoForMap( 'private', 'class'),
mapTypePrivateLabel: Util.getInfoForMap( 'private', 'label')
};
var content = Mustache.render(template, data);
// show dialog
var mapManualDialog = bootbox.dialog({
title: 'Pathfinder manual',
message: content,
buttons: {
success: {
label: 'close',
className: "btn-primary",
callback: function() {
$(mapManualDialog).modal('hide');
}
}
},
show: false
});
mapManualDialog.modal('show');
// modal offset top
var modalOffsetTop = 200;
// disable on scroll event
var disableOnScrollEvent = false;
// scroll breakpoints
var scrolLBreakpointElements = null;
// scroll navigation links
var scrollNavLiElements = null;
mapManualDialog.on('shown.bs.modal', function(e) {
// modal on open
scrolLBreakpointElements = $('.pf-manual-scroll-break');
scrollNavLiElements = $('.' + config.dialogNavigationListItemClass);
});
var scrollspyElement = $('#' + config.mapManualScrollspyId);
var whileScrolling = function(){
if(disableOnScrollEvent === false){
for(var i = 0; i < scrolLBreakpointElements.length; i++){
var offset = $(scrolLBreakpointElements[i]).offset().top;
if( (offset - modalOffsetTop) > 0){
if(! $( scrollNavLiElements[i]).hasClass('active')){
// remove all active classes
scrollNavLiElements.removeClass('active');
// remove focus on links
scrollNavLiElements.find('a').blur();
$( scrollNavLiElements[i]).addClass('active');
}
break;
}
}
}
};
// init scrollbar
scrollspyElement.mCustomScrollbar({
axis: 'y',
theme: 'light-thick',
scrollInertia: 200,
autoExpandScrollbar: false,
scrollButtons:{
scrollAmount: 30,
enable: true
},
advanced: {
updateOnBrowserResize: true,
updateOnContentResize: true
},
callbacks:{
onInit: function(){
// init fake-map update counter
scrollspyElement.find('.' + data.mapCounterClass).initMapUpdateCounter();
// set navigation button observer
var mainNavigationLinks = $('.' + config.dialogNavigationClass).find('a');
// text anchor links
var subNavigationLinks = scrollspyElement.find('a[data-target]');
var navigationLinks = mainNavigationLinks.add(subNavigationLinks);
navigationLinks.on('click', function(e){
e.preventDefault();
disableOnScrollEvent = true;
// scroll to anchor
scrollspyElement.mCustomScrollbar("scrollTo", $(this).attr('data-target'));
var mainNavigationLiElement = $(this).parent('.' + config.dialogNavigationListItemClass);
whileScrolling();
// if link is a main navigation link (not an anchor link)
if(mainNavigationLiElement.length > 0){
// remove all active classes
scrollNavLiElements.removeClass('active');
// set new active class
$(this).parent().addClass('active');
}
});
},
onScroll: function(){
disableOnScrollEvent = false;
whileScrolling();
},
whileScrolling: whileScrolling
},
mouseWheel:{
enable: true,
scrollAmount: 200,
axis: 'y',
preventDefault: true // do not scroll parent at the end
},
scrollbarPosition: 'outsite',
autoDraggerLength: true
});
});
};
});

145
js/app/ui/dialog/map.js Normal file
View File

@@ -0,0 +1,145 @@
/**
* map module dialogs
*/
define([
'jquery',
'app/init',
'app/util',
'app/render',
'bootbox',
], function($, Init, Util, Render, bootbox) {
'use strict';
var config = {
// map dialog
newMapDialogId: 'pf-map-new-dialog' // id for edit/update map dialog
};
/**
* shows the add/edit map dialog
* @param mapData
*/
$.fn.showNewMapDialog = function(mapData){
var formData = {};
// check if dialog is already open
var mapInfoDialogElement = $('#' + config.newMapDialogId);
if(!mapInfoDialogElement.is(':visible')){
requirejs(['text!templates/dialog/map.html', 'mustache'], function(template, Mustache) {
var data = {
id: config.newMapDialogId,
scope: Util.getMapScopes(),
type: Util.getMapTypes(),
icon: Util.getMapIcons(),
formData: formData
};
var content = Mustache.render(template, data);
var dialogTitle = 'Create new map';
var dialogSaveButton = 'add map';
if(mapData !== false){
dialogTitle = 'Edit map';
dialogSaveButton = 'save map';
content = $(content);
content.find('input[name="id"]').val( mapData.config.id );
content.find('select[name="icon"]').val( mapData.config.icon );
content.find('input[name="name"]').val( mapData.config.name );
content.find('select[name="scopeId"]').val( mapData.config.scope.id );
content.find('select[name="typeId"]').val( mapData.config.type.id );
}
var mapInfoDialog = bootbox.dialog({
title: dialogTitle,
message: content,
buttons: {
close: {
label: 'cancel',
className: 'btn-default'
},
success: {
label: '<i class="fa fa-code-fork fa-fw"></i>' + dialogSaveButton,
className: 'btn-primary',
callback: function() {
// get form Values
var form = $('#' + config.newMapDialogId).find('form');
// validate form
form.validator('validate');
// check weather the form is valid
var formValid = form.isValidForm();
if(formValid === true){
var newMapData = {mapData: form.getFormValues()};
$.ajax({
type: 'POST',
url: Init.path.saveMap,
data: newMapData,
dataType: 'json'
}).done(function(data){
Util.showNotify({title: dialogTitle, text: 'Map: ' + data.name, type: 'success'});
$(mapInfoDialog).modal('hide');
$(document).trigger('pf:closeMenu', [{}]);
}).fail(function( jqXHR, status, error) {
var reason = status + ' ' + error;
Util.showNotify({title: jqXHR.status + ': saveMap', text: reason, type: 'warning'});
$(document).setProgramStatus('problem');
});
}
return false;
}
}
}
});
});
}
};
/**
* shows the delete map Dialog
* @param mapElement
*/
$.fn.showDeleteMapDialog = function(mapData){
var mapName = mapData.config.name;
var mapDeleteDialog = bootbox.confirm('Delete map "' + mapName + '"?', function(result){
if(result){
var data = {mapData: mapData.config};
$.ajax({
type: 'POST',
url: Init.path.deleteMap,
data: data,
dataType: 'json'
}).done(function(data){
Util.showNotify({title: 'Map deleted', text: 'Map: ' + mapName, type: 'success'});
$(mapDeleteDialog).modal('hide');
}).fail(function( jqXHR, status, error) {
var reason = status + ' ' + error;
Util.showNotify({title: jqXHR.status + ': deleteMap', text: reason, type: 'warning'});
$(document).setProgramStatus('problem');
});
return false;
}
});
};
});

View File

@@ -346,13 +346,13 @@ define([
/**
* shows the map information modal dialog
*/
var showDialog = function(){
$.fn.showMapInfoDialog = function(){
var activeMap = Util.getMapModule().getActiveMap();
var mapData = activeMap.getMapData(true);
if(mapData !== false){
requirejs(['text!templates/modules/map_info_dialog.html', 'mustache'], function(template, Mustache) {
requirejs(['text!templates/dialog/map_info.html', 'mustache'], function(template, Mustache) {
var data = {
dialogNavigationClass: config.dialogNavigationClass,
@@ -416,10 +416,4 @@ define([
}
};
return {
showDialog: showDialog
};
});

View File

@@ -0,0 +1,362 @@
/**
* user settings dialog
*/
define([
'jquery',
'app/init',
'app/util',
'app/render',
'bootbox',
], function($, Init, Util, Render, bootbox) {
'use strict';
var config = {
dialogWizardNavigationClass: 'pf-wizard-navigation', // class for wizard navigation bar
// select character dialog
settingsDialogId: 'pf-settings-dialog', // id for "settings" dialog
settingsImageWrapperClass: 'pf-dialog-image-wrapper', // class for image wrapper (animated)
settingsImageInfoClass: 'pf-dialog-character-info', // class for character info layer (visible on hover)
settingsMainClass: 'pf-dialog-character-main', // class for main character highlighting
settingsNavigationButtonClass: 'pf-dialog-navigation-button', // class for all navigation buttons
settingsFinishButtonClass: 'pf-dialog-finish-button', // class for "finish" button
settingsPrevButtonClass: 'pf-dialog-prev-button', // class for "prev" button
settingsNextButtonClass: 'pf-dialog-next-button', // class for "next" button
settingsCloneApiRowClass: 'pf-dialog-api-row', // class for form row with API data (will be cloned)
settingsCloneRowButtonClass: 'pf-dialog-clone-button', // class for clone button (api row)
settingsDeleteRowButtonClass: 'pf-dialog-delete-button' // class for delete button (api row)
};
/**
* getz active Tab link element for a dialog
* @param dialog
* @returns {JQuery|*}
*/
var getActiveTabElement = function(dialog){
var navigationBarElement = $(dialog).find('.' + config.dialogWizardNavigationClass);
var currentActiveTab = navigationBarElement.find('li.active');
return currentActiveTab;
};
/**
* show "settings" dialog
*/
$.fn.showSettingsDialog = function(){
// check navigation buttons and show/hide them
var checkNavigationButton = function(dialog){
var navigationBarElement = $(dialog).find('.' + config.dialogWizardNavigationClass);
var currentActiveTab = navigationBarElement.find('li.active');
var hidePrevButton = currentActiveTab.prevAll().length > 0 ? false : true;
var hideNextButton = currentActiveTab.nextAll().length > 0 ? false : true;
if(hidePrevButton){
$('.' + config.settingsPrevButtonClass).hide();
}else{
$('.' + config.settingsPrevButtonClass).show();
}
if(hideNextButton){
$('.' + config.settingsNextButtonClass).hide();
}else{
$('.' + config.settingsNextButtonClass).show();
}
};
requirejs(['text!templates/dialog/settings.html', 'mustache'], function(template, Mustache) {
var data = {
id: config.settingsDialogId,
navigationClass: config.dialogWizardNavigationClass,
userData: Init.currentUserData,
cloneApiRowClass: config.settingsCloneApiRowClass,
cloneRowButtonClass: config.settingsCloneRowButtonClass,
deleteRowButtonClass: config.settingsDeleteRowButtonClass
};
var content = Mustache.render(template, data);
var selectCharacterDialog = bootbox.dialog({
title: 'Account settings',
message: content,
buttons: {
close: {
label: 'finish',
className: ['btn-success', 'pull-right', config.settingsFinishButtonClass].join(' ')
},
prev: {
label: '<i class="fa fa-fw fa-angle-left"></i>back',
className: ['btn-default', 'pull-left', config.settingsNavigationButtonClass, config.settingsPrevButtonClass].join(' '),
callback: function (e) {
var currentActiveTab = getActiveTabElement(this);
currentActiveTab.removeClass('finished');
currentActiveTab.prev('li').find('a').tab('show');
return false;
}
},
next: {
label: 'next<i class="fa fa-fw fa-angle-right"></i>',
className: ['btn-primary', 'pull-right', config.settingsNavigationButtonClass, config.settingsNextButtonClass].join(' '),
callback: function (e) {
var dialogElement = $(this);
var currentActiveTab = getActiveTabElement(dialogElement);
var currentActiveLink = currentActiveTab.find('a');
var tabContentElement = $(currentActiveLink.attr('href'));
var changeTab = function(){
currentActiveTab.addClass('finished');
currentActiveLink.removeClass('btn-danger btn-default');
currentActiveLink.addClass('btn-primary');
currentActiveTab.next('li').find('a').tab('show');
};
// validate form
var form = tabContentElement.find('form');
form.validator('validate');
var formValid = form.isValidForm();
if(!formValid){
currentActiveTab.removeClass('disabled');
currentActiveLink.removeClass('btn-default btn-primary');
currentActiveLink.addClass('btn-danger');
}else{
var tabFormValues = form.getFormValues();
if(! $.isEmptyObject(tabFormValues) ){
// send Tab data and store values
var requestData = {
settingsData: tabFormValues
};
selectCharacterDialog.find('.modal-content').showLoadingAnimation();
$.ajax({
type: 'POST',
url: Init.path.saveUserConfig,
data: requestData,
dataType: 'json'
}).done(function(responseData){
selectCharacterDialog.find('.modal-content').hideLoadingAnimation();
if(responseData.error){
var errorAlert = form.find('.alert');
for(var i = 0; i < responseData.error.length; i++){
var errorData = responseData.error[i];
if(errorData.type === 'api'){
errorAlert.find('small').text(errorData.message + '. Key ID: ' + errorData.keyId);
}
}
errorAlert.velocity('transition.slideUpIn',{
duration: 500
});
}else{
// store new/updated user data -> update head
Util.setCurrentUserData(responseData.userData);
dialogElement.find('.alert').velocity('transition.slideDownOut',{
duration: 500,
complete: function(){
// switch tab
changeTab();
}
});
}
Util.showNotify({title: 'Account data saved', type: 'success'});
}).fail(function( jqXHR, status, error) {
var reason = status + ' ' + error;
Util.showNotify({title: jqXHR.status + ': saveConfig', text: reason, type: 'warning'});
$(document).setProgramStatus('problem');
// close dialog
selectCharacterDialog.modal('hide');
});
}else{
// no request required -> change tab
changeTab();
}
}
return false;
}
}
}
});
// after modal is shown =======================================================================
selectCharacterDialog.on('shown.bs.modal', function(e) {
var dialogElement = $(this);
var tabLinkElements = dialogElement.find('a[data-toggle="tab"]');
// on Tab switch ======================================================================
tabLinkElements.on('shown.bs.tab', function (e) {
// check navigation buttons (hide/show)
checkNavigationButton(dialogElement);
$(e.target).removeClass('disabled');
// hide finish button
dialogElement.find('.' + config.settingsFinishButtonClass).hide();
if($(e.target).text() < $(e.relatedTarget).text()){
var currentActiveTab = getActiveTabElement(dialogElement);
var nextTabElements = currentActiveTab.nextAll();
// disable all next tabs
currentActiveTab.removeClass('finished');
nextTabElements.removeClass('finished');
nextTabElements.find('a').removeClass('btn-primary btn-danger').addClass('btn-default disabled');
}
if($(e.target).text() === '3'){
// load character tab -----------------------------------------------
requirejs(['text!templates/form/character_panel.html', 'mustache'], function(template, Mustache) {
// all characters for the current user
var characters = Init.currentUserData.characters;
// calculate grid class
var characterCount = characters.length;
var gridClass = ((12 / characterCount) < 4)? 4 : 12 / characterCount ;
// add character status information for each character
var mainCharacter = 0;
for(var i = 0; i < characters.length; i++){
var statusInfo = {};
statusInfo.class = Util.getStatusInfoForCharacter(characters[i], 'class');
statusInfo.label = Util.getStatusInfoForCharacter(characters[i], 'name');
characters[i].status =statusInfo;
if(characters[i].isMain === 1){
mainCharacter = characters[i].characterId;
}
}
var characterTemplateData = {
imageWrapperClass: config.settingsImageWrapperClass,
imageInfoClass: config.settingsImageInfoClass,
imageWrapperMainClass: config.settingsMainClass,
charactersData: characters,
gridClass: 'col-sm-' + gridClass,
mainCharacter: mainCharacter
};
var content = Mustache.render(template, characterTemplateData);
dialogElement.find('#pf-dialog-settings-character form').html(content);
var imageWrapperElements = dialogElement.find('.' + config.settingsImageWrapperClass);
// special effects :)
imageWrapperElements.velocity('stop').delay(100).velocity('transition.flipBounceXIn', {
display: 'inline-block',
stagger: 60,
drag: true,
duration: 400,
complete: function(){
// init all tooltips
var tooltipElements = dialogElement.find('[title]');
tooltipElements.tooltip({
placement: 'top',
container: dialogElement
});
}
});
// Hover effect for character info layer
imageWrapperElements.hoverIntent(function(e){
var characterInfoElement = $(this).find('.' + config.settingsImageInfoClass);
characterInfoElement.velocity('finish').velocity({
width: ['100%', [ 400, 15 ] ]
},{
easing: 'easeInSine'
});
}, function(e){
var characterInfoElement = $(this).find('.' + config.settingsImageInfoClass);
characterInfoElement.velocity('finish').velocity({
width: 0
},{
duration: 150,
easing: 'easeInOutSine'
});
});
// click event on character image
imageWrapperElements.on('click', function(e){
var wrapperElement = $(this);
var characterId = wrapperElement.data('id');
// update layout if character is selected
if(characterId > 0){
// update hidden field with new mainCharacterId
dialogElement.find('input[name="mainCharacterId"]').val(characterId);
imageWrapperElements.removeClass( config.settingsMainClass );
wrapperElement.addClass( config.settingsMainClass );
}
});
});
}else if($(e.target).text() === '4'){
// show finish button
dialogElement.find('.' + config.settingsFinishButtonClass).show();
// show success message
dialogElement.find('h1').velocity('stop').delay(200).velocity('transition.flipBounceXIn', {
duration: 500
}).delay(100).velocity('callout.pulse');
}
});
// API Tab ================================================================================
dialogElement.find('.' + config.settingsCloneRowButtonClass).on('click', function(){
var cloneRow = dialogElement.find('.' + config.settingsCloneApiRowClass).last();
var newApiRow = cloneRow.clone(true);
newApiRow.find('input').val('');
cloneRow.after(newApiRow);
});
dialogElement.find('.' + config.settingsDeleteRowButtonClass).on('click', function(){
$(this).parents('.row').remove();
});
});
});
};
});

View File

@@ -0,0 +1,101 @@
/**
* system effects dialog
*/
define([
'jquery',
'app/init',
'app/util',
'app/render',
'bootbox',
], function($, Init, Util, Render, bootbox) {
'use strict';
var config = {
// system effect dialog
systemEffectDialogWrapperClass: 'pf-system-effect-dialog-wrapper' // class for system effect dialog
};
var cache = {
systemEffectDialog: false // system effect info dialog
};
/**
* show system effect dialog
*/
$.fn.showSystemEffectInfoDialog = function(){
// cache table structure
if(!cache.systemEffectDialog){
var dialogWrapperElement = $('<div>', {
class: config.systemEffectDialogWrapperClass
});
$.each( Init.systemEffects.wh, function( effectName, effectData ) {
var table = $('<table>', {
class: ['table', 'table-condensed'].join(' ')
});
var tbody = $('<tbody>');
var thead = $('<thead>');
var rows = [];
// get formatted system effect name
var systemEffectName = Util.getEffectInfoForSystem(effectName, 'name');
var systemEffectClass = Util.getEffectInfoForSystem(effectName, 'class');
$.each( effectData, function( areaId, areaData ) {
if(areaId === '1'){
rows.push( $('<tr>') );
thead.append( rows[0] );
rows[0].append(
$('<td>').html( '&nbsp;&nbsp;' + systemEffectName).prepend(
$('<i>', {
class: ['fa', 'fa-square', 'fa-fw', systemEffectClass].join(' ')
})
)
);
}
rows[0].append( $('<td>', {
class: ['text-right', 'col-xs-1'].join(' ')
}).text( 'C' + areaId ));
$.each( areaData, function( i, data ) {
if(areaId === '1'){
rows.push( $('<tr>') );
tbody.append(rows[i + 1]);
// add label
rows[i + 1].append( $('<td>').text( data.effect ));
}
rows[i + 1].append( $('<td>', {
class: 'text-right'
}).text( data.value ));
});
});
dialogWrapperElement.append( table.append( thead ).append( tbody ) );
cache.systemEffectDialog = dialogWrapperElement;
});
}
bootbox.dialog({
title: 'System effect information',
message: cache.systemEffectDialog
});
};
});

69
js/app/ui/logo.js Normal file
View File

@@ -0,0 +1,69 @@
/**
* Logo
*/
define([
'jquery',
'lazylinepainter'
], function($) {
'use strict';
/**
* draws the pathfinder logo to an element and add some animation features
* @param callback
*/
$.fn.drawLogo = function(callback){
var canvasElement = $(this);
var pathObj = {
logo: {
strokepath: [
{
path: "M195.9 9.6 226.9 297.1 354.2 365 196.2 9.8 ",
strokeColor: '#477372',
duration: 1600
},
{
path: "M1.7 361.3 73.9 284.9 178.6 286.7 2.2 361.4 ",
strokeColor: '#5cb85c',
duration: 1000
},
{
path: "M192.9 286.7 121.2 318.6 335.6 363.5 193.4 286.7 ",
strokeColor: '#375959',
duration: 900
},
{
path: "M202.8 141.9 0.2 352.6 189.1 0.8 202.7 141.3 ",
strokeColor: '#63676a',
duration: 1500
}
],
dimensions: {
width: 355,
height: 366
}
}
};
// draw the logo
canvasElement.lazylinepainter(
{
svgData: pathObj,
strokeWidth: 2,
drawSequential: false,
delay: 300,
overrideKey: 'logo',
strokeJoin: 'bevel',
onComplete: function(){
if(callback){
callback();
}
}
}).lazylinepainter('paint');
};
});

View File

@@ -368,21 +368,61 @@ define([
* adds a popup tooltip with signature information to a row
* @param data
*/
$.fn.addRowTooltip = function(data){
$.fn.addRowTooltip = function(tooltipData){
var rowElement = $(this);
if(
data.addedBy.length > 0 &&
data.updatedBy.length > 0
tooltipData.created.characterId > 0 &&
tooltipData.updated.characterId > 0
){
var tooltip = '<table>' +
var data = {
created: tooltipData.created,
updated: tooltipData.updated
};
requirejs(['text!templates/tooltip/signature.html', 'mustache'], function(template, Mustache) {
var content = Mustache.render(template, data);
rowElement.attr('data-toggle', 'popover')
.attr('data-trigger', 'hover')
.attr('data-placement', 'bottom')
.attr('data-html', 1)
.attr('data-content', content)
.attr('data-container', 'body')
.popover();
});
/*
var tooltip = '';
// image
// tooltip += '<img class="pf-head-user-character-image" src="https://image.eveonline.com//Character/93289067_32.jpg">';
tooltip += '<ul class="media-list">' +
'<li class="media">' +
'<a class="pull-left" href="javascript:void(0);">' +
'<img class="pf-head-user-character-image" src="https://image.eveonline.com//Character/93289067_32.jpg">' +
'</a>' +
'<div class="media-body">' +
'<h4 class="media-heading">Media heading</h4>' +
'<p>hgfhfghfg</p>' +
'</div>' +
'</li>' +
'</ul>';
// table
tooltip += '<table>' +
'<tr>' +
'<td>Added</td>' +
'<td>' + data.addedBy + '</td>' +
'<td>' + data.created.characterId + '</td>' +
'</tr>' +
'<tr>' +
'<td>Updated</td>' +
'<td>' + data.updatedBy + '</td>' +
'<td>' + data.updated.characterId + '</td>' +
'</tr>' +
'</table>';
@@ -393,6 +433,7 @@ define([
.attr('data-content', tooltip)
.attr('data-container', 'body')
.popover();
*/
}
};
@@ -501,7 +542,6 @@ define([
}
}
});
});
};
@@ -1319,13 +1359,13 @@ console.log('TODO')
],
createdRow: function(row, data, dataIndex){
// callback function after new row created
console.log(data);
if(data.id > 0){
// add row tooltip
var tooltipData = {
addedBy: data.created.userName,
updatedBy: data.updated.userName
created: data.created,
updated: data.updated
};
$(row).addRowTooltip( tooltipData );

View File

@@ -186,29 +186,6 @@ define([
});
};
/**
* get all form Values as object
* this includes all xEditable fields
* @returns {{}}
*/
$.fn.getFormValues = function(){
var form = $(this);
var formData = {};
$.each(form.serializeArray(), function(i, field) {
formData[field.name] = field.value;
});
// get xEditable values
var editableValues = form.find('.' + config.formEditableFieldClass).editable('getValue');
// merge values
formData = $.extend(formData, editableValues);
return formData;
};
/**
* checks weather a bootstrap form is valid or not
* validation plugin does not provide a proper function for this
@@ -227,6 +204,38 @@ define([
return valid;
};
/**
* get all form Values as object
* this includes all xEditable fields
* @returns {{}}
*/
$.fn.getFormValues = function(){
var form = $(this);
var formData = {};
$.each(form.serializeArray(), function(i, field) {
if(field.name.indexOf('[]') !== -1){
// array field
var key = field.name.replace('[]', '');
if(! $.isArray(formData[key]) ){
formData[key] = [];
}
formData[key].push( field.value);
}else{
formData[field.name] = field.value;
}
});
// get xEditable values
var editableValues = form.find('.' + config.formEditableFieldClass).editable('getValue');
// merge values
formData = $.extend(formData, editableValues);
return formData;
};
/**
* checks if an element is currently visible in viewport
@@ -540,6 +549,51 @@ define([
return data;
};
/**
* get status info for a character for a given status
* @param characterData
* @param option
* @returns {string}
*/
var getStatusInfoForCharacter = function(characterData, option){
var statusInfo = '';
var corporationId = null;
var allianceId = null;
if(
Init.currentUserData &&
Init.currentUserData.character
){
var tempCharacterData = Init.currentUserData.character;
// check if current user has a corpId
if(tempCharacterData.corporation){
corporationId = tempCharacterData.corporation.id;
}
// check if current user has a allianceId
if(tempCharacterData.alliance){
allianceId = tempCharacterData.alliance.id;
}
}
// compare current user data with given user data
if(
characterData.corporation &&
characterData.corporation.id === corporationId
){
statusInfo = Init.characterStatus.corporation[option];
}else if(
characterData.alliance &&
characterData.alliance.id === allianceId
){
statusInfo = Init.characterStatus.alliance[option];
}
return statusInfo;
};
var getSystemEffectTable = function(data){
var table = '';
@@ -811,8 +865,52 @@ define([
};
/**
* set currentUserData to "global" variable
* @param userData
*/
var setCurrentUserData = function(userData){
var currentUserData = getCurrentUserData();
// check if userData has changed
var changed = false;
if(
currentUserData === undefined &&
userData !== undefined
){
changed = true;
}else if(userData.character
){
if(currentUserData.character === undefined){
changed = true;
}else if( userData.character.characterId !== currentUserData.character.characterId ){
changed = true;
}
}
Init.currentUserData = userData;
// update head if user data has changed
if(changed){
$.fn.updateHeaderUserData();
}
return getCurrentUserData();
};
/**
* get currentUserData from "global" variable
* @returns {*}
*/
var getCurrentUserData = function(){
return Init.currentUserData;
};
return {
getServerTime: getServerTime,
getCurrentUserData: getCurrentUserData,
timeStart: timeStart,
timeStop: timeStop,
log: log,
@@ -831,6 +929,7 @@ define([
getEffectInfoForSystem: getEffectInfoForSystem,
getSystemEffectData: getSystemEffectData,
getSystemEffectTable: getSystemEffectTable,
getStatusInfoForCharacter: getStatusInfoForCharacter,
getSecurityClassForSystem: getSecurityClassForSystem,
getTrueSecClassForSystem: getTrueSecClassForSystem,
getStatusInfoForSystem: getStatusInfoForSystem,
@@ -839,6 +938,7 @@ define([
getAllSignatureNames: getAllSignatureNames,
getSignatureTypeIdByName: getSignatureTypeIdByName,
getAreaIdBySecurity: getAreaIdBySecurity,
emergencyShutdown: emergencyShutdown
emergencyShutdown: emergencyShutdown,
setCurrentUserData: setCurrentUserData,
};
});

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,17 @@
/*
* Lazy Line Painter
* SVG Stroke animation.
*
* https://github.com/camoconnell/lazy-line-painter
* http://www.camoconnell.com
*
* Licensed under the MIT license.
*
*/
(function(e){var g={init:function(a){return this.each(function(){var b=e(this),c=b.data("lazyLinePainter");b.addClass("lazy-line");if(!c){var c=e.extend({width:null,height:null,strokeWidth:2,strokeColor:"#000",strokeOverColor:null,strokeCap:"round",strokeJoin:"round",strokeOpacity:1,arrowEnd:"none",onComplete:null,onStart:null,delay:null,overrideKey:null,drawSequential:!0,speedMultiplier:1,reverse:!1,responsive:!1},a),d=c.overrideKey?c.overrideKey:b.attr("id").replace("#",""),f=c.svgData[d].dimensions.width,
l=c.svgData[d].dimensions.height;c.svgData=c.svgData[d].strokepath;null===c.width&&(c.width=f);null===c.height&&(c.height=l);c.responsive||b.css({width:c.width,height:c.height});d="0 0 "+f+" "+l;f=document.createElementNS("http://www.w3.org/2000/svg","svg");f.setAttributeNS(null,"viewBox",d);f.setAttribute("xmlns","http://www.w3.org/2000/svg");c.svg=e(f);b.append(c.svg);b.data("lazyLinePainter",c)}})},paint:function(){return this.each(function(){var a=e(this).data("lazyLinePainter"),b=function(){a.paths=
[];a.longestDuration=0;for(var b=a.playhead=0,d=0,f=0,d=0;d<a.svgData.length;d++)b=a.svgData[d].duration*a.speedMultiplier,f+=b;for(d=0;d<a.svgData.length;d++){var e=m(a,d),h=e.getTotalLength();e.style.strokeDasharray=h+" "+h;e.style.strokeDashoffset=h;e.style.display="block";e.getBoundingClientRect();b=a.svgData[d].duration*a.speedMultiplier;b>a.longestDuration&&(a.longestDuration=b);var g;g=a.reverse?f-=b:a.playhead;a.paths.push({duration:b,drawStartTime:g,path:e,length:h});a.playhead+=b}a.totalDuration=
a.drawSequential?a.playhead:a.longestDuration;a.rAF=requestAnimationFrame(function(b){k(b,a)});if(null!==a.onStart)a.onStart()};null===a.delay?b():setTimeout(b,a.delay)})},pauseResume:function(){return this.each(function(){var a=e(this).data("lazyLinePainter");a.paused?(a.paused=!1,requestAnimationFrame(function(b){n(b,a)})):(a.paused=!0,cancelAnimationFrame(a.rAF))})},erase:function(){return this.each(function(){var a=e(this).data("lazyLinePainter");a.startTime=null;a.elapsedTime=null;cancelAnimationFrame(a.rAF);
a.svg.empty()})},destroy:function(){return this.each(function(){var a=e(this);a.removeData("lazyLinePainter");a.remove()})}},n=function(a,b){b.startTime=a-b.elapsedTime;requestAnimationFrame(function(a){k(a,b)})},k=function(a,b){b.startTime||(b.startTime=a);b.elapsedTime=a-b.startTime;for(var c=0;c<b.paths.length;c++){var d;b.drawSequential?(d=b.elapsedTime-b.paths[c].drawStartTime,0>d&&(d=0)):d=b.elapsedTime;d<b.paths[c].duration&&0<d?(d=d/b.paths[c].duration*b.paths[c].length,b.paths[c].path.style.strokeDashoffset=
b.reverse||b.svgData[c].reverse?-b.paths[c].length+d:b.paths[c].length-d):d>b.paths[c].duration&&(b.paths[c].path.style.strokeDashoffset=0)}if(b.elapsedTime<b.totalDuration)b.rAF=requestAnimationFrame(function(a){k(a,b)});else if(null!==b.onComplete)b.onComplete()},m=function(a,b){var c=document.createElementNS("http://www.w3.org/2000/svg","path"),d=e(c);a.svg.append(d);d.attr(p(a,a.svgData[b]));return c},p=function(a,b){return{d:b.path,stroke:b.strokeColor?b.strokeColor:a.strokeColor,"fill-opacity":0,
"stroke-opacity":b.strokeOpacity?b.strokeOpacity:a.strokeOpacity,"stroke-width":b.strokeWidth?b.strokeWidth:a.strokeWidth,"stroke-linecap":b.strokeCap?b.strokeCap:a.strokeCap,"stroke-linejoin":b.strokeJoin?b.strokeJoin:a.strokeJoin}};e.fn.lazylinepainter=function(a){if(g[a])return g[a].apply(this,Array.prototype.slice.call(arguments,1));if("object"!==typeof a&&a)console.log("opps - issue finding method");else return g.init.apply(this,arguments)}})(jQuery);

File diff suppressed because one or more lines are too long

BIN
public/img/logo_bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

View File

@@ -0,0 +1,123 @@
<div class="row ">
<div class="col-sm-12" >
<div class="pf-dialog-dynamic-area pf-credits-logo-background">
<div id="{{logoContainerId}}" class="text-center">
<svg width="355px" height="366px"id="{{logoSVGId}}">
<filter id = "LogoFilter" width = "150%" height = "150%">
<feOffset result = "offOut" in = "SourceAlpha" dx = "-3" dy = "3"/>
<feGaussianBlur result = "blurOut" in = "offOut" stdDeviation = "3"/>
<feBlend in = "SourceGraphic" in2 = "blurOut" mode = "normal"/>
</filter>
<g id="layer2" filter="url(#LogoFilter)">
<path class="{{logoPartTopRightClass}}" data-animationX="50" data-animationY="-50" d="M226.9 297.1 354.2 365 196 9.7 Z" id="path3353" />
<path class="{{logoPartBottomLeftClass}}" data-animationX="-50" data-animationY="50" d="M73.9 284.9 177.9 287.3 1.6 361.6 Z" id="path3357" id="path3357" />
<path class="{{logoPartBottomRightClass}}" data-animationX="50" data-animationY="50" d="M121.2 317.9 335.6 362.7 193.1 286 Z" id="path3359" />
<path class="{{logoPartTopLeftClass}}" data-animationX="-50" data-animationY="-50" d="M0.2 352.6 94.7 176.7 189.1 0.8 202.8 141.6 Z" id="path3361" />
</g>
</svg>
</div>
</div>
<h1 class="text-center txt-color txt-color-grayLight">
<strong>Pathfinder</strong>
<small>v.0.02 beta</small>
</h1>
<hr>
<blockquote>
<p>
<em class="pf-brand">pathfinder</em> is an open source project. You can view the source code for this project at the link below.
This application is licensed under the <em class="pf-brand">MIT License</em> License. The terms of this license are available at the link below.
In addition there are a number of third party libraries which have been used, as detailed below.
</p>
<small> By Exodus 4D</small>
</blockquote>
<div class="pf-dialog-dynamic-area">
<dl class="dl-horizontal">
<dt class="text-left txt-color txt-color-grayLight">URL <i class="fa fa-lg fa-external-link fa-fw"></i></dt>
<dd><a target="_blank" href="http://www.pathfinder.exodus4d.de/"><em class="pf-brand">pathfinder</em></a></dd>
<dt class="text-left txt-color txt-color-grayLight">Dev Page <i class="fa fa-lg fa-external-link fa-fw"></i></dt>
<dd><a target="_blank" href="http://exodus4d.github.io/pathfinder/"><em class="pf-brand">pathfinder</em> developer</a></dd>
<dt class="text-left txt-color txt-color-grayLight">Source <i class="fa fa-lg fa-github fa-fw"></i></dt>
<dd><a target="_blank" href="https://github.com/exodus4d/pathfinder"><em class="pf-brand">pathfinder</em> repository</a></dd>
<dt class="text-left txt-color txt-color-grayLight">Contact <i class="fa fa-lg fa-google-plus fa-fw"></i></dt>
<dd><a target="_blank" href="https://plus.google.com/u/0/b/110257318165279088853/110257318165279088853/about">Social Media</a></dd>
<dt class="text-left txt-color txt-color-grayLight">Media <i class="fa fa-lg fa-youtube-play fa-fw"></i></dt>
<dd><a target="_blank" href="https://www.youtube.com/channel/UC7HU7XEoMbqRwqxDTbMjSPg">YouTube</a></dd>
<dt class="txt-color txt-color-grayLight">Licence <i class="fa fa-lg fa-certificate fa-fw"></i> </dt>
<dd><a target="_blank" href="http://opensource.org/licenses/MIT"><em class="pf-brand">MIT License</em> (MIT)</a></dd>
</dl>
</div>
<h1 class="text-center txt-color txt-color-grayLight">
<strong>Thanks</strong>
</h1>
<hr>
<table class="table">
<thead>
<tr>
<th>#</th>
<th>URL</th>
<th>Reason</th>
</tr>
</thead>
<tbody>
<tr>
<td>CCP</td>
<td><a target="_blank" href="http://www.ccpgames.com/">http://www.ccpgames.com/</a></td>
<td>Special thanks to CCP for EVE ONLINE and all the dev APIs.</td>
</tr>
<tr>
<td><i class="fa fa-lg fa-fw fa-stack-overflow"></i></td>
<td><a target="_blank" href="http://stackoverflow.com/">http://stackoverflow.com/</a></td>
<td>Special thanks to all user who where answering all of my question.</td>
</tr>
<tr>
<td><i class="fa fa-lg fa-fw fa-codepen"></i></td>
<td><a target="_blank" href="http://codepen.io/">http://codepen.io/</a></td>
<td>Special thanks for delivering such a helpful service.</td>
</tr>
<tr>
<td><i class="fa fa-lg fa-fw fa-jsfiddle"></i></td>
<td><a target="_blank" href="http://jsfiddle.net/">http://jsfiddle.net/</a></td>
<td>Special thanks for delivering such a helpful service.</td>
</tr>
<tr>
<td><i class="fa fa-lg fa-fw fa-html5"></i></td>
<td><a target="_blank" href="http://www.w3.org/TR/html5/">http://www.w3.org/TR/html5/</a></td>
<td>Thanks for all the fancy new specs that made our all life more easier.</td>
</tr>
<tr>
<td><i class="fa fa-lg fa-fw fa-twitter"></i></td>
<td><a target="_blank" href="http://getbootstrap.com/">http://getbootstrap.com/</a></td>
<td>Thanks to TWITTER for supporting and developing Bootstrap.</td>
</tr>
<tr>
<td><i class="fa fa-lg fa-fw fa-github"></i></td>
<td><a target="_blank" href="https://github.com/">https://github.com/</a></td>
<td>Thanks to GitHub for hosting this project.</td>
</tr>
<tr>
<td><i class="fa fa-lg fa-fw fa-reddit"></i></td>
<td><a target="_blank" href="http://www.reddit.com/r/evetech">http://www.reddit.com/r/evetech</a></td>
<td>Thanks to Reddit´s deve tech channel for all the help.</td>
</tr>
<tr>
<td></td>
<td></td>
<td>Thanks to all the OpenSource lovers out there.</td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@@ -20,7 +20,6 @@
<div class="col-sm-10">
<input name="name" type="text" class="form-control" id="name" value="{{formData.name}}" placeholder="My map" data-error="Name required" required>
<span class="help-block with-errors">Set unique map name</span>
</div>
</div>
</div>

View File

@@ -5,7 +5,7 @@
<div class="row">
<div class="col-sm-5">
<div class="form-group">
<label class="col-sm-3 control-label" for="form_system">From</label>
<label class="col-sm-3 control-label">From</label>
<div class="col-sm-9">
<div class=" pull-right">
<p class="form-control-static">
@@ -19,11 +19,10 @@
<div class="col-sm-7">
<div class="form-group">
<label class="col-sm-1 control-label" for="form_system">To</label>
<label class="col-sm-1 control-label" for="to_system">To</label>
<div class="col-sm-11">
<div class="input-group">
<label for="form_system"></label>
<select id="form_system" name="systemTo" class="form-control {{selectClass}}" data-error="Choose a valid system" required/>
<select id="to_system" name="systemTo" class="form-control {{selectClass}}" data-error="Choose a valid system" required/>
<span class="help-block with-errors">Search system name</span>
</div>
</div>

View File

@@ -0,0 +1,197 @@
<div id="{{id}}">
<div role="tabpanel">
<ul class="text-center {{navigationClass}} row" role="tablist">
<li class="col-sm-3 active">
<a class="btn btn-default btn-circle btn-sm" data-toggle="tab" href="#pf-dialog-settings-account">1</a>
<h6>Account Setup</h6>
</li>
<li class="col-sm-3">
<a class="btn btn-default btn-circle btn-sm disabled" data-toggle="tab" href="#pf-dialog-settings-api">2</a>
<h6>API Keys</h6>
</li>
<li class="col-sm-3">
<a class="btn btn-default btn-circle btn-sm disabled" data-toggle="tab" href="#pf-dialog-settings-character">3</a>
<h6>Characters</h6>
</li>
<li class="col-sm-3">
<a class="btn btn-default btn-circle btn-sm disabled" data-toggle="tab" href="#pf-dialog-settings-done">4</a>
<h6>Done</h6>
</li>
</ul>
<hr>
<div class="tab-content">
{{! account tab ================================================================================================ }}
<div role="tabpanel" class="tab-pane fade in active" id="pf-dialog-settings-account">
<form role="form" class="form-horizontal">
<div class="row">
<div class="col-sm-12">
<div class="form-group">
<label class="col-sm-3 control-label">Username</label>
<div class="col-sm-9">
<p class="form-control-static">{{userData.name}}</p>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="form-group">
<label class="col-sm-3 control-label">Email</label>
<div class="col-sm-9">
<p class="form-control-static">
<i class="fa fa-fw fa-lg fa-pencil pull-right pf-dialog-icon-button collapsed" data-toggle="collapse" data-target="#collapseEmail" aria-expanded="false" aria-controls="collapseEmail"></i>
{{userData.email}}
</p>
</div>
</div>
</div>
</div>
<div id="collapseEmail" class="collapse">
<div class="row">
<div class="col-sm-12">
<div class="form-group">
<label for="email" class="col-sm-3 control-label">New Email</label>
<div class="col-sm-6">
<div class="input-group">
<input name="email" type="email" class="form-control" id="email" value="" placeholder="my@mail.com" data-error="Email required">
<span class="input-group-addon"><i class="fa fa-envelope"></i></span>
</div>
<div class="help-block with-errors"></div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="form-group">
<label for="email_confirm" class="col-sm-3 control-label">Confirm Email</label>
<div class="col-sm-6">
<div class="input-group">
<input name="email_confirm" type="email" class="form-control" id="email_confirm" value="" placeholder="my@mail.com" data-error="Email required" data-match="#email" data-match-error="Emall fields do not match">
<span class="input-group-addon"><i class="fa fa-envelope"></i></span>
</div>
<div class="help-block with-errors"></div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="form-group">
<label class="col-sm-3 control-label">Password</label>
<div class="col-sm-9">
<p class="form-control-static">
<i class="fa fa-fw fa-lg fa-pencil pull-right pf-dialog-icon-button collapsed"data-toggle="collapse" data-target="#collapsePassword" aria-expanded="false" aria-controls="collapsePassword"></i>
<i class="fa fa-fw fa-ellipsis-h"></i>
</p>
</div>
</div>
</div>
</div>
<div id="collapsePassword" class="collapse">
<div class="row">
<div class="col-sm-12">
<div class="form-group">
<label for="password" class="col-sm-3 control-label">New Password</label>
<div class="col-sm-6">
<div class="input-group">
<input name="password" type="password" class="form-control" id="password" placeholder="&middot;&middot;&middot;" data-minlength="6" data-minlength-error="Min. of 6 characters">
<span class="input-group-addon"><i class="fa fa-lock"></i></span>
</div>
<div class="help-block with-errors"></div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="form-group">
<label for="password_confirm" class="col-sm-3 control-label">Confirm Password</label>
<div class="col-sm-6">
<div class="input-group">
<input name="password_confirm" type="password" class="form-control" id="password_confirm" placeholder="&middot;&middot;&middot;" data-minlength="6" data-minlength-error="Min. of 6 characters" data-match="#password" data-match-error="Password fields do not match">
<span class="input-group-addon"><i class="fa fa-lock"></i></span>
</div>
<div class="help-block with-errors"></div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
{{! api tab ================================================================================================ }}
<div role="tabpanel" class="tab-pane fade" id="pf-dialog-settings-api">
<form role="form" class="form-horizontal">
{{#userData.api}}
<div class="row {{cloneApiRowClass}}">
<div class="col-sm-4">
<div class="form-group">
<label for="keyId" class="col-sm-4 control-label">Key ID</label>
<div class="col-sm-8">
<input name="keyId[]" type="text" value="{{keyId}}" class="form-control" id="keyId" data-error="Field is required" data-minlength="4" data-minlength-error="Min. of 4 characters" required>
<div class="help-block with-errors"></div>
</div>
</div>
</div>
<div class="col-sm-6">
<div class="form-group">
<label for="vCode" class="col-sm-2 control-label">vCode</label>
<div class="col-sm-10">
<input name="vCode[]" type="text" value="{{vCode}}" class="form-control" id="vCode" data-error="Field is required" data-minlength="64" data-minlength-error="Min. of 64 characters" required>
<div class="help-block with-errors"></div>
</div>
</div>
</div>
<div class="col-sm-2">
<p class="form-control-static">
<i class="fa fa-fw fa-lg fa-plus pull-left pf-dialog-icon-button collapsed {{cloneRowButtonClass}}"></i>
<i class="fa fa-fw fa-lg fa-close pull-right pf-dialog-icon-button collapsed txt-color txt-color-redDarker {{deleteRowButtonClass}}"></i>
</p>
</div>
</div>
{{/userData.api}}
<div class="alert alert-warning" style="display: none;">
<span class="txt-color txt-color-warning">Warning</span>
<small> (important non-critical information)</small>
</div>
</form>
</div>
{{! character tab ================================================================================================ }}
<div role="tabpanel" class="tab-pane fade" id="pf-dialog-settings-character">
<form role="form" class="form-horizontal">
</form>
</div>
{{! finish tab ================================================================================================ }}
<div role="tabpanel" class="tab-pane fade" id="pf-dialog-settings-done">
<form role="form" class="form-horizontal">
<h1 style="opacity: 0;" class="text-center txt-color txt-color-green"><strong><i class="fa fa-check fa-lg"></i> Complete</strong></h1>
<h5 class="text-center">Click next to finish</h5>
</form>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,40 @@
<div class="row text-center">
{{#charactersData}}
<div class="col {{gridClass}}">
<div class="pf-dialog-dynamic-area">
<div data-id="{{characterId}}" class="{{imageWrapperClass}}
{{#isMain}}
{{imageWrapperMainClass}}
{{/isMain}}
">
<div class="pf-dialog-image">
<img class="pf-dialog-character-image" src="https://image.eveonline.com/Character/{{characterId}}_128.jpg" alt="{{characterName}}"/>
<div class="{{imageInfoClass}}">
<div style="width: 128px">
{{#corporation}}
<img src="https://image.eveonline.com/Corporation/{{id}}_32.png"/>
<div class="pf-dialog-character-info-text"><small>{{name}}</small></div>
{{/corporation}}
{{#alliance}}
<img src="https://image.eveonline.com/Alliance/{{id}}_32.png"/>
<div class="pf-dialog-character-info-text"><small>{{name}}</small></div>
{{/alliance}}
</div>
</div>
</div>
<div class="pf-dialog-character-name">
<small>
{{#status}}
<i title="{{label}}" class="fa fa-fw fa-circle pf-user-status {{class}}"></i>
{{/status}}
{{name}}
</small>
</div>
</div>
</div>
</div>
{{/charactersData}}
</div>
<input type="hidden" name="mainCharacterId" value="{{mainCharacter}}">

View File

@@ -1,38 +0,0 @@
<div class="row" id="{{id}}">
<div class="col-sm-12">
<form role="form" class="form-horizontal">
<div class="row text-center">
{{#currentUserData.character}}
<div class="col {{gridClass}}">
<div class="pf-dialog-dynamic-area">
<div data-id="{{characterId}}" class="{{imageWrapperClass}}
{{#isMain}}
{{imageWrapperMainClass}}
{{/isMain}}
">
<div class="pf-dialog-image">
<img class="pf-dialog-character-image" src="https://image.eveonline.com/Character/{{characterId}}_128.jpg" alt="{{characterName}}"/>
<div class="{{imageInfoClass}}">
<div style="width: 128px">
{{#corporationId}}
<img src="https://image.eveonline.com/Corporation/{{corporationId}}_32.png"/>
<div class="pf-dialog-character-info-text"><small>{{corporationName}}</small></div>
{{/corporationId}}
{{#allianceId}}
<img src="https://image.eveonline.com/Alliance/{{allianceId}}_32.png"/>
<div class="pf-dialog-character-info-text"><small>{{allianceName}}</small></div>
{{/allianceId}}
</div>
</div>
</div>
<div class="pf-dialog-character-name"><small>{{characterName}}</small></div>
</div>
</div>
</div>
{{/currentUserData.character}}
</div>
</form>
</div>
</div>

View File

@@ -1,3 +0,0 @@
<div id="{{id}}" title="{{titel}}">
<p>{{content}}</p>
</div>

View File

@@ -3,7 +3,7 @@
<div class="navbar-header pull-left">
<p class="navbar-text txt-color txt-color-gray"><i class="fa fa-copyright"></i>
2015 <a href="https://github.com/exodus4d" target="_blank"><i class="fa fa-github fa-lg fa-fw"></i>Exodus 4D</a>
2015 <a class="{{footerLicenceLinkClass}}" href="javascript:void(0)" target="_blank">Licence</a>
</p>
</div>
<div class="navbar-header pull-right">

View File

@@ -5,13 +5,14 @@
<a class="navbar-brand pf-head-menu" href="#">
<div class={{brandLogo}}></div>&nbsp;&nbsp;Menu
</a>
<p class="navbar-text pf-head-main-character">
<a href="javascript:void(0);" title="set Pilot">
<i class="fa fa-user fa-fw"></i>{{userName}}
<p class="navbar-text {{userCharacterClass}}" title="settings">
<a href="javascript:void(0);">
<img class="{{userCharacterImageClass}}" src=""/>
<span>{{! will be filled with current user data }}</span>
</a>
</p>
<p class="navbar-text pf-head-active-user">
<a href="javascript:void(0);" title="active Pilots">
<p class="navbar-text pf-head-active-user" title="active Pilots">
<a href="javascript:void(0);">
<i class="fa fa-plane fa-fw"></i>active&nbsp;&nbsp;<span class="badge txt-color"></span>
</a>
</p>
@@ -19,8 +20,8 @@
</div>
<div class="navbar-header pull-right">
<p class="navbar-text pf-head-current-location">
<a href="javascript:void(0);" title="current location">
<p class="navbar-text pf-head-current-location" title="current location">
<a href="javascript:void(0);">
<i class="fa fa-map-marker fa-fw"></i><span></span>
</a>
</p>

View File

@@ -0,0 +1,13 @@
<ul class="media-list">
<li class="media">
<a class="pull-left" href="javascript:void(0);">
<img class="pf-head-user-character-image" src="https://image.eveonline.com//Character/93289067_32.jpg">
</a>
<div class="media-body">
<h4 class="media-heading">{{created.characterId}}</h4>
<p>hgfhfghfg</p>
</div>
</li>
</ul>

View File

@@ -26,8 +26,8 @@ $teal-dark: #477372;
$teal-darker: #375959;
$teal-darkest: #212C30;
// green
$green-light: #66c84f;
$green: #5cb85c;
$green-dark: #4f9e4f;
@@ -74,6 +74,7 @@ $system-color-sec-0-8: #00bf39;
$system-color-sec-0-9: #39bf99;
$system-color-sec-1-0: #28c0bf;
// brand colors
$brand-primary: $teal-darker !default;
$brand-success: $green-dark !default;
$brand-info: $blue-dark !default;

View File

@@ -199,7 +199,7 @@ $btn-info-bg: $brand-info;
$btn-info-border: darken($btn-info-bg, 5%);
$btn-warning-color: $gray-lightest;
$btn-warning-bg: $brand-warning;
$btn-warning-bg: $orange-dark;
$btn-warning-border: darken($btn-warning-bg, 5%);
$btn-danger-color: $gray-lightest;

View File

@@ -2,23 +2,120 @@
.modal-content {
// data tables ==========================================
// data tables ==================================================================
.dataTable, .table{
font-size: 10px;
font-family: $font-family-bold;
}
// horizontal line ==============================================================
hr{
margin: 5px 0 15px 0;
border-color: $gray-light;
}
// form wizard ==================================================================
.pf-wizard-navigation{
margin: 0;
li{
&:not(:last-child):before{
border-top: 1px solid $gray-light;
content: "";
display: block;
font-size: 0;
overflow: hidden;
position: relative;
top: 12px;
left: 71px;
right: 1px;
width: 100%;
}
&.finished{
&:before{
@include border-image( linear-gradient(to right, $teal-darker, $teal-darker) 1 1% );
border-bottom: 0;
}
}
&.active{
&:before{
@include border-image( linear-gradient(to right, $brand-success, $gray-light) 1 1% );
border-bottom: 0;
}
}
& > h6{
color: $gray-light;
font-size: 11px;
margin: 5px;
}
a:hover{
& + h6{
color: $gray-lighter;
}
}
&.active a:not(.btn-danger){
@extend .btn-success;
& + h6{
color: $gray-lighter;
}
}
}
}
// buttons ============================================================================
// hide some button until they get triggered by JS
.pf-dialog-finish-button, .pf-dialog-prev-button{
display: none;
}
// icon buttons within a dialog
.pf-dialog-icon-button{
cursor: pointer;
@include transition(color 0.15s ease-out);
will-change: color, transition;
&:not(.collapsed), &:hover{
color: $orange;
}
}
}
// character select dialog ================================
#pf-select-character-dialog{
// settings dialog ======================================================================
#pf-settings-dialog{
// smaller buttons
.form-group .btn-sm{
padding: 4px 7px 3px;
}
// show clone button only on last row
.pf-dialog-api-row:not(:nth-last-child(2)) .pf-dialog-clone-button{
display: none;
}
// show delete button only on last row
.pf-dialog-api-row:first-of-type .pf-dialog-delete-button{
display: none;
}
.pf-dialog-dynamic-area{
display: inline-block;
margin: 10px 5px 20px 5px;
padding: 10px 10px 5px 10px;
@include border-radius(10px);
// character images
.pf-dialog-image-wrapper{
opacity: 0;
width: 128px;
@@ -32,14 +129,29 @@
display: inline-block;
background-color: $gray-darker;
&.pf-dialog-character-main:before{
// not main character star
&:before{
content: "\f005";
font-family: FontAwesome;
position: absolute;
z-index: 10;
left: 6px;
top: 4px;
color: $orange;
color: $gray-lighter;
@include transition(color 0.2s ease-out);
}
&.pf-dialog-character-main{
border-color: $orange-dark;
&:hover{
border-color: $orange;
}
// mein character star
&:before{
color: $orange;
}
}
&:hover{
@@ -52,7 +164,10 @@
.pf-dialog-character-image{
@include filter(grayscale(50%))
}
&:before{
color: $orange;
}
}
@@ -71,7 +186,6 @@
height: 100%;
background: rgba($gray, 0.80);
overflow: hidden;
@include border-top-radius(10px);
will-change: width, transition;
padding: 10px 0;
@@ -95,9 +209,6 @@
}
}
}
}
// map manual dialog ======================================
@@ -121,4 +232,87 @@
background-color: $gray-dark;
overflow: hidden;
@include border-radius(5px);
.dl-horizontal{
margin-bottom: 0;
}
}
// credits dialog =========================================
$logo-stroke-width: 0px;
.pf-credits-dialog{
.pf-credits-logo-background{
overflow: visible;
background: url("#{$base-url}/logo_bg.png");
padding: 20px;
margin-bottom: 20px;
}
#pf-credits-logo-container{
width: 355px;
height: 366px;
margin: 0 auto;
#pf-credits-logo-svg{
opacity: 0;
position: absolute;
z-index: 1; // over hidden logo
overflow: visible; // make sure shadow is visible
path{
will-change: fill, opacity, transform, translate, translateX, translateY;
cursor: pointer;
pointer-events: all;
@include transform( translate3d(0, 0, 0) );
}
}
.logo-ploygon-top-right{
fill: $teal-dark;
fill-rule: evenodd;
stroke: $teal-dark;
stroke-width: $logo-stroke-width;
stroke-linecap: butt;
stroke-linejoin: miter;
stroke-opacity: 1;
fill-opacity: 1;
}
.logo-ploygon-bottom-left{
fill: $green;
fill-rule: evenodd;
stroke: $green;
stroke-width: $logo-stroke-width;
stroke-linecap: butt;
stroke-linejoin: miter;
stroke-opacity: 1;
fill-opacity: 1;
}
.logo-ploygon-bottom-right{
fill: $teal-darker;
fill-rule: evenodd;
stroke: $teal-darker;
stroke-width: $logo-stroke-width;
stroke-linecap: butt;
stroke-linejoin: miter;
stroke-opacity: 1;
fill-opacity: 1;
}
.logo-ploygon-top-left{
fill: $gray-light;
fill-opacity: 1;
fill-rule: evenodd;
stroke: $gray-light;
stroke-width: $logo-stroke-width;
stroke-linecap: butt;
stroke-linejoin: miter;
stroke-opacity: 1;
}
}
}

View File

@@ -11,6 +11,8 @@ body{
a{
color: $teal-dark;
will-change: color;
@include transition( color 0.08s ease-out );
&:hover{
color: $teal-light;
@@ -212,6 +214,19 @@ em{
}
// User status =================================================
.pf-user-status{
color: $red-darker;
}
.pf-user-status-corp{
color: $green;
}
.pf-user-status-ally{
color: $blue;
}
// WH effects ==================================================
.pf-system-effect{
@@ -473,7 +488,16 @@ em{
padding: 5px 5px;
@include border-radius(3px);
@include box-shadow(0 6px 12px rgba(0,0,0,.4));
}
// tooltips within modals
.modal .tooltip{
// higher z-index
z-index: $zindex-modal + 10;
.tooltip-inner{
color: $gray-lighter;
}
}
.tooltip.top .tooltip-arrow,{
@@ -511,9 +535,15 @@ em{
margin-bottom: 0px;
a{
@include transition( color 0.15s ease-out );
will-change: color;
&:focus{
color: $teal-dark;
img{
border-color: $gray;
}
}
&:hover{
@@ -522,6 +552,10 @@ em{
.badge{
color: $teal-light;
}
img{
border-color: $teal;
}
}
}
@@ -553,6 +587,12 @@ em{
color: $gray-lighter;
}
.pf-head-user-character{
opacity: 0; // triggered by js
visibility: 'hidden';
}
.pf-head-active-user, .pf-head-current-location{
display: none; // triggered by js
@@ -560,11 +600,29 @@ em{
@include transition( color 0.3s ease-out );
}
}
.pf-head-user-character-image{
display: inline-block;
margin-top: -6px;
margin-bottom: -6px;
width: 27px;
border: 1px solid $gray;
margin-right: 3px;
@include transition( border-color 0.15s ease-out );
will-change: border-color;
}
.pf-head-program-status{
cursor: pointer;
}
// tooltips header
.tooltip{
.tooltip-inner{
color: $gray-lighter;
}
}
}
// footer =======================================================

View File

@@ -48,7 +48,7 @@ $mapWidth: 2500px;
border: {
width: 1px;
style: solid;
color: $gray-lighter;
color: $gray-dark;
}
}
}
@@ -200,15 +200,6 @@ $mapWidth: 2500px;
.pf-user-status{
font-size: 7px;
}
.pf-user-status-corp{
color: $green;
}
.pf-user-status-ally{
color: $blue;
}
}
}

View File

@@ -9,12 +9,6 @@
text-transform: capitalize;
}
}
// system info table =====================================================
.pf-system-info-table{
padding-right: 7px;
font-family: $font-family-bold;
}
}
// signature table module ===================================================

View File

@@ -11,9 +11,9 @@
&.txt-color-grayLight { color: $gray-light !important; }
&.txt-color-gray { color: $gray !important; }
&.txt-color-grayDark { color: $gray-dark !important; }
&.txt-color-greenLight { color: $green-light !important; }
&.txt-color-green { color: $green !important; }
&.txt-color-greenLight { color: $greenLight !important; }
&.txt-color-greenDark { color: $greenDark !important; }
&.txt-color-greenDark { color: $green-dark !important; }
&.txt-color-redLight { color: $redLight !important; }
&.txt-color-red { color: $red !important; }
&.txt-color-redDarker { color: $red-darker !important; }

View File

@@ -540,17 +540,7 @@ h6 {
}
.input-group-addon {
transition: border-color 0.3s;
-o-transition: border-color 0.3s;
-ms-transition: border-color 0.3s;
-moz-transition: border-color 0.3s;
-webkit-transition: border-color 0.3s;
transition: background-color 0.3s;
-o-transition: background-color 0.3s;
-ms-transition: background-color 0.3s;
-moz-transition: background-color 0.3s;
-webkit-transition: background-color 0.3s;
@include transition(border-color ease-in-out .15s, color ease-in-out .15s);
}
.input-group-addon .fa {
@@ -567,9 +557,9 @@ h6 {
input[type="text"]:focus + .input-group-addon {
border-color: $blueSky;
background-color: lighten($state-info-text, 23%);
color:$white;
border-color: $teal;
//background-color: lighten($state-info-text, 23%);
color: $teal;
}
.has-warning input[type="text"], .has-warning input[type="text"] + .input-group-addon {
@@ -586,8 +576,8 @@ input[type="text"]:focus + .input-group-addon {
}
.has-error .input-group-addon {
border-color: $state-danger-border;
background:$state-danger-bg;
border-color: $red;
background:$red;
color:$state-danger-text;
}
.has-error input[type="text"], .has-error input[type="text"] + .input-group-addon {
@@ -1299,7 +1289,7 @@ input[type="text"]:focus + .input-group-addon {
color:$white;
}
.btn-default.disabled {
color:$gray-light;
color: $gray-lighter;
}
.btn {
@@ -1500,6 +1490,17 @@ input[type="text"]:focus + .input-group-addon {
border-radius: 50%;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
@include box-shadow(none !important);
}
.btn-circle.btn-sm {
width: 22px;
height: 22px;
padding: 4px 0;
font-size: 12px;
line-height: 14px;
border-radius: 50%;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
}
.btn-circle.btn-lg {
width: 50px;