- New "Intel module" for Citadel tracking, closed #246
- updated "Select2" js lib `4.0.3` -> `4.0.6-rc.1` - fixed some login Issues - fixed broken `map/*` reroute URL wildcard replacement - fixed broken cache layer for Universe models
This commit is contained in:
@@ -6,7 +6,8 @@
|
||||
* Time: 17:42
|
||||
*/
|
||||
|
||||
namespace controller\api;
|
||||
namespace Controller\Api;
|
||||
|
||||
use Controller;
|
||||
use Model;
|
||||
|
||||
@@ -20,15 +21,14 @@ class Access extends Controller\AccessController {
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function search($f3, $params){
|
||||
|
||||
$accessData = [];
|
||||
|
||||
if(
|
||||
array_key_exists( 'arg1', $params) &&
|
||||
array_key_exists( 'arg2', $params)
|
||||
array_key_exists('arg1', $params) &&
|
||||
array_key_exists('arg2', $params)
|
||||
){
|
||||
$searchType = strtolower( $params['arg1'] );
|
||||
$searchToken = strtolower( $params['arg2'] );
|
||||
$searchType = strtolower($params['arg1']);
|
||||
$searchToken = strtolower($params['arg2']);
|
||||
|
||||
$accessModel = null;
|
||||
switch($searchType){
|
||||
@@ -59,13 +59,9 @@ class Access extends Controller\AccessController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
echo json_encode($accessData);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -70,7 +70,6 @@ class Map extends Controller\AccessController {
|
||||
|
||||
// default map type config
|
||||
$mapsDefaultConfig = Config::getMapsDefaultConfig();
|
||||
|
||||
$mapTypeData = [];
|
||||
foreach((array)$rows as $rowData){
|
||||
$data = [
|
||||
@@ -81,7 +80,6 @@ class Map extends Controller\AccessController {
|
||||
'defaultConfig' => $mapsDefaultConfig[$rowData->name]
|
||||
];
|
||||
$mapTypeData[$rowData->name] = $data;
|
||||
|
||||
}
|
||||
$return->mapTypes = $mapTypeData;
|
||||
|
||||
@@ -190,6 +188,17 @@ class Map extends Controller\AccessController {
|
||||
'status' => (bool)Config::getPathfinderData('discord.status')
|
||||
];
|
||||
|
||||
// structure status ---------------------------------------------------------------------------------------
|
||||
$structureStatus = Model\StructureStatusModel::getAll();
|
||||
$structureData = [];
|
||||
foreach($structureStatus as $status){
|
||||
$structureData[$status->_id] = $status->getData();
|
||||
}
|
||||
$return->structureStatus = $structureData;
|
||||
|
||||
// universe category data ---------------------------------------------------------------------------------
|
||||
$return->universeCategories = [65 => Model\Universe\BasicUniverseModel::getNew('CategoryModel')->getById(65)->getData()];
|
||||
|
||||
$f3->set(self::CACHE_KEY_INIT, $return, $expireTimeCache );
|
||||
}
|
||||
|
||||
|
||||
80
app/main/controller/api/structure.php
Normal file
80
app/main/controller/api/structure.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: exodu
|
||||
* Date: 24.04.2018
|
||||
* Time: 22:23
|
||||
*/
|
||||
|
||||
namespace Controller\Api;
|
||||
|
||||
use Controller;
|
||||
use Model;
|
||||
use Exception;
|
||||
|
||||
class Structure extends Controller\AccessController {
|
||||
|
||||
/**
|
||||
* save/update structure
|
||||
* @param \Base $f3
|
||||
* @throws Exception
|
||||
*/
|
||||
public function save(\Base $f3){
|
||||
$structureData = (array)$f3->get('POST');
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
$return = (object) [];
|
||||
$return->error = [];
|
||||
|
||||
/**
|
||||
* @var $structure Model\StructureModel
|
||||
*/
|
||||
$structure = Model\BasicModel::getNew('StructureModel');
|
||||
$structure->getById((int)$structureData['id']);
|
||||
|
||||
if($structure->dry() || $structure->hasAccess($activeCharacter)){
|
||||
$newStructure = $structure->dry();
|
||||
try{
|
||||
$structure->copyfrom($structureData, ['structureId', 'corporationId', 'systemId', 'statusId', 'name', 'description']);
|
||||
$structure->save();
|
||||
|
||||
if($newStructure){
|
||||
$activeCharacter->getCorporation()->saveStructure($structure);
|
||||
}
|
||||
$return->structures = $structure->getDataByCorporations();
|
||||
}catch(Exception\ValidationException $e){
|
||||
$return->error[] = $e->getError();
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* delete structure
|
||||
* @param \Base $f3
|
||||
* @throws Exception
|
||||
*/
|
||||
public function delete(\Base $f3){
|
||||
$structureData = (array)$f3->get('POST');
|
||||
$structureId = (int)$structureData['id'];
|
||||
|
||||
$return = (object) [];
|
||||
|
||||
if($structureId){
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
/**
|
||||
* @var $structure Model\StructureModel
|
||||
*/
|
||||
$structure = Model\BasicModel::getNew('StructureModel');
|
||||
$structure->getById($structureId);
|
||||
if($structure->hasAccess($activeCharacter) && $structure->erase()){
|
||||
$return->deletedStructureIds = [$structureId];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
echo json_encode($return);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
namespace Controller\Api;
|
||||
|
||||
use Controller;
|
||||
use Data\Mapper as Mapper;
|
||||
use lib\Config;
|
||||
@@ -441,6 +442,30 @@ class System extends Controller\AccessController {
|
||||
echo json_encode($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Base $f3
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getData(\Base $f3){
|
||||
$requestData = (array)$f3->get('POST');
|
||||
$mapId = (int)$requestData['mapId'];
|
||||
$systemId = (int)$requestData['systemId'];
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
$return = (object) [];
|
||||
|
||||
if(
|
||||
!is_null($map = $activeCharacter->getMap($mapId)) &&
|
||||
!is_null($system = $map->getSystemById($systemId))
|
||||
){
|
||||
$return->system = $system->getData();
|
||||
$return->system->signatures = $system->getSignaturesData();
|
||||
$return->system->structures = $system->getStructuresData();
|
||||
}
|
||||
|
||||
echo json_encode($return);
|
||||
}
|
||||
|
||||
/**
|
||||
* delete systems and all its connections from map
|
||||
* -> set "active" flag
|
||||
|
||||
36
app/main/controller/api/universe.php
Normal file
36
app/main/controller/api/universe.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: exodu
|
||||
* Date: 21.04.2018
|
||||
* Time: 15:49
|
||||
*/
|
||||
|
||||
namespace Controller\Api;
|
||||
|
||||
use Controller;
|
||||
use Controller\Ccp as Ccp;
|
||||
|
||||
class Universe extends Controller\AccessController {
|
||||
|
||||
/**
|
||||
* search static Universe data by string within categories
|
||||
* @param \Base $f3
|
||||
* @param $params
|
||||
*/
|
||||
public function search(\Base $f3, $params){
|
||||
$postData = (array)$f3->get('POST');
|
||||
$categories = (array)$postData['categories'];
|
||||
$universeNameData = [];
|
||||
|
||||
if(
|
||||
array_key_exists('arg1', $params) &&
|
||||
!empty($search = strtolower($params['arg1'])) &&
|
||||
!empty($categories)
|
||||
){
|
||||
$universeNameData = Ccp\Universe::searchUniverseNameData($categories, $search);
|
||||
}
|
||||
|
||||
echo json_encode($universeNameData);
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,7 @@ class Sso extends Api\User{
|
||||
const ERROR_VERIFY_CHARACTER = 'Unable to verify character data. %s';
|
||||
const ERROR_LOGIN_FAILED = 'Failed authentication due to technical problems: %s';
|
||||
const ERROR_CHARACTER_VERIFICATION = 'Character verification failed by SSP SSO';
|
||||
const ERROR_CHARACTER_DATA = 'Failed to load characterData from ESI';
|
||||
const ERROR_CHARACTER_FORBIDDEN = 'Character "%s" is not authorized to log in. Reason: %s';
|
||||
const ERROR_SERVICE_TIMEOUT = 'CCP SSO service timeout (%ss). Try again later';
|
||||
const ERROR_COOKIE_LOGIN = 'Login from Cookie failed. Please retry by CCP SSO';
|
||||
@@ -207,7 +208,7 @@ class Sso extends Api\User{
|
||||
// verification available data. Data is needed for "ownerHash" check
|
||||
|
||||
// get character data from ESI
|
||||
$characterData = $this->getCharacterData($verificationCharacterData->CharacterID);
|
||||
$characterData = $this->getCharacterData((int)$verificationCharacterData->CharacterID);
|
||||
|
||||
if( isset($characterData->character) ){
|
||||
// add "ownerHash" and SSO tokens
|
||||
@@ -281,6 +282,9 @@ class Sso extends Api\User{
|
||||
);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// failed to load characterData from API
|
||||
$f3->set(self::SESSION_KEY_SSO_ERROR, self::ERROR_CHARACTER_DATA);
|
||||
}
|
||||
}else{
|
||||
// failed to verify character by CCP SSO
|
||||
@@ -325,7 +329,7 @@ class Sso extends Api\User{
|
||||
$loginCheck = $this->loginByCharacter($character);
|
||||
if($loginCheck){
|
||||
// route to "map"
|
||||
$f3->reroute(['map']);
|
||||
$f3->reroute($f3->alias('map','*= ') );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,67 +498,44 @@ class Sso extends Api\User{
|
||||
/**
|
||||
* get character data
|
||||
* @param int $characterId
|
||||
* @return object
|
||||
* @return \stdClass
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getCharacterData($characterId){
|
||||
public function getCharacterData(int $characterId) : \stdClass{
|
||||
$characterData = (object) [];
|
||||
|
||||
$characterDataBasic = $this->getF3()->ccpClient->getCharacterData($characterId);
|
||||
if($characterId){
|
||||
$characterDataBasic = $this->getF3()->ccpClient->getCharacterData($characterId);
|
||||
|
||||
if( !empty($characterDataBasic) ){
|
||||
// remove some "unwanted" data -> not relevant for Pathfinder
|
||||
$characterData->character = array_filter($characterDataBasic, function($key){
|
||||
return in_array($key, ['id', 'name', 'securityStatus']);
|
||||
}, ARRAY_FILTER_USE_KEY);
|
||||
if( !empty($characterDataBasic) ){
|
||||
// remove some "unwanted" data -> not relevant for Pathfinder
|
||||
$characterData->character = array_filter($characterDataBasic, function($key){
|
||||
return in_array($key, ['id', 'name', 'securityStatus']);
|
||||
}, ARRAY_FILTER_USE_KEY);
|
||||
|
||||
$characterData->corporation = null;
|
||||
$characterData->alliance = null;
|
||||
$characterData->corporation = null;
|
||||
$characterData->alliance = null;
|
||||
|
||||
if(isset($characterDataBasic['corporation'])){
|
||||
$corporationId = (int)$characterDataBasic['corporation']['id'];
|
||||
|
||||
/**
|
||||
* @var Model\CorporationModel $corporationModel
|
||||
*/
|
||||
$corporationModel = Model\BasicModel::getNew('CorporationModel');
|
||||
$corporationModel->getById($corporationId, 0);
|
||||
|
||||
if($corporationModel->dry()){
|
||||
// request corporation data
|
||||
$corporationData = $this->getF3()->ccpClient->getCorporationData($corporationId);
|
||||
|
||||
if( !empty($corporationData) ){
|
||||
// check for NPC corporation
|
||||
$corporationData['isNPC'] = $this->getF3()->ccpClient->isNpcCorporation($corporationId);
|
||||
|
||||
$corporationModel->copyfrom($corporationData, ['id', 'name', 'isNPC']);
|
||||
$characterData->corporation = $corporationModel->save();
|
||||
if($corporationId = (int)$characterDataBasic['corporation']['id']){
|
||||
/**
|
||||
* @var Model\CorporationModel $corporation
|
||||
*/
|
||||
$corporation = Model\BasicModel::getNew('CorporationModel');
|
||||
$corporation->getById($corporationId, 0);
|
||||
if( !$corporation->dry() ){
|
||||
$characterData->corporation = $corporation;
|
||||
}
|
||||
}else{
|
||||
$characterData->corporation = $corporationModel;
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($characterDataBasic['alliance'])){
|
||||
$allianceId = (int)$characterDataBasic['alliance']['id'];
|
||||
|
||||
/**
|
||||
* @var Model\AllianceModel $allianceModel
|
||||
*/
|
||||
$allianceModel = Model\BasicModel::getNew('AllianceModel');
|
||||
$allianceModel->getById($allianceId, 0);
|
||||
|
||||
if($allianceModel->dry()){
|
||||
// request alliance data
|
||||
$allianceData = $this->getF3()->ccpClient->getAllianceData($allianceId);
|
||||
|
||||
if( !empty($allianceData) ){
|
||||
$allianceModel->copyfrom($allianceData, ['id', 'name']);
|
||||
$characterData->alliance = $allianceModel->save();
|
||||
if($allianceId = (int)$characterDataBasic['alliance']['id']){
|
||||
/**
|
||||
* @var Model\AllianceModel $allianceModel
|
||||
*/
|
||||
$alliance = Model\BasicModel::getNew('AllianceModel');
|
||||
$alliance->getById($allianceId, 0);
|
||||
if( !$alliance->dry() ){
|
||||
$characterData->alliance = $alliance;
|
||||
}
|
||||
}else{
|
||||
$characterData->alliance = $allianceModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -564,29 +545,29 @@ class Sso extends Api\User{
|
||||
|
||||
/**
|
||||
* update character
|
||||
* @param $characterData
|
||||
* @return \Model\CharacterModel
|
||||
* @param \stdClass $characterData
|
||||
* @return \Model\CharacterModel|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function updateCharacter($characterData){
|
||||
$characterModel = null;
|
||||
protected function updateCharacter(\stdClass $characterData){
|
||||
$character = null;
|
||||
|
||||
if( !empty($characterData->character) ){
|
||||
|
||||
/**
|
||||
* @var Model\CharacterModel $characterModel
|
||||
* @var Model\CharacterModel $character
|
||||
*/
|
||||
$characterModel = Model\BasicModel::getNew('CharacterModel');
|
||||
$characterModel->getById((int)$characterData->character['id'], 0);
|
||||
$characterModel->copyfrom($characterData->character, [
|
||||
$character = Model\BasicModel::getNew('CharacterModel');
|
||||
$character->getById((int)$characterData->character['id'], 0);
|
||||
$character->copyfrom($characterData->character, [
|
||||
'id', 'name', 'ownerHash', 'crestAccessToken', 'crestRefreshToken', 'esiScopes', 'securityStatus'
|
||||
]);
|
||||
$characterModel->corporationId = $characterData->corporation;
|
||||
$characterModel->allianceId = $characterData->alliance;
|
||||
$characterModel = $characterModel->save();
|
||||
|
||||
$character->corporationId = $characterData->corporation;
|
||||
$character->allianceId = $characterData->alliance;
|
||||
$character = $character->save();
|
||||
}
|
||||
|
||||
return $characterModel;
|
||||
return $character;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,7 +10,8 @@ namespace Controller\Ccp;
|
||||
|
||||
|
||||
use Controller\Controller;
|
||||
use Model\BasicModel;
|
||||
use lib\Util;
|
||||
use Model;
|
||||
|
||||
class Universe extends Controller {
|
||||
|
||||
@@ -20,8 +21,9 @@ class Universe extends Controller {
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function setupDB(\Base $f3){
|
||||
$this->setupRegions($f3);
|
||||
$this->setupConstellations($f3);
|
||||
//$this->setupRegions($f3);
|
||||
//$this->setupConstellations($f3);
|
||||
//$this->setupCategories($f3);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,4 +95,54 @@ class Universe extends Controller {
|
||||
$constellationModel->reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Base $f3
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function setupCategories(\Base $f3){
|
||||
$categoryIdsWhitelist = [
|
||||
6, // Ship
|
||||
65 // Structure
|
||||
];
|
||||
$categoryIds = $f3->ccpClient->getUniverseCategories();
|
||||
$categoryIds = array_intersect ($categoryIdsWhitelist, $categoryIds);
|
||||
$categoryModel = Model\Universe\BasicUniverseModel::getNew('CategoryModel');
|
||||
foreach($categoryIds as $categoryId){
|
||||
$categoryModel->loadById($categoryId);
|
||||
$categoryModel->loadGroupsData();
|
||||
|
||||
foreach((array)$categoryModel->groups as $group){
|
||||
$group->loadTypesData();
|
||||
}
|
||||
|
||||
$categoryModel->reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* search universeName data by search term
|
||||
* @param array $categories
|
||||
* @param string $search
|
||||
* @param bool $strict
|
||||
* @return array
|
||||
*/
|
||||
public static function searchUniverseNameData(array $categories, string $search, bool $strict = false) : array {
|
||||
$f3 = \Base::instance();
|
||||
$universeNameData = [];
|
||||
|
||||
if( !empty($categories) && !empty($search)){
|
||||
$universeIds = $f3->ccpClient->search($categories, $search, $strict);
|
||||
if(isset($universeIds['error'])){
|
||||
// ESI error
|
||||
$universeNameData = $universeIds;
|
||||
}elseif( !empty($universeIds) ){
|
||||
$universeIds = Util::arrayFlattenByValue($universeIds);
|
||||
$universeNameData = $f3->ccpClient->getUniverseNamesData($universeIds);
|
||||
}
|
||||
}
|
||||
|
||||
return $universeNameData;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -69,15 +69,18 @@ class Setup extends Controller {
|
||||
'Model\WormholeModel',
|
||||
'Model\RightModel',
|
||||
'Model\RoleModel',
|
||||
'Model\StructureModel',
|
||||
|
||||
'Model\CharacterStatusModel',
|
||||
'Model\ConnectionScopeModel',
|
||||
'Model\StructureStatusModel',
|
||||
|
||||
'Model\CharacterMapModel',
|
||||
'Model\AllianceMapModel',
|
||||
'Model\CorporationMapModel',
|
||||
|
||||
'Model\CorporationRightModel',
|
||||
'Model\CorporationStructureModel',
|
||||
|
||||
'Model\UserCharacterModel',
|
||||
'Model\CharacterModel',
|
||||
@@ -105,6 +108,8 @@ class Setup extends Controller {
|
||||
'info' => [],
|
||||
'models' => [
|
||||
'Model\Universe\TypeModel',
|
||||
'Model\Universe\GroupModel',
|
||||
'Model\Universe\CategoryModel',
|
||||
'Model\Universe\StructureModel',
|
||||
//'Model\Universe\RegionModel',
|
||||
//'Model\Universe\ConstellationModel'
|
||||
|
||||
@@ -65,8 +65,10 @@ class AbstractIterator extends \RecursiveArrayIterator {
|
||||
$mapValue = static::$map[$iterator->key()];
|
||||
|
||||
// check for mapping key
|
||||
if($iterator->hasChildren()){
|
||||
|
||||
if(
|
||||
$iterator->hasChildren() &&
|
||||
Util::is_assoc($iterator->current())
|
||||
){
|
||||
// recursive call for child elements
|
||||
$iterator->offsetSet($iterator->key(), forward_static_call(array('self', __METHOD__), $iterator->getChildren())->getArrayCopy());
|
||||
$iterator->next();
|
||||
|
||||
@@ -29,12 +29,23 @@ class Util {
|
||||
}
|
||||
|
||||
/**
|
||||
* flatten multidimensional array
|
||||
* flatten multidimensional array ignore keys
|
||||
* @param array $array
|
||||
* @return array
|
||||
*/
|
||||
static function arrayFlattenByValue(array $array) : array {
|
||||
$return = [];
|
||||
array_walk_recursive($array, function($value) use (&$return) { $return[] = $value; });
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* flatten multidimensional array merge keys
|
||||
* -> overwrites duplicate keys!
|
||||
* @param array $array
|
||||
* @return array
|
||||
*/
|
||||
static function arrayFlatten(array $array) : array {
|
||||
static function arrayFlattenByKey(array $array) : array {
|
||||
$return = [];
|
||||
array_walk_recursive($array, function($value, $key) use (&$return) { $return[$key] = $value; });
|
||||
return $return;
|
||||
|
||||
@@ -27,6 +27,11 @@ class AllianceModel extends BasicModel {
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'ticker' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'shared' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
@@ -35,6 +40,9 @@ class AllianceModel extends BasicModel {
|
||||
'allianceCharacters' => [
|
||||
'has-many' => ['Model\CharacterModel', 'allianceId']
|
||||
],
|
||||
'alliancCorporations' => [
|
||||
'has-many' => ['Model\CharacterModel', 'allianceId']
|
||||
],
|
||||
'mapAlliances' => [
|
||||
'has-many' => ['Model\AllianceMapModel', 'allianceId']
|
||||
]
|
||||
@@ -54,6 +62,21 @@ class AllianceModel extends BasicModel {
|
||||
return $allianceData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* return false will stop any further action
|
||||
* @param self $self
|
||||
* @param $pkeys
|
||||
* @return bool
|
||||
*/
|
||||
public function beforeUpdateEvent($self, $pkeys){
|
||||
// if model changed, 'update' col needs to be updated as well
|
||||
// -> data no longer "outdated"
|
||||
$this->touch('updated');
|
||||
|
||||
return parent::beforeUpdateEvent($self, $pkeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* get all maps for this alliance
|
||||
* @return array|mixed
|
||||
@@ -87,9 +110,9 @@ class AllianceModel extends BasicModel {
|
||||
* get all characters in this alliance
|
||||
* @param array $characterIds
|
||||
* @param array $options
|
||||
* @return array
|
||||
* @return CharacterModel[]
|
||||
*/
|
||||
public function getCharacters($characterIds = [], $options = []){
|
||||
public function getCharacters($characterIds = [], $options = []) : array {
|
||||
$characters = [];
|
||||
$filter = ['active = ?', 1];
|
||||
|
||||
@@ -114,4 +137,21 @@ class AllianceModel extends BasicModel {
|
||||
|
||||
return $characters;
|
||||
}
|
||||
|
||||
public function getById(int $id, int $ttl = self::DEFAULT_SQL_TTL, bool $isActive = true){
|
||||
/**
|
||||
* @var AllianceModel $alliance
|
||||
*/
|
||||
$alliance = parent::getById($id, $ttl, $isActive);
|
||||
if($alliance->isOutdated()){
|
||||
// request alliance data
|
||||
$allianceData = self::getF3()->ccpClient->getAllianceData($id);
|
||||
if( !empty($allianceData) ){
|
||||
$alliance->copyfrom($allianceData, ['id', 'name', 'ticker']);
|
||||
$alliance->save();
|
||||
}
|
||||
}
|
||||
|
||||
return $alliance;
|
||||
}
|
||||
}
|
||||
@@ -104,6 +104,11 @@ abstract class BasicModel extends \DB\Cortex {
|
||||
*/
|
||||
const DEFAULT_CACHE_TTL = 120;
|
||||
|
||||
/**
|
||||
* default TTL for SQL query cache
|
||||
*/
|
||||
const DEFAULT_SQL_TTL = 3;
|
||||
|
||||
const ERROR_INVALID_MODEL_CLASS = 'Model class (%s) not found';
|
||||
|
||||
public function __construct($db = NULL, $table = NULL, $fluid = NULL, $ttl = 0){
|
||||
@@ -464,7 +469,7 @@ abstract class BasicModel extends \DB\Cortex {
|
||||
* @param bool $isActive
|
||||
* @return \DB\Cortex
|
||||
*/
|
||||
public function getById(int $id, int $ttl = 3, bool $isActive = true){
|
||||
public function getById(int $id, int $ttl = self::DEFAULT_SQL_TTL, bool $isActive = true){
|
||||
return $this->getByForeignKey('id', (int)$id, ['limit' => 1], $ttl, $isActive);
|
||||
}
|
||||
|
||||
@@ -763,6 +768,28 @@ abstract class BasicModel extends \DB\Cortex {
|
||||
return $this->validationError;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks whether data is outdated and should be refreshed
|
||||
* @return bool
|
||||
*/
|
||||
protected function isOutdated(): bool {
|
||||
$outdated = true;
|
||||
if(!$this->dry()){
|
||||
$timezone = $this->getF3()->get('getTimeZone')();
|
||||
$currentTime = new \DateTime('now', $timezone);
|
||||
$updateTime = \DateTime::createFromFormat(
|
||||
'Y-m-d H:i:s',
|
||||
$this->updated,
|
||||
$timezone
|
||||
);
|
||||
$interval = $updateTime->diff($currentTime);
|
||||
if($interval->days < Universe\BasicUniverseModel::CACHE_MAX_DAYS){
|
||||
$outdated = false;
|
||||
}
|
||||
}
|
||||
return $outdated;
|
||||
}
|
||||
|
||||
public function save(){
|
||||
try{
|
||||
return parent::save();
|
||||
|
||||
@@ -181,7 +181,7 @@ class CharacterModel extends BasicModel {
|
||||
// no cached character data found
|
||||
|
||||
$characterData = (object) [];
|
||||
$characterData->id = $this->id;
|
||||
$characterData->id = $this->_id;
|
||||
$characterData->name = $this->name;
|
||||
$characterData->role = $this->roleId->getData();
|
||||
$characterData->shared = $this->shared;
|
||||
|
||||
@@ -379,7 +379,7 @@ class ConnectionModel extends AbstractMapTrackingModel {
|
||||
* get all connection log data linked to this connection
|
||||
* @return array
|
||||
*/
|
||||
public function getLogsData() : array{
|
||||
public function getLogsData() : array {
|
||||
$logsData = [];
|
||||
$logs = $this->getLogs();
|
||||
|
||||
|
||||
@@ -103,6 +103,16 @@ class CorporationModel extends BasicModel {
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'ticker' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'memberCount' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
],
|
||||
'shared' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
@@ -121,6 +131,12 @@ class CorporationModel extends BasicModel {
|
||||
],
|
||||
'corporationRights' => [
|
||||
'has-many' => ['Model\CorporationRightModel', 'corporationId']
|
||||
],
|
||||
'corporationStructures' => [
|
||||
'has-many' => ['Model\CorporationStructureModel', 'corporationId']
|
||||
],
|
||||
'structures' => [
|
||||
'has-many' => ['Model\StructureModel', 'corporationId']
|
||||
]
|
||||
];
|
||||
|
||||
@@ -145,6 +161,21 @@ class CorporationModel extends BasicModel {
|
||||
return $cooperationData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* return false will stop any further action
|
||||
* @param self $self
|
||||
* @param $pkeys
|
||||
* @return bool
|
||||
*/
|
||||
public function beforeUpdateEvent($self, $pkeys){
|
||||
// if model changed, 'update' col needs to be updated as well
|
||||
// -> data no longer "outdated"
|
||||
$this->touch('updated');
|
||||
|
||||
return parent::beforeUpdateEvent($self, $pkeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* get all maps for this corporation
|
||||
* @param array $mapIds
|
||||
@@ -210,6 +241,38 @@ class CorporationModel extends BasicModel {
|
||||
return $characters;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all structure data for this corporation
|
||||
* @param array $systemIds
|
||||
* @return array
|
||||
*/
|
||||
public function getStructuresData(array $systemIds = []) : array {
|
||||
$structuresData = [];
|
||||
|
||||
$this->filter('corporationStructures', ['active = ?', 1]);
|
||||
$this->has('corporationStructures.structureId', ['active = ?', 1]);
|
||||
|
||||
if($systemIds){
|
||||
if(count($systemIds) == 1){
|
||||
$filterSystems = 'systemId = ?';
|
||||
$filterSystemIds = reset($systemIds);
|
||||
}else{
|
||||
$filterSystems = 'systemId IN (?)';
|
||||
$filterSystemIds = $systemIds;
|
||||
}
|
||||
|
||||
$this->has('corporationStructures.structureId', [$filterSystems, $filterSystemIds]);
|
||||
}
|
||||
|
||||
if($this->corporationStructures) {
|
||||
foreach($this->corporationStructures as $corporationStructure){
|
||||
$structuresData[] = $corporationStructure->structureId->getData();
|
||||
}
|
||||
}
|
||||
|
||||
return $structuresData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get roles for each character in this corp
|
||||
* -> CCP API call
|
||||
@@ -272,6 +335,46 @@ class CorporationModel extends BasicModel {
|
||||
return $corporationRights;
|
||||
}
|
||||
|
||||
/**
|
||||
* load corporation by Id either from DB or load data from API
|
||||
* @param int $id
|
||||
* @param int $ttl
|
||||
* @param bool $isActive
|
||||
* @return \DB\Cortex
|
||||
*/
|
||||
public function getById(int $id, int $ttl = self::DEFAULT_SQL_TTL, bool $isActive = true){
|
||||
/**
|
||||
* @var CorporationModel $corporation
|
||||
*/
|
||||
$corporation = parent::getById($id, $ttl, $isActive);
|
||||
if($corporation->isOutdated()){
|
||||
// request corporation data
|
||||
$corporationData = self::getF3()->ccpClient->getCorporationData($id);
|
||||
if( !empty($corporationData) ){
|
||||
// check for NPC corporation
|
||||
$corporationData['isNPC'] = self::getF3()->ccpClient->isNpcCorporation($id);
|
||||
|
||||
$corporation->copyfrom($corporationData, ['id', 'name', 'ticker', 'memberCount', 'isNPC']);
|
||||
$corporation->save();
|
||||
}
|
||||
}
|
||||
|
||||
return $corporation;
|
||||
}
|
||||
|
||||
/**
|
||||
* add new structure for this corporation
|
||||
* @param StructureModel $structure
|
||||
*/
|
||||
public function saveStructure(StructureModel $structure){
|
||||
if( !$structure->dry() ){
|
||||
$corporationStructure = $this->rel('corporationStructures');
|
||||
$corporationStructure->corporationId = $this;
|
||||
$corporationStructure->structureId = $structure;
|
||||
$corporationStructure->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get all corporations
|
||||
* @param array $options
|
||||
|
||||
65
app/main/model/corporationstructuremodel.php
Normal file
65
app/main/model/corporationstructuremodel.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: exodu
|
||||
* Date: 15.04.2018
|
||||
* Time: 19:23
|
||||
*/
|
||||
|
||||
namespace Model;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class CorporationStructureModel extends BasicModel {
|
||||
|
||||
protected $table = 'corporation_structure';
|
||||
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 1,
|
||||
'index' => true
|
||||
],
|
||||
'corporationId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\CorporationModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'corporation',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'structureId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\StructureModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'structure',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* overwrites parent
|
||||
* @param null $db
|
||||
* @param null $table
|
||||
* @param null $fields
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function setup($db=null, $table=null, $fields=null){
|
||||
$status = parent::setup($db,$table,$fields);
|
||||
|
||||
if($status === true){
|
||||
$status = parent::setMultiColumnIndex(['corporationId', 'structureId'], true);
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
}
|
||||
@@ -649,7 +649,7 @@ class MapModel extends AbstractMapTrackingModel {
|
||||
* get all connection data in this map
|
||||
* @return \stdClass[]
|
||||
*/
|
||||
public function getConnectionData(){
|
||||
public function getConnectionData() : array {
|
||||
$connectionData = [];
|
||||
$connections = $this->getConnections();
|
||||
|
||||
@@ -663,6 +663,34 @@ class MapModel extends AbstractMapTrackingModel {
|
||||
return $connectionData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all structures data for this map
|
||||
* @param array $systemIds
|
||||
* @return array
|
||||
*/
|
||||
public function getStructuresData(array $systemIds = []) : array {
|
||||
$structuresData = [];
|
||||
$corporations = $this->getAllCorporations();
|
||||
|
||||
foreach($corporations as $corporation){
|
||||
// corporations should be unique
|
||||
if( !isset($structuresData[$corporation->_id]) ){
|
||||
// get all structures for current corporation
|
||||
$corporationStructuresData = $corporation->getStructuresData($systemIds);
|
||||
if( !empty($corporationStructuresData) ){
|
||||
// corporation has structures
|
||||
$structuresData[$corporation->_id] = [
|
||||
'id' => $corporation->_id,
|
||||
'name' => $corporation->name,
|
||||
'structures' => $corporationStructuresData
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $structuresData;
|
||||
}
|
||||
|
||||
/**
|
||||
* set map access for an object (character, corporation or alliance)
|
||||
* @param $obj
|
||||
@@ -767,7 +795,7 @@ class MapModel extends AbstractMapTrackingModel {
|
||||
* @return bool
|
||||
* @throws PathfinderException
|
||||
*/
|
||||
public function hasAccess(CharacterModel $characterModel){
|
||||
public function hasAccess(CharacterModel $characterModel) : bool {
|
||||
$hasAccess = false;
|
||||
|
||||
if( !$this->dry() ){
|
||||
@@ -809,20 +837,58 @@ class MapModel extends AbstractMapTrackingModel {
|
||||
return $characters;
|
||||
}
|
||||
|
||||
/**
|
||||
* get corporations that have access to this map
|
||||
* @return CorporationModel[]
|
||||
*/
|
||||
public function getCorporations() : array {
|
||||
$corporations = [];
|
||||
|
||||
if($this->isCorporation()){
|
||||
$this->filter('mapCorporations', ['active = ?', 1]);
|
||||
|
||||
if($this->mapCorporations){
|
||||
foreach($this->mapCorporations as $mapCorporation){
|
||||
$corporations[] = $mapCorporation->corporationId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $corporations;
|
||||
}
|
||||
|
||||
/**
|
||||
* get alliances that have access to this map
|
||||
* @return AllianceModel[]
|
||||
*/
|
||||
public function getAlliances() : array {
|
||||
$alliances = [];
|
||||
|
||||
if($this->isAlliance()){
|
||||
$this->filter('mapAlliances', ['active = ?', 1]);
|
||||
|
||||
if($this->mapAlliances){
|
||||
foreach($this->mapAlliances as $mapAlliance){
|
||||
$alliances[] = $mapAlliance->allianceId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $alliances;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all character models that are currently online "viewing" this map
|
||||
* @param array $options filter options
|
||||
* @return CharacterModel[]
|
||||
*/
|
||||
private function getAllCharacters($options = []){
|
||||
private function getAllCharacters($options = []) : array {
|
||||
$characters = [];
|
||||
|
||||
if($this->isPrivate()){
|
||||
$activeCharacters = $this->getCharacters();
|
||||
|
||||
// add active character for each user
|
||||
foreach($activeCharacters as $activeCharacter){
|
||||
$characters[] = $activeCharacter;
|
||||
foreach($this->getCharacters() as $character){
|
||||
$characters[] = $character;
|
||||
}
|
||||
}elseif($this->isCorporation()){
|
||||
$corporations = $this->getCorporations();
|
||||
@@ -870,18 +936,35 @@ class MapModel extends AbstractMapTrackingModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* get all corporations that have access to this map
|
||||
* get all corporations that have access
|
||||
* -> for private maps -> get corporations from characters
|
||||
* -> for corporation maps -> get corporations
|
||||
* -> for alliance maps -> get corporations from alliances
|
||||
* @return CorporationModel[]
|
||||
*/
|
||||
public function getCorporations(){
|
||||
public function getAllCorporations() : array {
|
||||
$corporations = [];
|
||||
|
||||
if($this->isCorporation()){
|
||||
$this->filter('mapCorporations', ['active = ?', 1]);
|
||||
|
||||
if($this->mapCorporations){
|
||||
foreach($this->mapCorporations as $mapCorporation){
|
||||
$corporations[] = $mapCorporation->corporationId;
|
||||
if($this->isPrivate()){
|
||||
foreach($this->getCharacters() as $character){
|
||||
if(
|
||||
$character->hasCorporation() &&
|
||||
!array_key_exists($character->get('corporationId', true), $corporations)
|
||||
){
|
||||
$corporations[$character->getCorporation()->_id] = $character->getCorporation();
|
||||
}
|
||||
}
|
||||
}elseif($this->isCorporation()){
|
||||
$corporations = $this->getCorporations();
|
||||
}elseif($this->isAlliance()){
|
||||
foreach($this->getAlliances() as $alliance){
|
||||
foreach($alliance->getCharacters() as $character){
|
||||
if(
|
||||
$character->hasCorporation() &&
|
||||
!array_key_exists($character->get('corporationId', true), $corporations)
|
||||
){
|
||||
$corporations[$character->getCorporation()->_id] = $character->getCorporation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -889,26 +972,6 @@ class MapModel extends AbstractMapTrackingModel {
|
||||
return $corporations;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all alliances that have access to this map
|
||||
* @return AllianceModel[]
|
||||
*/
|
||||
public function getAlliances(){
|
||||
$alliances = [];
|
||||
|
||||
if($this->isAlliance()){
|
||||
$this->filter('mapAlliances', ['active = ?', 1]);
|
||||
|
||||
if($this->mapAlliances){
|
||||
foreach($this->mapAlliances as $mapAlliance){
|
||||
$alliances[] = $mapAlliance->allianceId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $alliances;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $action
|
||||
* @return Logging\LogInterface
|
||||
|
||||
218
app/main/model/structuremodel.php
Normal file
218
app/main/model/structuremodel.php
Normal file
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: exodu
|
||||
* Date: 15.04.2018
|
||||
* Time: 19:41
|
||||
*/
|
||||
|
||||
namespace Model;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
|
||||
class StructureModel extends BasicModel {
|
||||
|
||||
protected $table = 'structure';
|
||||
|
||||
/**
|
||||
* categoryId (from CCP´s SDE) that holds all "groups" with structure "types"
|
||||
*/
|
||||
const CATEGORY_STRUCTURE_ID = 65;
|
||||
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 1,
|
||||
'index' => true
|
||||
],
|
||||
'structureId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true
|
||||
],
|
||||
'corporationId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\CorporationModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'corporation',
|
||||
'on-delete' => 'SET NULL'
|
||||
]
|
||||
]
|
||||
],
|
||||
'systemId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'validate' => true
|
||||
],
|
||||
'statusId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\StructureStatusModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'structure_status',
|
||||
'on-delete' => 'SET NULL'
|
||||
]
|
||||
]
|
||||
],
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'description' => [
|
||||
'type' => Schema::DT_VARCHAR512,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'structureCorporations' => [
|
||||
'has-many' => ['Model\CorporationStructureModel', 'structureId']
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* get structure data
|
||||
* @return \stdClass
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getData() : \stdClass {
|
||||
$structureData = (object) [];
|
||||
$structureData->id = $this->_id;
|
||||
$structureData->systemId = $this->systemId;
|
||||
$structureData->status = $this->statusId->getData();
|
||||
$structureData->name = $this->name;
|
||||
$structureData->description = $this->description;
|
||||
|
||||
if($this->structureId){
|
||||
$structureData->structure = $this->getUniverseTypeData($this->structureId);
|
||||
}
|
||||
|
||||
if($this->corporationId){
|
||||
$structureData->owner = (object) [];
|
||||
$structureData->owner->id = $this->corporationId->_id;
|
||||
$structureData->owner->name = $this->corporationId->name;
|
||||
}
|
||||
|
||||
$structureData->updated = (object) [];
|
||||
$structureData->updated->updated = strtotime($this->updated);
|
||||
|
||||
return $structureData;
|
||||
}
|
||||
|
||||
/**
|
||||
* set structureId (universeType) for this structure
|
||||
* @param $structureId
|
||||
* @return int|null
|
||||
*/
|
||||
public function set_structureId($structureId){
|
||||
$structureId = (int)$structureId;
|
||||
$structureId = $structureId ? : null;
|
||||
|
||||
return $structureId;
|
||||
}
|
||||
|
||||
/**
|
||||
* set corporationId (owner) for this structure
|
||||
* -> if corporation does not exists in DB -> load from API
|
||||
* @param $corporationId
|
||||
* @return int|null
|
||||
*/
|
||||
public function set_corporationId($corporationId){
|
||||
$oldCorporationId = $this->get('corporationId', true) ? : 0;
|
||||
$corporationId = !is_string($corporationId) ? : (int)$corporationId;
|
||||
|
||||
if($corporationId){
|
||||
if($corporationId !== $oldCorporationId){
|
||||
// make sure there is already corporation data stored for new corporationId
|
||||
/**
|
||||
* @var CorporationModel $corporation
|
||||
*/
|
||||
$corporation = $this->rel('corporationId');
|
||||
$corporation->getById($corporationId);
|
||||
if($corporation->dry()){
|
||||
$corporationId = null;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$corporationId = null;
|
||||
}
|
||||
|
||||
return $corporationId;
|
||||
}
|
||||
/**
|
||||
* validates systemId
|
||||
* @param string $key
|
||||
* @param string $val
|
||||
* @return bool
|
||||
*/
|
||||
protected function validate_systemId(string $key, string $val): bool {
|
||||
$valid = true;
|
||||
|
||||
if( !$this->dry() && $this->systemId !== (int)$val ){
|
||||
// structure always belongs to the same system
|
||||
$valid = false;
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* check access by chraacter
|
||||
* @param CharacterModel $characterModel
|
||||
* @return bool
|
||||
*/
|
||||
public function hasAccess(CharacterModel $characterModel) : bool {
|
||||
$access = false;
|
||||
if($this->dry()){
|
||||
$access = true;
|
||||
}elseif($characterModel->hasCorporation()){
|
||||
$this->filter('structureCorporations', ['active = ?', 1]);
|
||||
$this->has('structureCorporations.corporationId', ['active = ?', 1]);
|
||||
$this->has('structureCorporations.corporationId', ['id = ?', $characterModel->get('corporationId', true)]);
|
||||
|
||||
if($this->structureCorporations){
|
||||
$access = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $access;
|
||||
}
|
||||
|
||||
/**
|
||||
* get structure data grouped by corporations
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function getDataByCorporations() : array {
|
||||
$structuresData = [];
|
||||
foreach((array)$this->structureCorporations as $structureCorporation){
|
||||
if($structureCorporation->isActive() && $structureCorporation->corporationId->isActive()){
|
||||
$structuresData[$structureCorporation->corporationId->_id] = [
|
||||
'id' => $structureCorporation->corporationId->_id,
|
||||
'name' => $structureCorporation->corporationId->name,
|
||||
'structures' => [$this->getData()]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $structuresData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get universe type data for structureId
|
||||
* @param int $structureId
|
||||
* @return \stdClass
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function getUniverseTypeData(int $structureId) : \stdClass {
|
||||
/**
|
||||
* @var $type Universe\TypeModel
|
||||
*/
|
||||
$type = Universe\BasicUniverseModel::getNew('TypeModel')->getById($structureId);
|
||||
return $type->dry() ? (object)[] : $type->getData();
|
||||
}
|
||||
|
||||
}
|
||||
92
app/main/model/structurestatusmodel.php
Normal file
92
app/main/model/structurestatusmodel.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: exodu
|
||||
* Date: 15.04.2018
|
||||
* Time: 20:13
|
||||
*/
|
||||
|
||||
namespace Model;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
|
||||
class StructureStatusModel extends BasicModel {
|
||||
|
||||
protected $table = 'structure_status';
|
||||
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 1,
|
||||
'index' => true
|
||||
],
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'label' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'class' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'structures' => [
|
||||
'has-many' => ['Model\StructureModel', 'statusId']
|
||||
]
|
||||
];
|
||||
|
||||
protected static $tableData = [
|
||||
[
|
||||
'id' => 1,
|
||||
'name' => 'unknown',
|
||||
'label' => '',
|
||||
'class' => 'pf-structure-status-unknown'
|
||||
],
|
||||
[
|
||||
'id' => 2,
|
||||
'name' => 'online',
|
||||
'label' => 'online',
|
||||
'class' => 'pf-structure-status-online'
|
||||
],
|
||||
[
|
||||
'id' => 3,
|
||||
'name' => 'offline',
|
||||
'label' => 'offline',
|
||||
'class' => 'pf-structure-status-offline'
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* get structure status data
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function getData() : \stdClass {
|
||||
$statusData = (object) [];
|
||||
$statusData->id = $this->_id;
|
||||
$statusData->name = $this->name;
|
||||
$statusData->label = $this->label;
|
||||
$statusData->class = $this->class;
|
||||
|
||||
return $statusData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all status options
|
||||
* @return \DB\CortexCollection
|
||||
*/
|
||||
public static function getAll(){
|
||||
$query = [
|
||||
'active = :active',
|
||||
':active' => 1
|
||||
];
|
||||
|
||||
return (new self())->find($query);
|
||||
}
|
||||
}
|
||||
@@ -203,7 +203,7 @@ class SystemModel extends AbstractMapTrackingModel {
|
||||
// no cached system data found
|
||||
|
||||
$systemData = (object) [];
|
||||
$systemData->id = $this->id;
|
||||
$systemData->id = $this->_id;
|
||||
$systemData->mapId = is_object($this->mapId) ? $this->get('mapId', true) : 0;
|
||||
$systemData->systemId = $this->systemId;
|
||||
$systemData->name = $this->name;
|
||||
@@ -485,7 +485,6 @@ class SystemModel extends AbstractMapTrackingModel {
|
||||
public function getSignatures(){
|
||||
$signatures = [];
|
||||
$this->filter('signatures', ['active = ?', 1], ['order' => 'name']);
|
||||
|
||||
if($this->signatures){
|
||||
$signatures = $this->signatures;
|
||||
}
|
||||
@@ -494,13 +493,12 @@ class SystemModel extends AbstractMapTrackingModel {
|
||||
}
|
||||
|
||||
/**
|
||||
* get all data for all Signatures in this system
|
||||
* get data for all Signatures in this system
|
||||
* @return \stdClass[]
|
||||
*/
|
||||
public function getSignaturesData(){
|
||||
$signaturesData = [];
|
||||
$signatures = $this->getSignatures();
|
||||
|
||||
foreach($signatures as $signature){
|
||||
$signaturesData[] = $signature->getData();
|
||||
}
|
||||
@@ -516,7 +514,6 @@ class SystemModel extends AbstractMapTrackingModel {
|
||||
*/
|
||||
public function getSignatureById(CharacterModel $characterModel, $id){
|
||||
$signature = null;
|
||||
|
||||
if($this->hasAccess($characterModel)){
|
||||
$this->filter('signatures', ['active = ? AND id = ?', 1, $id]);
|
||||
if($this->signatures){
|
||||
@@ -535,7 +532,6 @@ class SystemModel extends AbstractMapTrackingModel {
|
||||
*/
|
||||
public function getSignatureByName(CharacterModel $characterModel, $name){
|
||||
$signature = null;
|
||||
|
||||
if($this->hasAccess($characterModel)){
|
||||
$this->filter('signatures', ['active = ? AND name = ?', 1, $name]);
|
||||
if($this->signatures){
|
||||
@@ -546,6 +542,14 @@ class SystemModel extends AbstractMapTrackingModel {
|
||||
return $signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* get data for all structures in this system
|
||||
* @return \stdClass[]
|
||||
*/
|
||||
public function getStructuresData() : array {
|
||||
return $this->getMap()->getStructuresData([$this->systemId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* check whether this system is a wormhole
|
||||
* @return bool
|
||||
|
||||
121
app/main/model/universe/GroupModel.php
Normal file
121
app/main/model/universe/GroupModel.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: exodu
|
||||
* Date: 13.04.2018
|
||||
* Time: 23:58
|
||||
*/
|
||||
|
||||
namespace Model\Universe;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class GroupModel extends BasicUniverseModel {
|
||||
|
||||
protected $table = 'group';
|
||||
|
||||
protected $fieldConf = [
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'published' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 1,
|
||||
'index' => true
|
||||
],
|
||||
'categoryId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\CategoryModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'category',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'types' => [
|
||||
'has-many' => ['Model\Universe\TypeModel', 'groupId']
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* get group data
|
||||
* @return object
|
||||
*/
|
||||
public function getData(){
|
||||
$groupData = (object) [];
|
||||
$groupData->id = $this->id;
|
||||
$groupData->name = $this->name;
|
||||
|
||||
|
||||
if($typesData = $this->getTypesData()){
|
||||
$groupData->types = $typesData;
|
||||
}
|
||||
|
||||
return $groupData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all types for this group
|
||||
* @return array|mixed
|
||||
*/
|
||||
protected function getTypes(){
|
||||
$types = [];
|
||||
$this->filter('types', [
|
||||
'published = :published',
|
||||
':published' => 1
|
||||
]);
|
||||
|
||||
if($this->types){
|
||||
$types = $this->types;
|
||||
}
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getTypesData() : array {
|
||||
$typesData = [];
|
||||
$types = $this->getTypes();
|
||||
|
||||
foreach($types as $type){
|
||||
$typesData[] = $type->getData();
|
||||
}
|
||||
|
||||
return $typesData;
|
||||
}
|
||||
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient->getUniverseGroupData($id);
|
||||
if(!empty($data)){
|
||||
$category = $this->rel('categoryId');
|
||||
$category->loadById($data['categoryId'], $accessToken, $additionalOptions);
|
||||
$data['categoryId'] = $category;
|
||||
|
||||
$this->copyfrom($data, ['id', 'name', 'published', 'categoryId']);
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load types data for this group
|
||||
*/
|
||||
public function loadTypesData(){
|
||||
if( !$this->dry() ){
|
||||
$data = self::getF3()->ccpClient->getUniverseGroupData($this->_id);
|
||||
if(!empty($data)){
|
||||
foreach((array)$data['types'] as $typeId){
|
||||
$type = $this->rel('types');
|
||||
$type->loadById($typeId);
|
||||
$type->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,53 @@ abstract class BasicUniverseModel extends BasicModel {
|
||||
|
||||
protected $db = 'DB_UNIVERSE';
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* return false will stop any further action
|
||||
* @param self $self
|
||||
* @param $pkeys
|
||||
* @return bool
|
||||
*/
|
||||
public function beforeUpdateEvent($self, $pkeys){
|
||||
// if model changed, 'update' col needs to be updated as well
|
||||
// -> data no longer "outdated"
|
||||
$this->touch('updated');
|
||||
|
||||
return parent::beforeUpdateEvent($self, $pkeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* load object by $id
|
||||
* -> if $id not exists in DB -> query API
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
public function loadById(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
/**
|
||||
* @var $model self
|
||||
*/
|
||||
$model = $this->getById($id, 0);
|
||||
if($model->isOutdated()){
|
||||
$model->loadData($id, $accessToken, $additionalOptions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load data from API into $this and save $this
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
abstract protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []);
|
||||
|
||||
/**
|
||||
* factory for all UniverseModels
|
||||
* @param string $model
|
||||
* @param int $ttl
|
||||
* @return BasicModel|null
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function getNew($model, $ttl = self::DEFAULT_TTL){
|
||||
$class = null;
|
||||
|
||||
@@ -35,51 +82,4 @@ abstract class BasicUniverseModel extends BasicModel {
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* load data from API into $this and save $this
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
abstract protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []);
|
||||
|
||||
/**
|
||||
* load object by $id
|
||||
* -> if $id not exists in DB -> query API
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
public function loadById(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
/**
|
||||
* @var $model self
|
||||
*/
|
||||
$model = $this->getById($id);
|
||||
if($model->isOutdated()){
|
||||
$model->loadData($id, $accessToken, $additionalOptions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks whether data is outdated and should be refreshed
|
||||
* @return bool
|
||||
*/
|
||||
protected function isOutdated(): bool {
|
||||
$outdated = true;
|
||||
if(!$this->dry()){
|
||||
$timezone = $this->getF3()->get('getTimeZone')();
|
||||
$currentTime = new \DateTime('now', $timezone);
|
||||
$updateTime = \DateTime::createFromFormat(
|
||||
'Y-m-d H:i:s',
|
||||
$this->updated,
|
||||
$timezone
|
||||
);
|
||||
$interval = $updateTime->diff($currentTime);
|
||||
if($interval->days < self::CACHE_MAX_DAYS ){
|
||||
$outdated = false;
|
||||
}
|
||||
}
|
||||
return $outdated;
|
||||
}
|
||||
}
|
||||
111
app/main/model/universe/categoryModel.php
Normal file
111
app/main/model/universe/categoryModel.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: exodu
|
||||
* Date: 13.04.2018
|
||||
* Time: 23:49
|
||||
*/
|
||||
|
||||
namespace Model\Universe;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class CategoryModel extends BasicUniverseModel {
|
||||
|
||||
protected $table = 'category';
|
||||
|
||||
protected $fieldConf = [
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
],
|
||||
'published' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 1,
|
||||
'index' => true
|
||||
],
|
||||
'groups' => [
|
||||
'has-many' => ['Model\Universe\GroupModel', 'categoryId']
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* get category data
|
||||
* @return object
|
||||
*/
|
||||
public function getData(){
|
||||
$categoryData = (object) [];
|
||||
$categoryData->id = $this->id;
|
||||
$categoryData->name = $this->name;
|
||||
|
||||
if($groupsData = $this->getGroupsData()){
|
||||
$categoryData->groups = $groupsData;
|
||||
}
|
||||
|
||||
return $categoryData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get all groups for this category
|
||||
* @return array|mixed
|
||||
*/
|
||||
protected function getGroups(){
|
||||
$groups = [];
|
||||
$this->filter('groups', [
|
||||
'published = :published',
|
||||
':published' => 1
|
||||
]);
|
||||
|
||||
if($this->groups){
|
||||
$groups = $this->groups;
|
||||
}
|
||||
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getGroupsData() : array {
|
||||
$groupsData = [];
|
||||
$groups = $this->getGroups();
|
||||
|
||||
foreach($groups as $group){
|
||||
$groupsData[] = $group->getData();
|
||||
}
|
||||
|
||||
return $groupsData;
|
||||
}
|
||||
|
||||
/**
|
||||
* load data from API into $this and save $this
|
||||
* @param int $id
|
||||
* @param string $accessToken
|
||||
* @param array $additionalOptions
|
||||
*/
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient->getUniverseCategoryData($id);
|
||||
if(!empty($data)){
|
||||
$this->copyfrom($data, ['id', 'name', 'published']);
|
||||
$this->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* load groups data for this category
|
||||
*/
|
||||
public function loadGroupsData(){
|
||||
if( !$this->dry() ){
|
||||
$data = self::getF3()->ccpClient->getUniverseCategoryData($this->_id);
|
||||
if(!empty($data)){
|
||||
foreach((array)$data['groups'] as $groupId){
|
||||
$group = $this->rel('groups');
|
||||
$group->loadById($groupId);
|
||||
$group->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,7 +96,7 @@ class StructureModel extends BasicUniverseModel {
|
||||
*/
|
||||
public function copyfrom($key, $fields = null){
|
||||
// flatten array (e.g. "position" key)
|
||||
$key = Util::arrayFlatten((array)$key);
|
||||
$key = Util::arrayFlattenByKey((array)$key);
|
||||
parent::copyfrom($key, $fields);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,9 +52,14 @@ class TypeModel extends BasicUniverseModel {
|
||||
],
|
||||
'groupId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'nullable' => false,
|
||||
'default' => 0,
|
||||
'index' => true
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\Universe\GroupModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'group',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'marketGroupId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
@@ -83,6 +88,18 @@ class TypeModel extends BasicUniverseModel {
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* get type data
|
||||
* @return object
|
||||
*/
|
||||
public function getData(){
|
||||
$typeData = (object) [];
|
||||
$typeData->id = $this->id;
|
||||
$typeData->name = $this->name;
|
||||
|
||||
return $typeData;
|
||||
}
|
||||
|
||||
/**
|
||||
* get shipData from object
|
||||
* -> more fields can be added in here if needed
|
||||
@@ -107,6 +124,10 @@ class TypeModel extends BasicUniverseModel {
|
||||
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
|
||||
$data = self::getF3()->ccpClient->getUniverseTypesData($id, $additionalOptions);
|
||||
if(!empty($data)){
|
||||
$group = $this->rel('groupId');
|
||||
$group->loadById($data['groupId'], $accessToken, $additionalOptions);
|
||||
$data['groupId'] = $group;
|
||||
|
||||
$this->copyfrom($data);
|
||||
$this->save();
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ requirejs.config({
|
||||
deps : ['jquery']
|
||||
},
|
||||
select2: {
|
||||
deps : ['jquery'],
|
||||
deps : ['jquery', 'mousewheel'],
|
||||
exports: 'Select2'
|
||||
},
|
||||
validator: {
|
||||
|
||||
@@ -67,9 +67,10 @@ define([
|
||||
*/
|
||||
$.fn.destroyTimestampCounter = function(){
|
||||
return this.each(function(){
|
||||
let element = $(this);
|
||||
element.find('[data-counter="init"]').each(function(){
|
||||
let interval = $(this).data('interval');
|
||||
let parentElement = $(this);
|
||||
parentElement.find('[data-counter="init"]').each(function(){
|
||||
let element = $(this);
|
||||
let interval = element.data('interval');
|
||||
if(interval){
|
||||
clearInterval(interval);
|
||||
element.removeAttr('data-counter')
|
||||
|
||||
@@ -33,6 +33,7 @@ define(['jquery'], ($) => {
|
||||
getMapConnectionData: '/api/map/getConnectionData', // ajax URL - get connection data
|
||||
getMapLogData: '/api/map/getLogData', // ajax URL - get logs data
|
||||
// system API
|
||||
getSystemData: '/api/system/getData', // ajax URL - get system data
|
||||
searchSystem: '/api/system/search', // ajax URL - search system by name
|
||||
saveSystem: '/api/system/save', // ajax URL - saves system to map
|
||||
deleteSystem: '/api/system/delete', // ajax URL - delete system from map
|
||||
@@ -47,10 +48,15 @@ define(['jquery'], ($) => {
|
||||
getSignatures: '/api/signature/getAll', // ajax URL - get all signature data for system
|
||||
saveSignatureData: '/api/signature/save', // ajax URL - save signature data for system
|
||||
deleteSignatureData: '/api/signature/delete', // ajax URL - delete signature data for system
|
||||
// structure API
|
||||
saveStructureData: '/api/structure/save', // ajax URL - save structure data
|
||||
deleteStructureData: '/api/structure/delete', // ajax URL - delete structure data
|
||||
// route API
|
||||
searchRoute: '/api/route/search', // ajax URL - search system routes
|
||||
// stats API
|
||||
getStatisticsData: '/api/statistic/getData', // ajax URL - get statistics data (activity log)
|
||||
// universe API
|
||||
searchUniverseData: '/api/universe/search', // ajax URL - search universe data
|
||||
// GitHub API
|
||||
gitHubReleases: '/api/github/releases' // ajax URL - get release info from GitHub
|
||||
},
|
||||
|
||||
@@ -105,6 +105,10 @@ define([
|
||||
let ssoButtonElement = $('.' + config.ssoButtonClass);
|
||||
let cookieHintElement = $('#' + config.cookieHintId);
|
||||
|
||||
$(document).on('click', '.' + config.ssoButtonClass + ', .' + config.characterSelectionClass + ' a', function(){
|
||||
$('.' + config.splashOverlayClass).showSplashOverlay();
|
||||
});
|
||||
|
||||
// cookie hint --------------------------------------------------------
|
||||
cookieHintElement.find('.btn-success').on('click', function(){
|
||||
setAcceptCookie();
|
||||
@@ -683,11 +687,6 @@ define([
|
||||
let content = Mustache.render(template, data);
|
||||
this.characterElement.html(content);
|
||||
|
||||
// lock character selection on click (prevent click spamming)
|
||||
this.characterElement.find('a').on('click', function(){
|
||||
$('.' + config.splashOverlayClass).showSplashOverlay();
|
||||
});
|
||||
|
||||
// show character panel (animation settings)
|
||||
initCharacterAnimation(this.characterElement.find('.' + config.characterImageWrapperClass));
|
||||
}else{
|
||||
|
||||
@@ -14,7 +14,6 @@ define([
|
||||
'app/map/magnetizing',
|
||||
'app/map/scrollbar',
|
||||
'dragToSelect',
|
||||
'select2',
|
||||
'app/map/contextmenu',
|
||||
'app/map/overlay',
|
||||
'app/map/local'
|
||||
|
||||
@@ -32,6 +32,9 @@ define([
|
||||
// set default dialog config
|
||||
Util.initDefaultBootboxConfig();
|
||||
|
||||
// set default select2 config
|
||||
Util.initDefaultSelect2Config();
|
||||
|
||||
// load page
|
||||
// load info (maintenance) info panel (if scheduled)
|
||||
$('body').loadPageStructure().setGlobalShortcuts();
|
||||
@@ -128,6 +131,8 @@ define([
|
||||
Init.url = response.url;
|
||||
Init.slack = response.slack;
|
||||
Init.discord = response.discord;
|
||||
Init.structureStatus = response.structureStatus;
|
||||
Init.universeCategories = response.universeCategories;
|
||||
Init.routeSearch = response.routeSearch;
|
||||
Init.programMode = response.programMode;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ define([
|
||||
'app/ui/system_graph',
|
||||
'app/ui/system_signature',
|
||||
'app/ui/system_route',
|
||||
'app/ui/system_intel',
|
||||
'app/ui/system_killboard',
|
||||
'app/ui/connection_info',
|
||||
'app/counter'
|
||||
@@ -23,6 +24,7 @@ define([
|
||||
SystemGraphModule,
|
||||
SystemSignatureModule,
|
||||
SystemRouteModule,
|
||||
SystemIntelModule,
|
||||
SystemKillboardModule,
|
||||
ConnectionInfoModule
|
||||
) => {
|
||||
@@ -276,6 +278,9 @@ define([
|
||||
// draw system routes module
|
||||
drawModule(secondCell, SystemRouteModule, currentSystemData.mapId, currentSystemData.systemData);
|
||||
|
||||
// draw system intel module
|
||||
drawModule(secondCell, SystemIntelModule, currentSystemData.mapId, currentSystemData.systemData);
|
||||
|
||||
// draw system killboard module
|
||||
drawModule(secondCell, SystemKillboardModule, currentSystemData.mapId, currentSystemData.systemData);
|
||||
});
|
||||
|
||||
@@ -346,7 +346,6 @@ define([
|
||||
let formValid = form.isValidForm();
|
||||
|
||||
if(formValid === true){
|
||||
|
||||
// lock dialog
|
||||
let dialogContent = mapInfoDialog.find('.modal-content');
|
||||
dialogContent.showLoadingAnimation();
|
||||
@@ -391,7 +390,6 @@ define([
|
||||
data: requestData,
|
||||
dataType: 'json'
|
||||
}).done(function(responseData){
|
||||
|
||||
if(responseData.error.length){
|
||||
form.showFormMessage(responseData.error);
|
||||
}else{
|
||||
|
||||
@@ -7,10 +7,67 @@ define([
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/map/util'
|
||||
], function($, Init, Util, MapUtil) {
|
||||
|
||||
], ($, Init, Util, MapUtil) => {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* format result data
|
||||
* @param data
|
||||
* @returns {*}
|
||||
*/
|
||||
let formatCategoryTypeResultData = (data) => {
|
||||
if(data.loading) return data.text;
|
||||
if(data.placeholder) return data.placeholder;
|
||||
|
||||
let markup = '<div class="clearfix">';
|
||||
|
||||
if(data.hasOwnProperty('children')){
|
||||
// category group label
|
||||
markup += '<div class="col-xs-9">' + data.text + '</div>';
|
||||
markup += '<div class="col-xs-3 text-right">(' + data.children.length + ')</div>';
|
||||
}else{
|
||||
let imagePath = '';
|
||||
let iconName = '';
|
||||
let thumb = '';
|
||||
|
||||
switch(data.categoryType){
|
||||
case 'character':
|
||||
imagePath = Init.url.ccpImageServer + '/Character/' + data.id + '_32.jpg';
|
||||
break;
|
||||
case 'corporation':
|
||||
imagePath = Init.url.ccpImageServer + '/Corporation/' + data.id + '_32.png';
|
||||
break;
|
||||
case 'alliance':
|
||||
imagePath = Init.url.ccpImageServer + '/Alliance/' + data.id + '_32.png';
|
||||
break;
|
||||
case 'inventory_type':
|
||||
imagePath = Init.url.ccpImageServer + '/Type/' + data.id + '_32.png';
|
||||
break;
|
||||
case 'render':
|
||||
imagePath = Init.url.ccpImageServer + '/Render/' + data.id + '_32.png';
|
||||
break;
|
||||
case 'station':
|
||||
iconName = 'fa-home';
|
||||
break;
|
||||
case 'solar_system':
|
||||
iconName = 'fa-sun';
|
||||
break;
|
||||
}
|
||||
|
||||
if(imagePath){
|
||||
thumb = '<img src="' + imagePath + '" style="max-width: 100%" />';
|
||||
}else if(iconName){
|
||||
thumb = '<i class="fas fa-fw ' + iconName + '" ></i>';
|
||||
}
|
||||
|
||||
markup += '<div class="col-xs-2 text-center">' + thumb + '</div>';
|
||||
markup += '<div class="col-xs-10">' + data.text + '</div>';
|
||||
}
|
||||
markup += '</div>';
|
||||
|
||||
return markup;
|
||||
};
|
||||
|
||||
/**
|
||||
* init a select element as "select2" for map selection
|
||||
*/
|
||||
@@ -20,7 +77,6 @@ define([
|
||||
$.when(
|
||||
selectElement.select2({
|
||||
dropdownParent: selectElement.parents('.modal-body'),
|
||||
theme: 'pathfinder',
|
||||
maximumSelectionLength: 5
|
||||
})
|
||||
);
|
||||
@@ -133,8 +189,7 @@ define([
|
||||
}
|
||||
},
|
||||
dropdownParent: selectElement.parents('.modal-body'),
|
||||
theme: 'pathfinder',
|
||||
minimumInputLength: 2,
|
||||
minimumInputLength: 3,
|
||||
templateResult: formatResultData,
|
||||
placeholder: 'System name',
|
||||
allowClear: true,
|
||||
@@ -171,52 +226,8 @@ define([
|
||||
$.fn.initAccessSelect = function(options){
|
||||
|
||||
return this.each(function(){
|
||||
|
||||
let selectElement = $(this);
|
||||
|
||||
// format result data
|
||||
function formatResultData (data) {
|
||||
|
||||
if (data.loading){
|
||||
return data.text;
|
||||
}
|
||||
|
||||
// check if an option is already selected
|
||||
// do not show the same result twice
|
||||
let currentValues = selectElement.val();
|
||||
|
||||
if(
|
||||
currentValues &&
|
||||
currentValues.indexOf( data.id.toString() ) !== -1
|
||||
){
|
||||
return ;
|
||||
}
|
||||
|
||||
let imagePath = '';
|
||||
let previewContent = '';
|
||||
|
||||
switch(options.type){
|
||||
case 'character':
|
||||
imagePath = Init.url.ccpImageServer + '/Character/' + data.id + '_32.jpg';
|
||||
previewContent = '<img src="' + imagePath + '" style="max-width: 100%" />';
|
||||
break;
|
||||
case 'corporation':
|
||||
imagePath = Init.url.ccpImageServer + '/Corporation/' + data.id + '_32.png';
|
||||
previewContent = '<img src="' + imagePath + '" style="max-width: 100%" />';
|
||||
break;
|
||||
case 'alliance':
|
||||
imagePath = Init.url.ccpImageServer + '/Alliance/' + data.id + '_32.png';
|
||||
previewContent = '<img src="' + imagePath + '" style="max-width: 100%" />';
|
||||
break;
|
||||
}
|
||||
|
||||
let markup = '<div class="clearfix">';
|
||||
markup += '<div class="col-sm-2">' + previewContent + '</div>';
|
||||
markup += '<div class="col-sm-10">' + data.text + '</div></div>';
|
||||
|
||||
return markup;
|
||||
}
|
||||
|
||||
// format selection data
|
||||
function formatSelectionData (data){
|
||||
|
||||
@@ -251,7 +262,8 @@ define([
|
||||
results: data.map( function(item){
|
||||
return {
|
||||
id: item.id,
|
||||
text: item.name
|
||||
text: item.name,
|
||||
categoryType: options.type
|
||||
};
|
||||
})
|
||||
};
|
||||
@@ -266,12 +278,11 @@ define([
|
||||
}
|
||||
},
|
||||
dropdownParent: selectElement.parents('.modal-body'),
|
||||
theme: 'pathfinder',
|
||||
minimumInputLength: 3,
|
||||
placeholder: options.type + ' names',
|
||||
allowClear: false,
|
||||
maximumSelectionLength: options.maxSelectionLength,
|
||||
templateResult: formatResultData,
|
||||
templateResult: formatCategoryTypeResultData,
|
||||
templateSelection: formatSelectionData,
|
||||
escapeMarkup: function(markup){
|
||||
// let our custom formatter work
|
||||
@@ -288,4 +299,190 @@ define([
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* init a select element as an ajax based "select2" object for universeTypes
|
||||
* e.g. 'alliance', 'corporation', 'character', ...
|
||||
* @param options
|
||||
* @returns {*}
|
||||
*/
|
||||
$.fn.initUniverseSearch = function(options) {
|
||||
|
||||
let showErrorNotification = (reason) => {
|
||||
Util.showNotify({title: 'Search failed', text: reason + ' deleted', type: 'warning'});
|
||||
};
|
||||
|
||||
/**
|
||||
* format selection data
|
||||
* @param data
|
||||
* @returns {*}
|
||||
*/
|
||||
function formatSelectionData (data){
|
||||
if(data.loading) return data.text;
|
||||
if(data.placeholder) return data.placeholder;
|
||||
|
||||
let markup = '<div class="clearfix">';
|
||||
markup += '<div class="col-sm-10">' + data.text + '</div></div>';
|
||||
|
||||
return markup;
|
||||
}
|
||||
|
||||
return this.each(function() {
|
||||
let selectElement = $(this);
|
||||
|
||||
$.when(
|
||||
selectElement.select2({
|
||||
ajax: {
|
||||
type: 'POST',
|
||||
url: function(params){
|
||||
// add params to URL
|
||||
return Init.path.searchUniverseData + '/' + params.term;
|
||||
},
|
||||
dataType: 'json',
|
||||
delay: 250,
|
||||
timeout: 5000,
|
||||
cache: true,
|
||||
data: function(params){
|
||||
return {
|
||||
categories: options.categoryNames
|
||||
};
|
||||
},
|
||||
processResults: function(result, page) {
|
||||
let data = {results: []};
|
||||
if(result.hasOwnProperty('error')){
|
||||
showErrorNotification(result.error);
|
||||
}else{
|
||||
let mapChildren = function(item){
|
||||
return {
|
||||
id: item.id,
|
||||
text: item.name,
|
||||
categoryType: this
|
||||
};
|
||||
};
|
||||
|
||||
for(let category in result){
|
||||
// skip custom functions in case result = [] (array functions)
|
||||
if(result.hasOwnProperty(category)){
|
||||
data.results.push({
|
||||
text: category,
|
||||
children: result[category].map(mapChildren, category)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
error: function (jqXHR, status, error) {
|
||||
if( !Util.isXHRAborted(jqXHR) ){
|
||||
let reason = status + ' ' + jqXHR.status + ': ' + error;
|
||||
showErrorNotification(reason);
|
||||
}
|
||||
}
|
||||
},
|
||||
dropdownParent: selectElement.parents('.modal-body') ,
|
||||
minimumInputLength: 3,
|
||||
placeholder: '',
|
||||
allowClear: options.maxSelectionLength <= 1,
|
||||
maximumSelectionLength: options.maxSelectionLength,
|
||||
templateResult: formatCategoryTypeResultData,
|
||||
// templateSelection: formatSelectionData, // some issues with "clear" selection on single selects (empty option is needed)
|
||||
escapeMarkup: function(markup){
|
||||
// let our custom formatter work
|
||||
return markup;
|
||||
}
|
||||
}).on('change', function(e){
|
||||
// select changed
|
||||
}).on('select2:open', function(){
|
||||
// clear selected system (e.g. default system)
|
||||
// => improves usability (not necessary). There is a small "x" whe it could be cleared manually
|
||||
if(
|
||||
options.maxSelectionLength === 1 &&
|
||||
$(this).val() !== null
|
||||
){
|
||||
$(this).val('').trigger('change');
|
||||
}
|
||||
})
|
||||
).done(function(){
|
||||
// after init finish
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
$.fn.initUniverseTypeSelect = function(options) {
|
||||
|
||||
/**
|
||||
* get select option data by categoryIds
|
||||
* @param categoryIds
|
||||
* @returns {{results: Array}}
|
||||
*/
|
||||
let getOptionsData = categoryIds => {
|
||||
let data = [];
|
||||
|
||||
let mapChildren = function(type){
|
||||
return {
|
||||
id: type.id,
|
||||
text: type.name,
|
||||
groupId: this.groupId,
|
||||
categoryId: this.categoryId,
|
||||
categoryType: this.categoryType
|
||||
};
|
||||
};
|
||||
|
||||
for(let categoryId of categoryIds){
|
||||
let categoryData = Util.getObjVal(Init, 'universeCategories.' + categoryId);
|
||||
if(categoryData && categoryData.groups){
|
||||
// categoryId data exists and has groups...
|
||||
for(let groupData of categoryData.groups){
|
||||
if(groupData && groupData.types){
|
||||
// groupData exists and has types...
|
||||
data.push({
|
||||
text: groupData.name,
|
||||
children: groupData.types.map(mapChildren, {
|
||||
groupId: groupData.id,
|
||||
categoryId: categoryData.id,
|
||||
categoryType: 'inventory_type',
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
return this.each(function() {
|
||||
let selectElement = $(this);
|
||||
|
||||
$.when(
|
||||
selectElement.select2({
|
||||
data: getOptionsData(options.categoryIds),
|
||||
dropdownParent: selectElement.parents('.modal-body'),
|
||||
minimumInputLength: 0, // minimum number of characters required to start a search
|
||||
maximumInputLength: 100, // maximum number of characters that may be provided for a search term
|
||||
placeholder: '',
|
||||
allowClear: options.maxSelectionLength <= 1,
|
||||
multiple: options.maxSelectionLength > 1,
|
||||
maximumSelectionLength: options.maxSelectionLength,
|
||||
// maximumSelectionLength: options.maxSelectionLength > 1 ? options.maxSelectionLength > 1 : 0,
|
||||
// minimumResultsForSearch: 5, // minimum number of results required to display the search box
|
||||
templateResult: formatCategoryTypeResultData,
|
||||
escapeMarkup: function(markup){
|
||||
return markup;
|
||||
}
|
||||
}).on('select2:open', function(){
|
||||
// clear selected system (e.g. default system)
|
||||
// => improves usability (not necessary). There is a small "x" whe it could be cleared manually
|
||||
if(
|
||||
options.maxSelectionLength === 1 &&
|
||||
$(this).val() !== null
|
||||
){
|
||||
$(this).val('').trigger('change');
|
||||
}
|
||||
}).val(options.selected).trigger('change')
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
@@ -169,33 +169,6 @@ define([
|
||||
moduleElement.find('.' + config.descriptionArea).hideLoadingAnimation();
|
||||
};
|
||||
|
||||
/**
|
||||
* update a character counter field with current value length - maxCharLength
|
||||
* @param field
|
||||
* @param charCounterElement
|
||||
* @param maxCharLength
|
||||
*/
|
||||
let updateCounter = function(field, charCounterElement, maxCharLength){
|
||||
let value = field.val();
|
||||
let inputLength = value.length;
|
||||
|
||||
// line breaks are 2 characters!
|
||||
let newLines = value.match(/(\r\n|\n|\r)/g);
|
||||
let addition = 0;
|
||||
if (newLines != null) {
|
||||
addition = newLines.length;
|
||||
}
|
||||
inputLength += addition;
|
||||
|
||||
charCounterElement.text(maxCharLength - inputLength);
|
||||
|
||||
if(maxCharLength <= inputLength){
|
||||
charCounterElement.toggleClass('txt-color-red', true);
|
||||
}else{
|
||||
charCounterElement.toggleClass('txt-color-red', false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* get module element
|
||||
* @param parentElement
|
||||
@@ -319,10 +292,10 @@ define([
|
||||
textarea.parent().next().append(charCounter);
|
||||
|
||||
// update character counter
|
||||
updateCounter(textarea, charCounter, maxDescriptionLength);
|
||||
Util.updateCounter(textarea, charCounter, maxDescriptionLength);
|
||||
|
||||
textarea.on('keyup', function(){
|
||||
updateCounter($(this), charCounter, maxDescriptionLength);
|
||||
Util.updateCounter($(this), charCounter, maxDescriptionLength);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
626
js/app/ui/system_intel.js
Normal file
626
js/app/ui/system_intel.js
Normal file
@@ -0,0 +1,626 @@
|
||||
/**
|
||||
* system route module
|
||||
*/
|
||||
|
||||
define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'bootbox'
|
||||
], ($, Init, Util, bootbox) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
// module info
|
||||
modulePosition: 1,
|
||||
moduleName: 'systemIntel',
|
||||
moduleHeadClass: 'pf-module-head', // class for module header
|
||||
moduleHandlerClass: 'pf-module-handler-drag', // class for "drag" handler
|
||||
moduleTypeClass: 'pf-system-intel-module', // class for this module
|
||||
|
||||
// headline toolbar
|
||||
moduleHeadlineIconClass: 'pf-module-icon-button', // class for toolbar icons in the head
|
||||
moduleHeadlineIconAddClass: 'pf-module-icon-button-add', // class for "add structure" icon
|
||||
moduleHeadlineIconRefreshClass: 'pf-module-icon-button-refresh', // class for "refresh" icon
|
||||
|
||||
// system intel module
|
||||
systemStructuresTableClass: 'pf-system-structure-table', // class for route tables
|
||||
|
||||
// structure dialog
|
||||
structureDialogId: 'pf-structure-dialog', // id for "structure" dialog
|
||||
typeSelectId: 'pf-structure-dialog-type-select', // id for "type" select
|
||||
corporationSelectId: 'pf-structure-dialog-corporation-select', // id for "corporation" select
|
||||
descriptionTextareaId: 'pf-structure-dialog-description-textarea', // id for "description" textarea
|
||||
descriptionTextareaCharCounter: 'pf-form-field-char-count', // class for "character counter" element for form field
|
||||
|
||||
// dataTable
|
||||
tableRowIdPrefix: 'pf-structure-row_', // id prefix for table rows
|
||||
tableCellImageClass: 'pf-table-image-smaller-cell', // class for table "image" cells
|
||||
tableCellCounterClass: 'pf-table-counter-cell', // class for table "counter" cells
|
||||
tableCellEllipsisClass: 'pf-table-cell-ellipses-auto', // class for table "ellipsis" cells
|
||||
dataTableActionCellClass: 'pf-table-action-cell' // class for "action" cells
|
||||
};
|
||||
|
||||
let maxDescriptionLength = 512;
|
||||
|
||||
/**
|
||||
* get status icon for structure
|
||||
* @param statusData
|
||||
* @returns {string}
|
||||
*/
|
||||
let getStatusData = (statusData) => {
|
||||
return '<i class="fas fa-fw fa-circle ' + statusData.class + '" title="' + statusData.label + '"></i>';
|
||||
};
|
||||
|
||||
/**
|
||||
* get <tr> DOM id by id
|
||||
* @param tableApi
|
||||
* @param id
|
||||
* @returns {*}
|
||||
*/
|
||||
let getRowId = (tableApi, id) => {
|
||||
return tableApi.rows().ids().toArray().find(rowId => rowId === config.tableRowIdPrefix + id);
|
||||
};
|
||||
|
||||
/**
|
||||
* callback -> add structure rows from responseData
|
||||
* @param context
|
||||
* @param responseData
|
||||
*/
|
||||
let callbackAddStructureRows = (context, responseData) => {
|
||||
let systemData = Util.getObjVal(responseData, 'system');
|
||||
callbackUpdateStructureRows(context, systemData);
|
||||
};
|
||||
|
||||
/**
|
||||
* callback -> add structure rows from systemData
|
||||
* @param context
|
||||
* @param systemData
|
||||
*/
|
||||
let callbackUpdateStructureRows = (context, systemData) => {
|
||||
let touchedRows = [];
|
||||
if(systemData){
|
||||
let corporations = Util.getObjVal(systemData, 'structures');
|
||||
if(corporations) {
|
||||
for (let [corporationId, corporationData] of Object.entries(corporations)){
|
||||
if(corporationData.structures && corporationData.structures.length){
|
||||
for(let structureData of corporationData.structures){
|
||||
let rowId = getRowId(context.tableApi, structureData.id);
|
||||
|
||||
// add corporation data
|
||||
structureData.corporation = {
|
||||
id: corporationData.id,
|
||||
name: corporationData.name
|
||||
};
|
||||
|
||||
if(rowId){
|
||||
// update row
|
||||
let api = context.tableApi.row('#' + rowId).data(structureData);
|
||||
api.nodes().to$().data('animationStatus', 'changed').destroyTimestampCounter();
|
||||
|
||||
touchedRows.push(api.id());
|
||||
}else{
|
||||
// insert new row
|
||||
//context.tableApi.row.add(structureData).nodes().to$().data('animationStatus', 'added');
|
||||
let api = context.tableApi.row.add(structureData);
|
||||
api.nodes().to$().data('animationStatus', 'added');
|
||||
|
||||
touchedRows.push(api.id());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(context.removeMissing){
|
||||
context.tableApi.rows((idx, data, node) => !touchedRows.includes(node.id)).remove();
|
||||
}
|
||||
|
||||
context.tableApi.draw();
|
||||
};
|
||||
|
||||
/**
|
||||
* callback -> delete structure rows
|
||||
* @param context
|
||||
* @param responseData
|
||||
*/
|
||||
let callbackDeleteStructures = (context, responseData) => {
|
||||
let structureIds = Util.getObjVal(responseData, 'deletedStructureIds');
|
||||
if(structureIds && structureIds.length){
|
||||
for(let structureId of structureIds){
|
||||
let rowId = getRowId(context.tableApi, structureId);
|
||||
if(rowId){
|
||||
context.tableApi.row('#' + rowId).remove();
|
||||
}
|
||||
}
|
||||
context.tableApi.draw();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* send ajax request
|
||||
* @param url
|
||||
* @param requestData
|
||||
* @param context
|
||||
* @param callback
|
||||
*/
|
||||
let sendRequest = (url, requestData, context, callback) => {
|
||||
context.moduleElement.showLoadingAnimation();
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: requestData,
|
||||
context: context
|
||||
}).done(function(data){
|
||||
callback(this, data);
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
let reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': System intel data', text: reason, type: 'warning'});
|
||||
$(document).setProgramStatus('problem');
|
||||
}).always(function(){
|
||||
// hide loading animation
|
||||
this.moduleElement.hideLoadingAnimation();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* requests system data
|
||||
* @param requestData
|
||||
* @param context
|
||||
* @param callback
|
||||
*/
|
||||
let getStructureData = (requestData, context, callback) => {
|
||||
sendRequest(Init.path.getSystemData, requestData, context, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* save structure data
|
||||
* @param requestData
|
||||
* @param context
|
||||
* @param callback
|
||||
*/
|
||||
let saveStructureData = (requestData, context, callback) => {
|
||||
sendRequest(Init.path.saveStructureData, requestData, context, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* delete structure
|
||||
* @param requestData
|
||||
* @param context
|
||||
* @param callback
|
||||
*/
|
||||
let deleteStructure = (requestData, context, callback) => {
|
||||
sendRequest(Init.path.deleteStructureData, requestData, context, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* show structure dialog
|
||||
* @param moduleElement
|
||||
* @param tableApi
|
||||
* @param systemId
|
||||
* @param structureData
|
||||
*/
|
||||
let showStructureDialog = (moduleElement, tableApi, systemId, structureData) => {
|
||||
let structureStatusData = Util.getObjVal(Init, 'structureStatus');
|
||||
let structureTypeData = Util.getObjVal(Init, 'structureStatus');
|
||||
|
||||
let data = {
|
||||
id: config.structureDialogId,
|
||||
structureData: structureData,
|
||||
structureStatus: Object.keys(structureStatusData).map((k) => {
|
||||
let data = structureStatusData[k];
|
||||
data.selected = data.id === Util.getObjVal(structureData, 'status.id');
|
||||
return data;
|
||||
}),
|
||||
typeSelectId: config.typeSelectId,
|
||||
corporationSelectId: config.corporationSelectId,
|
||||
descriptionTextareaId: config.descriptionTextareaId,
|
||||
descriptionTextareaCharCounter: config.descriptionTextareaCharCounter,
|
||||
maxDescriptionLength: maxDescriptionLength
|
||||
};
|
||||
|
||||
requirejs(['text!templates/dialog/structure.html', 'mustache'], (template, Mustache) => {
|
||||
let content = Mustache.render(template, data);
|
||||
|
||||
let structureDialog = bootbox.dialog({
|
||||
title: 'Structure',
|
||||
message: content,
|
||||
show: true,
|
||||
buttons: {
|
||||
close: {
|
||||
label: 'cancel',
|
||||
className: 'btn-default'
|
||||
},
|
||||
success: {
|
||||
label: '<i class="fas fa-fw fa-check"></i> save',
|
||||
className: 'btn-success',
|
||||
callback: function (){
|
||||
let form = this.find('form');
|
||||
|
||||
// validate form
|
||||
form.validator('validate');
|
||||
|
||||
// check whether the form is valid
|
||||
let formValid = form.isValidForm();
|
||||
|
||||
if(formValid){
|
||||
// get form data
|
||||
let formData = form.getFormValues();
|
||||
formData.id = Util.getObjVal(structureData, 'id') | 0;
|
||||
formData.structureId = Util.getObjVal(formData, 'structureId') | 0;
|
||||
formData.corporationId = Util.getObjVal(formData, 'corporationId') | 0;
|
||||
formData.systemId = systemId | 0;
|
||||
|
||||
saveStructureData(formData,{
|
||||
moduleElement: moduleElement,
|
||||
tableApi: tableApi
|
||||
}, callbackUpdateStructureRows);
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
structureDialog.on('shown.bs.modal', function(e) {
|
||||
// init type select live search
|
||||
let selectElementType = $(this).find('#' + config.typeSelectId);
|
||||
selectElementType.initUniverseTypeSelect({
|
||||
categoryIds: [65],
|
||||
maxSelectionLength: 1,
|
||||
selected: [Util.getObjVal(structureData, 'structure.id')]
|
||||
});
|
||||
|
||||
// init corporation select live search
|
||||
let selectElementCorporation = $(this).find('#' + config.corporationSelectId);
|
||||
selectElementCorporation.initUniverseSearch({
|
||||
categoryNames: ['corporation'],
|
||||
maxSelectionLength: 1
|
||||
});
|
||||
|
||||
// init character counter
|
||||
let textarea = $(this).find('#' + config.descriptionTextareaId);
|
||||
let charCounter = $(this).find('.' + config.descriptionTextareaCharCounter);
|
||||
Util.updateCounter(textarea, charCounter, maxDescriptionLength);
|
||||
|
||||
textarea.on('keyup', function(){
|
||||
Util.updateCounter($(this), charCounter, maxDescriptionLength);
|
||||
});
|
||||
|
||||
// set form validator (after select2 init finish)
|
||||
$(this).find('form').initFormValidation();
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* get module element
|
||||
* @returns {*}
|
||||
*/
|
||||
let getModule = (parentElement, mapId, systemData) => {
|
||||
let corporationId = Util.getCurrentUserInfo('corporationId');
|
||||
|
||||
// create new module container
|
||||
let moduleElement = $('<div>').append(
|
||||
$('<div>', {
|
||||
class: config.moduleHeadClass
|
||||
}).append(
|
||||
$('<h5>', {
|
||||
class: config.moduleHandlerClass
|
||||
}),
|
||||
$('<h5>', {
|
||||
class: 'pull-right'
|
||||
}).append(
|
||||
$('<i>', {
|
||||
class: ['fas', 'fa-fw', 'fa-plus', config.moduleHeadlineIconClass, config.moduleHeadlineIconAddClass].join(' '),
|
||||
title: 'add'
|
||||
}).attr('data-html', 'true').attr('data-toggle', 'tooltip'),
|
||||
$('<i>', {
|
||||
class: ['fas', 'fa-fw', 'fa-sync', config.moduleHeadlineIconClass, config.moduleHeadlineIconRefreshClass].join(' '),
|
||||
title: 'refresh all'
|
||||
}).attr('data-html', 'true').attr('data-toggle', 'tooltip')
|
||||
),
|
||||
$('<h5>', {
|
||||
text: 'Intel'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
let table = $('<table>', {
|
||||
class: ['compact', 'stripe', 'order-column', 'row-border', 'pf-table-fixed', config.systemStructuresTableClass].join(' ')
|
||||
});
|
||||
moduleElement.append(table);
|
||||
|
||||
let structureTable = table.DataTable({
|
||||
paging: false,
|
||||
lengthChange: false,
|
||||
ordering: true,
|
||||
order: [[ 10, 'desc' ], [ 0, 'asc' ]],
|
||||
info: false,
|
||||
searching: false,
|
||||
hover: false,
|
||||
autoWidth: false,
|
||||
rowId: rowData => config.tableRowIdPrefix + rowData.id,
|
||||
language: {
|
||||
emptyTable: 'No structures recorded',
|
||||
info: '_START_ to _END_ of _MAX_',
|
||||
infoEmpty: ''
|
||||
},
|
||||
rowGroup: {
|
||||
enable: true,
|
||||
dataSrc: 'systemId'
|
||||
},
|
||||
columnDefs: [
|
||||
{
|
||||
targets: 0,
|
||||
title: '',
|
||||
width: 2,
|
||||
class: 'text-center',
|
||||
data: 'status',
|
||||
render: {
|
||||
display: data => getStatusData(data),
|
||||
sort: data => data.id
|
||||
},
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
$(cell).find('i').tooltip();
|
||||
}
|
||||
},{
|
||||
targets: 1,
|
||||
title: '',
|
||||
width: 26,
|
||||
orderable: false,
|
||||
className: [config.tableCellImageClass, 'text-center'].join(' '),
|
||||
data: 'structure.id',
|
||||
defaultContent: '<i class="fas fa-question txt-color txt-color-orangeDark"></i>',
|
||||
render: {
|
||||
_: function(data, type, row, meta){
|
||||
let value = data;
|
||||
if(type === 'display' && value){
|
||||
value = '<img src="' + Init.url.ccpImageServer + '/Type/' + value + '_32.png" />';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
},{
|
||||
targets: 2,
|
||||
title: 'structure',
|
||||
width: 50,
|
||||
className: [config.tableCellEllipsisClass].join(' '),
|
||||
data: 'structure.name',
|
||||
defaultContent: '<i class="fas fa-question txt-color txt-color-orangeDark"></i>',
|
||||
},{
|
||||
targets: 3,
|
||||
title: 'name',
|
||||
width: 60,
|
||||
className: [config.tableCellEllipsisClass].join(' '),
|
||||
data: 'name'
|
||||
},{
|
||||
targets: 4,
|
||||
title: '',
|
||||
width: 26,
|
||||
orderable: false,
|
||||
className: [config.tableCellImageClass, 'text-center'].join(' '),
|
||||
data: 'owner.id',
|
||||
defaultContent: '<i class="fas fa-question txt-color txt-color-orangeDark"></i>',
|
||||
render: {
|
||||
_: function(data, type, row, meta){
|
||||
let value = data;
|
||||
if(type === 'display' && value){
|
||||
value = '<img src="' + Init.url.ccpImageServer + '/Corporation/' + value + '_32.png" />';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
},{
|
||||
targets: 5,
|
||||
title: 'owner',
|
||||
width: 50,
|
||||
className: [config.tableCellEllipsisClass].join(' '),
|
||||
data: 'owner.name',
|
||||
defaultContent: '<i class="fas fa-question txt-color txt-color-orangeDark"></i>',
|
||||
},{
|
||||
targets: 6,
|
||||
title: 'note',
|
||||
className: [config.tableCellEllipsisClass].join(' '),
|
||||
data: 'description'
|
||||
},{
|
||||
targets: 7,
|
||||
title: 'updated',
|
||||
width: 80,
|
||||
className: ['text-right', config.tableCellCounterClass].join(' '),
|
||||
data: 'updated.updated'
|
||||
},{
|
||||
targets: 8,
|
||||
title: '',
|
||||
orderable: false,
|
||||
width: 10,
|
||||
class: ['text-center', config.dataTableActionCellClass, config.moduleHeadlineIconClass].join(' '),
|
||||
data: null,
|
||||
render: {
|
||||
display: data => {
|
||||
let icon = '<i class="fas fa-pencil-alt"></i>';
|
||||
if(data.corporation.id !== corporationId){
|
||||
icon = '';
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
},
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
let tableApi = this.api();
|
||||
|
||||
if($(cell).is(':empty')){
|
||||
$(cell).removeClass(config.dataTableActionCellClass + ' ' + config.moduleHeadlineIconClass);
|
||||
}else{
|
||||
$(cell).on('click', function(e) {
|
||||
// get current row data (important!)
|
||||
// -> "rowData" param is not current state, values are "on createCell()" state
|
||||
rowData = tableApi.row( $(cell).parents('tr')).data();
|
||||
showStructureDialog(moduleElement, tableApi, systemData.systemId, rowData);
|
||||
});
|
||||
}
|
||||
}
|
||||
},{
|
||||
targets: 9,
|
||||
title: '',
|
||||
orderable: false,
|
||||
width: 10,
|
||||
class: ['text-center', config.dataTableActionCellClass].join(' '),
|
||||
data: null,
|
||||
render: {
|
||||
display: data => {
|
||||
let icon = '<i class="fas fa-times txt-color txt-color-redDarker"></i>';
|
||||
if(data.corporation.id !== corporationId){
|
||||
icon = '<i class="fas fa-ban txt-color txt-color-grayLight" title="restricted" data-placement="left"></i>';
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
},
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
let tableApi = this.api();
|
||||
|
||||
if($(cell).find('.fa-ban').length){
|
||||
$(cell).removeClass(config.dataTableActionCellClass + ' ' + config.moduleHeadlineIconClass);
|
||||
$(cell).find('i').tooltip();
|
||||
}else{
|
||||
let confirmationSettings = {
|
||||
container: 'body',
|
||||
placement: 'left',
|
||||
btnCancelClass: 'btn btn-sm btn-default',
|
||||
btnCancelLabel: 'cancel',
|
||||
btnCancelIcon: 'fas fa-fw fa-ban',
|
||||
title: 'delete structure',
|
||||
btnOkClass: 'btn btn-sm btn-danger',
|
||||
btnOkLabel: 'delete',
|
||||
btnOkIcon: 'fas fa-fw fa-times',
|
||||
onConfirm : function(e, target){
|
||||
// get current row data (important!)
|
||||
// -> "rowData" param is not current state, values are "on createCell()" state
|
||||
rowData = tableApi.row( $(cell).parents('tr')).data();
|
||||
|
||||
// let deleteRowElement = $(cell).parents('tr');
|
||||
// tableApi.rows(deleteRowElement).remove().draw();
|
||||
deleteStructure({
|
||||
id: rowData.id
|
||||
},{
|
||||
moduleElement: moduleElement,
|
||||
tableApi: tableApi
|
||||
}, callbackDeleteStructures);
|
||||
}
|
||||
};
|
||||
|
||||
// init confirmation dialog
|
||||
$(cell).confirmation(confirmationSettings);
|
||||
}
|
||||
}
|
||||
},{
|
||||
targets: 10,
|
||||
name: 'corporation',
|
||||
data: 'corporation',
|
||||
visible: false,
|
||||
render: {
|
||||
sort: function(data){
|
||||
return data.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
drawCallback: function (settings){
|
||||
let tableApi = this.api();
|
||||
let columnCount = tableApi.columns(':visible').count();
|
||||
let rows = tableApi.rows( {page:'current'} ).nodes();
|
||||
let last= null;
|
||||
|
||||
tableApi.column('corporation:name', {page:'current'} ).data().each( function ( group, i ) {
|
||||
if ( !last || last.id !== group.id ) {
|
||||
$(rows).eq(i).before(
|
||||
'<tr class="group">' +
|
||||
'<td></td>' +
|
||||
'<td class="' + config.tableCellImageClass + '">' +
|
||||
'<img src="' + Init.url.ccpImageServer + '/Corporation/' + group.id + '_32.png" />' +
|
||||
'</td>' +
|
||||
'<td colspan="' + (columnCount - 2 ) + '">' + group.name + '</td>' +
|
||||
'</tr>'
|
||||
);
|
||||
last = group;
|
||||
}
|
||||
});
|
||||
|
||||
rows.to$().find('.' + config.tableCellCounterClass + ':not([data-counter])').initTimestampCounter();
|
||||
|
||||
let animationRows = rows.to$().filter(function() {
|
||||
return (
|
||||
$(this).data('animationStatus') ||
|
||||
$(this).data('animationTimer')
|
||||
);
|
||||
});
|
||||
|
||||
for(let i = 0; i < animationRows.length; i++){
|
||||
let animationRow = $(animationRows[i]);
|
||||
animationRow.pulseTableRow(animationRow.data('animationStatus'));
|
||||
animationRow.removeData('animationStatus');
|
||||
}
|
||||
},
|
||||
initComplete: function(settings){
|
||||
let tableApi = this.api();
|
||||
|
||||
// initial structure data request
|
||||
getStructureData({
|
||||
mapId: mapId,
|
||||
systemId: systemData.id
|
||||
},{
|
||||
moduleElement: moduleElement,
|
||||
tableApi: tableApi
|
||||
}, callbackAddStructureRows);
|
||||
}
|
||||
});
|
||||
|
||||
// init tooltips for this module
|
||||
let tooltipElements = moduleElement.find('[data-toggle="tooltip"]');
|
||||
tooltipElements.tooltip({
|
||||
container: 'body'
|
||||
});
|
||||
|
||||
return moduleElement;
|
||||
};
|
||||
|
||||
/**
|
||||
* init intel module
|
||||
* @param moduleElement
|
||||
* @param mapId
|
||||
* @param systemData
|
||||
*/
|
||||
let initModule = (moduleElement, mapId, systemData) => {
|
||||
|
||||
let structureTableElement = moduleElement.find('.' + config.systemStructuresTableClass);
|
||||
let tableApi = structureTableElement.DataTable();
|
||||
|
||||
// init structure dialog --------------------------------------------------------------------------------------
|
||||
moduleElement.find('.' + config.moduleHeadlineIconAddClass).on('click', function(e){
|
||||
showStructureDialog(moduleElement, tableApi, systemData.systemId);
|
||||
});
|
||||
|
||||
// init refresh button ----------------------------------------------------------------------------------------
|
||||
moduleElement.find('.' + config.moduleHeadlineIconRefreshClass).on('click', function(e){
|
||||
getStructureData({
|
||||
mapId: mapId,
|
||||
systemId: systemData.id
|
||||
},{
|
||||
moduleElement: moduleElement,
|
||||
tableApi: tableApi,
|
||||
removeMissing: true
|
||||
}, callbackAddStructureRows);
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
config: config,
|
||||
getModule: getModule,
|
||||
initModule: initModule
|
||||
};
|
||||
|
||||
});
|
||||
@@ -46,6 +46,11 @@ define([
|
||||
return label;
|
||||
};
|
||||
|
||||
/**
|
||||
* show killMails
|
||||
* @param moduleElement
|
||||
* @param killboardData
|
||||
*/
|
||||
let showKillmails = function(moduleElement, killboardData){
|
||||
|
||||
// show number of killMails
|
||||
|
||||
@@ -8,7 +8,7 @@ define([
|
||||
'app/util',
|
||||
'bootbox',
|
||||
'app/map/util'
|
||||
], function($, Init, Util, bootbox, MapUtil) {
|
||||
], ($, Init, Util, bootbox, MapUtil) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
@@ -103,7 +103,7 @@ define([
|
||||
* @param context
|
||||
* @param routesData
|
||||
*/
|
||||
let callbackAddRouteRow = (context, routesData) => {
|
||||
let callbackAddRouteRows = (context, routesData) => {
|
||||
|
||||
if(routesData.length > 0){
|
||||
for(let i = 0; i < routesData.length; i++){
|
||||
@@ -170,7 +170,6 @@ define([
|
||||
return rowElement;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* requests route data from eveCentral API and execute callback
|
||||
* @param requestData
|
||||
@@ -210,7 +209,7 @@ define([
|
||||
routeData.push( getRouteRequestDataFromRowData( this.data() ));
|
||||
});
|
||||
|
||||
getRouteData({routeData: routeData}, context, callbackAddRouteRow);
|
||||
getRouteData({routeData: routeData}, context, callbackAddRouteRows);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -261,7 +260,7 @@ define([
|
||||
mapSelectOptions: mapSelectOptions
|
||||
};
|
||||
|
||||
requirejs(['text!templates/dialog/route.html', 'mustache'], function(template, Mustache) {
|
||||
requirejs(['text!templates/dialog/route.html', 'mustache'], (template, Mustache) => {
|
||||
|
||||
let content = Mustache.render(template, data);
|
||||
|
||||
@@ -326,7 +325,7 @@ define([
|
||||
}]
|
||||
};
|
||||
|
||||
getRouteData(requestData, context, callbackAddRouteRow);
|
||||
getRouteData(requestData, context, callbackAddRouteRows);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -418,7 +417,7 @@ define([
|
||||
routeData: requestRouteData
|
||||
};
|
||||
|
||||
getRouteData(requestData, contextData, callbackAddRouteRow);
|
||||
getRouteData(requestData, contextData, callbackAddRouteRows);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -432,7 +431,7 @@ define([
|
||||
let showSettingsDialog = (dialogData, moduleElement, systemFromData, routesTable) => {
|
||||
|
||||
let promiseStore = MapUtil.getLocaleData('map', dialogData.mapId);
|
||||
promiseStore.then(function(dataStore) {
|
||||
promiseStore.then(dataStore => {
|
||||
// selected systems (if already stored)
|
||||
let systemSelectOptions = [];
|
||||
if(
|
||||
@@ -902,7 +901,6 @@ define([
|
||||
)
|
||||
);
|
||||
|
||||
// crate new route table
|
||||
let table = $('<table>', {
|
||||
class: ['compact', 'stripe', 'order-column', 'row-border', config.systemInfoRoutesTableClass].join(' ')
|
||||
});
|
||||
@@ -1039,7 +1037,7 @@ define([
|
||||
routeData: [routeData]
|
||||
};
|
||||
|
||||
getRouteData(requestData, context, callbackAddRouteRow);
|
||||
getRouteData(requestData, context, callbackAddRouteRows);
|
||||
});
|
||||
}
|
||||
},{
|
||||
@@ -1074,7 +1072,7 @@ define([
|
||||
routeData: [routeData]
|
||||
};
|
||||
|
||||
getRouteData(requestData, context, callbackAddRouteRow);
|
||||
getRouteData(requestData, context, callbackAddRouteRows);
|
||||
});
|
||||
}
|
||||
},{
|
||||
@@ -1122,10 +1120,10 @@ define([
|
||||
});
|
||||
|
||||
for(let i = 0; i < animationRows.length; i++){
|
||||
$(animationRows[i]).pulseTableRow($(animationRows[i]).data('animationStatus'));
|
||||
$(animationRows[i]).removeData('animationStatus');
|
||||
let animationRow = $(animationRows[i]);
|
||||
animationRow.pulseTableRow(animationRow.data('animationStatus'));
|
||||
animationRow.removeData('animationStatus');
|
||||
}
|
||||
|
||||
},
|
||||
initComplete: function(settings, json){
|
||||
// click on "fake connection" -------------------------------------------------------------------------
|
||||
@@ -1231,7 +1229,6 @@ define([
|
||||
};
|
||||
|
||||
let routesTableElement = moduleElement.find('.' + config.systemInfoRoutesTableClass);
|
||||
|
||||
let routesTable = routesTableElement.DataTable();
|
||||
|
||||
// init refresh routes --------------------------------------------------------------------
|
||||
|
||||
102
js/app/util.js
102
js/app/util.js
@@ -15,7 +15,8 @@ define([
|
||||
'easyPieChart',
|
||||
'hoverIntent',
|
||||
'bootstrapConfirmation',
|
||||
'bootstrapToggle'
|
||||
'bootstrapToggle',
|
||||
'select2'
|
||||
], ($, Init, SystemEffect, SignatureType, bootbox, localforage) => {
|
||||
|
||||
'use strict';
|
||||
@@ -55,6 +56,8 @@ define([
|
||||
mapWrapperClass: 'pf-map-wrapper', // wrapper div (scrollable)
|
||||
mapClass: 'pf-map' , // class for all maps
|
||||
|
||||
// select2
|
||||
select2Class: 'pf-select2', // class for all "Select2" <select> elements
|
||||
|
||||
// animation
|
||||
animationPulseSuccessClass: 'pf-animation-pulse-success', // animation class
|
||||
@@ -962,14 +965,78 @@ define([
|
||||
};
|
||||
|
||||
/**
|
||||
* set default configuration for "Bootbox" dialogs
|
||||
* set default configuration for "Bootbox"
|
||||
*/
|
||||
let initDefaultBootboxConfig = function(){
|
||||
let initDefaultBootboxConfig = () => {
|
||||
bootbox.setDefaults({
|
||||
onEscape: true // enables close dialogs on ESC key
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* set default configuration for "Select2"
|
||||
*/
|
||||
let initDefaultSelect2Config = () => {
|
||||
$.fn.select2.defaults.set('theme', 'pathfinder');
|
||||
|
||||
let initScrollbar = (resultsWrapper) => {
|
||||
// default 'mousewheel' event set by select2 needs to be disabled
|
||||
// in order to make mCustomScrollbar mouseWheel enable works correctly
|
||||
$(resultsWrapper).find('ul.select2-results__options').off('mousewheel');
|
||||
|
||||
resultsWrapper.mCustomScrollbar({
|
||||
mouseWheel: {
|
||||
enable: true,
|
||||
scrollAmount: 'auto',
|
||||
axis: 'y',
|
||||
preventDefault: true
|
||||
},
|
||||
keyboard: {
|
||||
enable: false,
|
||||
scrollType: 'stepless',
|
||||
scrollAmount: 'auto'
|
||||
},
|
||||
scrollbarPosition: 'inside',
|
||||
autoDraggerLength: true,
|
||||
autoHideScrollbar: false,
|
||||
advanced: {
|
||||
updateOnContentResize: true
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let getResultsWrapper = (selectElement) => {
|
||||
let wrapper = null;
|
||||
let selectElementId = selectElement.getAttribute('data-select2-id');
|
||||
if(selectElementId){
|
||||
let resultsOptions = $('#select2-' + selectElementId + '-results');
|
||||
if(resultsOptions.length) {
|
||||
let resultsWrapper = resultsOptions.parents('.select2-results');
|
||||
if(resultsWrapper.length){
|
||||
wrapper = resultsWrapper;
|
||||
}
|
||||
}
|
||||
}
|
||||
return wrapper;
|
||||
};
|
||||
|
||||
// global open event
|
||||
$(document).on('select2:open', '.' + config.select2Class, function(e){
|
||||
let resultsWrapper = getResultsWrapper(this);
|
||||
if(resultsWrapper){
|
||||
initScrollbar(resultsWrapper);
|
||||
}
|
||||
});
|
||||
|
||||
// global select2:closing event
|
||||
$(document).on('select2:closing', '.' + config.select2Class, function(e){
|
||||
let resultsWrapper = getResultsWrapper(this);
|
||||
if(resultsWrapper){
|
||||
resultsWrapper.mCustomScrollbar('destroy');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* get the current main trigger delay for the main trigger functions
|
||||
* optional in/decrease the delay
|
||||
@@ -1104,6 +1171,33 @@ define([
|
||||
return duration;
|
||||
};
|
||||
|
||||
/**
|
||||
* update a character counter field with current value length - maxCharLength
|
||||
* @param field
|
||||
* @param charCounterElement
|
||||
* @param maxCharLength
|
||||
*/
|
||||
let updateCounter = function(field, charCounterElement, maxCharLength){
|
||||
let value = field.val();
|
||||
let inputLength = value.length;
|
||||
|
||||
// line breaks are 2 characters!
|
||||
let newLines = value.match(/(\r\n|\n|\r)/g);
|
||||
let addition = 0;
|
||||
if (newLines != null) {
|
||||
addition = newLines.length;
|
||||
}
|
||||
inputLength += addition;
|
||||
|
||||
charCounterElement.text(maxCharLength - inputLength);
|
||||
|
||||
if(maxCharLength <= inputLength){
|
||||
charCounterElement.toggleClass('txt-color-red', true);
|
||||
}else{
|
||||
charCounterElement.toggleClass('txt-color-red', false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* trigger main logging event with log information
|
||||
* @param logKey
|
||||
@@ -2413,12 +2507,14 @@ define([
|
||||
showVersionInfo: showVersionInfo,
|
||||
initPrototypes: initPrototypes,
|
||||
initDefaultBootboxConfig: initDefaultBootboxConfig,
|
||||
initDefaultSelect2Config: initDefaultSelect2Config,
|
||||
getCurrentTriggerDelay: getCurrentTriggerDelay,
|
||||
getServerTime: getServerTime,
|
||||
convertTimestampToServerTime: convertTimestampToServerTime,
|
||||
getTimeDiffParts: getTimeDiffParts,
|
||||
timeStart: timeStart,
|
||||
timeStop: timeStop,
|
||||
updateCounter: updateCounter,
|
||||
log: log,
|
||||
showNotify: showNotify,
|
||||
stopTabBlink: stopTabBlink,
|
||||
|
||||
4
js/lib/select2.min.js
vendored
4
js/lib/select2.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -153,7 +153,7 @@ requirejs.config({
|
||||
deps : ['jquery']
|
||||
},
|
||||
select2: {
|
||||
deps : ['jquery'],
|
||||
deps : ['jquery', 'mousewheel'],
|
||||
exports: 'Select2'
|
||||
},
|
||||
validator: {
|
||||
|
||||
@@ -67,9 +67,10 @@ define([
|
||||
*/
|
||||
$.fn.destroyTimestampCounter = function(){
|
||||
return this.each(function(){
|
||||
let element = $(this);
|
||||
element.find('[data-counter="init"]').each(function(){
|
||||
let interval = $(this).data('interval');
|
||||
let parentElement = $(this);
|
||||
parentElement.find('[data-counter="init"]').each(function(){
|
||||
let element = $(this);
|
||||
let interval = element.data('interval');
|
||||
if(interval){
|
||||
clearInterval(interval);
|
||||
element.removeAttr('data-counter')
|
||||
|
||||
@@ -33,6 +33,7 @@ define(['jquery'], ($) => {
|
||||
getMapConnectionData: '/api/map/getConnectionData', // ajax URL - get connection data
|
||||
getMapLogData: '/api/map/getLogData', // ajax URL - get logs data
|
||||
// system API
|
||||
getSystemData: '/api/system/getData', // ajax URL - get system data
|
||||
searchSystem: '/api/system/search', // ajax URL - search system by name
|
||||
saveSystem: '/api/system/save', // ajax URL - saves system to map
|
||||
deleteSystem: '/api/system/delete', // ajax URL - delete system from map
|
||||
@@ -47,10 +48,15 @@ define(['jquery'], ($) => {
|
||||
getSignatures: '/api/signature/getAll', // ajax URL - get all signature data for system
|
||||
saveSignatureData: '/api/signature/save', // ajax URL - save signature data for system
|
||||
deleteSignatureData: '/api/signature/delete', // ajax URL - delete signature data for system
|
||||
// structure API
|
||||
saveStructureData: '/api/structure/save', // ajax URL - save structure data
|
||||
deleteStructureData: '/api/structure/delete', // ajax URL - delete structure data
|
||||
// route API
|
||||
searchRoute: '/api/route/search', // ajax URL - search system routes
|
||||
// stats API
|
||||
getStatisticsData: '/api/statistic/getData', // ajax URL - get statistics data (activity log)
|
||||
// universe API
|
||||
searchUniverseData: '/api/universe/search', // ajax URL - search universe data
|
||||
// GitHub API
|
||||
gitHubReleases: '/api/github/releases' // ajax URL - get release info from GitHub
|
||||
},
|
||||
|
||||
@@ -105,6 +105,10 @@ define([
|
||||
let ssoButtonElement = $('.' + config.ssoButtonClass);
|
||||
let cookieHintElement = $('#' + config.cookieHintId);
|
||||
|
||||
$(document).on('click', '.' + config.ssoButtonClass + ', .' + config.characterSelectionClass + ' a', function(){
|
||||
$('.' + config.splashOverlayClass).showSplashOverlay();
|
||||
});
|
||||
|
||||
// cookie hint --------------------------------------------------------
|
||||
cookieHintElement.find('.btn-success').on('click', function(){
|
||||
setAcceptCookie();
|
||||
@@ -683,11 +687,6 @@ define([
|
||||
let content = Mustache.render(template, data);
|
||||
this.characterElement.html(content);
|
||||
|
||||
// lock character selection on click (prevent click spamming)
|
||||
this.characterElement.find('a').on('click', function(){
|
||||
$('.' + config.splashOverlayClass).showSplashOverlay();
|
||||
});
|
||||
|
||||
// show character panel (animation settings)
|
||||
initCharacterAnimation(this.characterElement.find('.' + config.characterImageWrapperClass));
|
||||
}else{
|
||||
|
||||
@@ -14,7 +14,6 @@ define([
|
||||
'app/map/magnetizing',
|
||||
'app/map/scrollbar',
|
||||
'dragToSelect',
|
||||
'select2',
|
||||
'app/map/contextmenu',
|
||||
'app/map/overlay',
|
||||
'app/map/local'
|
||||
|
||||
@@ -32,6 +32,9 @@ define([
|
||||
// set default dialog config
|
||||
Util.initDefaultBootboxConfig();
|
||||
|
||||
// set default select2 config
|
||||
Util.initDefaultSelect2Config();
|
||||
|
||||
// load page
|
||||
// load info (maintenance) info panel (if scheduled)
|
||||
$('body').loadPageStructure().setGlobalShortcuts();
|
||||
@@ -128,6 +131,8 @@ define([
|
||||
Init.url = response.url;
|
||||
Init.slack = response.slack;
|
||||
Init.discord = response.discord;
|
||||
Init.structureStatus = response.structureStatus;
|
||||
Init.universeCategories = response.universeCategories;
|
||||
Init.routeSearch = response.routeSearch;
|
||||
Init.programMode = response.programMode;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ define([
|
||||
'app/ui/system_graph',
|
||||
'app/ui/system_signature',
|
||||
'app/ui/system_route',
|
||||
'app/ui/system_intel',
|
||||
'app/ui/system_killboard',
|
||||
'app/ui/connection_info',
|
||||
'app/counter'
|
||||
@@ -23,6 +24,7 @@ define([
|
||||
SystemGraphModule,
|
||||
SystemSignatureModule,
|
||||
SystemRouteModule,
|
||||
SystemIntelModule,
|
||||
SystemKillboardModule,
|
||||
ConnectionInfoModule
|
||||
) => {
|
||||
@@ -276,6 +278,9 @@ define([
|
||||
// draw system routes module
|
||||
drawModule(secondCell, SystemRouteModule, currentSystemData.mapId, currentSystemData.systemData);
|
||||
|
||||
// draw system intel module
|
||||
drawModule(secondCell, SystemIntelModule, currentSystemData.mapId, currentSystemData.systemData);
|
||||
|
||||
// draw system killboard module
|
||||
drawModule(secondCell, SystemKillboardModule, currentSystemData.mapId, currentSystemData.systemData);
|
||||
});
|
||||
|
||||
@@ -346,7 +346,6 @@ define([
|
||||
let formValid = form.isValidForm();
|
||||
|
||||
if(formValid === true){
|
||||
|
||||
// lock dialog
|
||||
let dialogContent = mapInfoDialog.find('.modal-content');
|
||||
dialogContent.showLoadingAnimation();
|
||||
@@ -391,7 +390,6 @@ define([
|
||||
data: requestData,
|
||||
dataType: 'json'
|
||||
}).done(function(responseData){
|
||||
|
||||
if(responseData.error.length){
|
||||
form.showFormMessage(responseData.error);
|
||||
}else{
|
||||
|
||||
@@ -7,10 +7,67 @@ define([
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/map/util'
|
||||
], function($, Init, Util, MapUtil) {
|
||||
|
||||
], ($, Init, Util, MapUtil) => {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* format result data
|
||||
* @param data
|
||||
* @returns {*}
|
||||
*/
|
||||
let formatCategoryTypeResultData = (data) => {
|
||||
if(data.loading) return data.text;
|
||||
if(data.placeholder) return data.placeholder;
|
||||
|
||||
let markup = '<div class="clearfix">';
|
||||
|
||||
if(data.hasOwnProperty('children')){
|
||||
// category group label
|
||||
markup += '<div class="col-xs-9">' + data.text + '</div>';
|
||||
markup += '<div class="col-xs-3 text-right">(' + data.children.length + ')</div>';
|
||||
}else{
|
||||
let imagePath = '';
|
||||
let iconName = '';
|
||||
let thumb = '';
|
||||
|
||||
switch(data.categoryType){
|
||||
case 'character':
|
||||
imagePath = Init.url.ccpImageServer + '/Character/' + data.id + '_32.jpg';
|
||||
break;
|
||||
case 'corporation':
|
||||
imagePath = Init.url.ccpImageServer + '/Corporation/' + data.id + '_32.png';
|
||||
break;
|
||||
case 'alliance':
|
||||
imagePath = Init.url.ccpImageServer + '/Alliance/' + data.id + '_32.png';
|
||||
break;
|
||||
case 'inventory_type':
|
||||
imagePath = Init.url.ccpImageServer + '/Type/' + data.id + '_32.png';
|
||||
break;
|
||||
case 'render':
|
||||
imagePath = Init.url.ccpImageServer + '/Render/' + data.id + '_32.png';
|
||||
break;
|
||||
case 'station':
|
||||
iconName = 'fa-home';
|
||||
break;
|
||||
case 'solar_system':
|
||||
iconName = 'fa-sun';
|
||||
break;
|
||||
}
|
||||
|
||||
if(imagePath){
|
||||
thumb = '<img src="' + imagePath + '" style="max-width: 100%" />';
|
||||
}else if(iconName){
|
||||
thumb = '<i class="fas fa-fw ' + iconName + '" ></i>';
|
||||
}
|
||||
|
||||
markup += '<div class="col-xs-2 text-center">' + thumb + '</div>';
|
||||
markup += '<div class="col-xs-10">' + data.text + '</div>';
|
||||
}
|
||||
markup += '</div>';
|
||||
|
||||
return markup;
|
||||
};
|
||||
|
||||
/**
|
||||
* init a select element as "select2" for map selection
|
||||
*/
|
||||
@@ -20,7 +77,6 @@ define([
|
||||
$.when(
|
||||
selectElement.select2({
|
||||
dropdownParent: selectElement.parents('.modal-body'),
|
||||
theme: 'pathfinder',
|
||||
maximumSelectionLength: 5
|
||||
})
|
||||
);
|
||||
@@ -133,8 +189,7 @@ define([
|
||||
}
|
||||
},
|
||||
dropdownParent: selectElement.parents('.modal-body'),
|
||||
theme: 'pathfinder',
|
||||
minimumInputLength: 2,
|
||||
minimumInputLength: 3,
|
||||
templateResult: formatResultData,
|
||||
placeholder: 'System name',
|
||||
allowClear: true,
|
||||
@@ -171,52 +226,8 @@ define([
|
||||
$.fn.initAccessSelect = function(options){
|
||||
|
||||
return this.each(function(){
|
||||
|
||||
let selectElement = $(this);
|
||||
|
||||
// format result data
|
||||
function formatResultData (data) {
|
||||
|
||||
if (data.loading){
|
||||
return data.text;
|
||||
}
|
||||
|
||||
// check if an option is already selected
|
||||
// do not show the same result twice
|
||||
let currentValues = selectElement.val();
|
||||
|
||||
if(
|
||||
currentValues &&
|
||||
currentValues.indexOf( data.id.toString() ) !== -1
|
||||
){
|
||||
return ;
|
||||
}
|
||||
|
||||
let imagePath = '';
|
||||
let previewContent = '';
|
||||
|
||||
switch(options.type){
|
||||
case 'character':
|
||||
imagePath = Init.url.ccpImageServer + '/Character/' + data.id + '_32.jpg';
|
||||
previewContent = '<img src="' + imagePath + '" style="max-width: 100%" />';
|
||||
break;
|
||||
case 'corporation':
|
||||
imagePath = Init.url.ccpImageServer + '/Corporation/' + data.id + '_32.png';
|
||||
previewContent = '<img src="' + imagePath + '" style="max-width: 100%" />';
|
||||
break;
|
||||
case 'alliance':
|
||||
imagePath = Init.url.ccpImageServer + '/Alliance/' + data.id + '_32.png';
|
||||
previewContent = '<img src="' + imagePath + '" style="max-width: 100%" />';
|
||||
break;
|
||||
}
|
||||
|
||||
let markup = '<div class="clearfix">';
|
||||
markup += '<div class="col-sm-2">' + previewContent + '</div>';
|
||||
markup += '<div class="col-sm-10">' + data.text + '</div></div>';
|
||||
|
||||
return markup;
|
||||
}
|
||||
|
||||
// format selection data
|
||||
function formatSelectionData (data){
|
||||
|
||||
@@ -251,7 +262,8 @@ define([
|
||||
results: data.map( function(item){
|
||||
return {
|
||||
id: item.id,
|
||||
text: item.name
|
||||
text: item.name,
|
||||
categoryType: options.type
|
||||
};
|
||||
})
|
||||
};
|
||||
@@ -266,12 +278,11 @@ define([
|
||||
}
|
||||
},
|
||||
dropdownParent: selectElement.parents('.modal-body'),
|
||||
theme: 'pathfinder',
|
||||
minimumInputLength: 3,
|
||||
placeholder: options.type + ' names',
|
||||
allowClear: false,
|
||||
maximumSelectionLength: options.maxSelectionLength,
|
||||
templateResult: formatResultData,
|
||||
templateResult: formatCategoryTypeResultData,
|
||||
templateSelection: formatSelectionData,
|
||||
escapeMarkup: function(markup){
|
||||
// let our custom formatter work
|
||||
@@ -288,4 +299,190 @@ define([
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* init a select element as an ajax based "select2" object for universeTypes
|
||||
* e.g. 'alliance', 'corporation', 'character', ...
|
||||
* @param options
|
||||
* @returns {*}
|
||||
*/
|
||||
$.fn.initUniverseSearch = function(options) {
|
||||
|
||||
let showErrorNotification = (reason) => {
|
||||
Util.showNotify({title: 'Search failed', text: reason + ' deleted', type: 'warning'});
|
||||
};
|
||||
|
||||
/**
|
||||
* format selection data
|
||||
* @param data
|
||||
* @returns {*}
|
||||
*/
|
||||
function formatSelectionData (data){
|
||||
if(data.loading) return data.text;
|
||||
if(data.placeholder) return data.placeholder;
|
||||
|
||||
let markup = '<div class="clearfix">';
|
||||
markup += '<div class="col-sm-10">' + data.text + '</div></div>';
|
||||
|
||||
return markup;
|
||||
}
|
||||
|
||||
return this.each(function() {
|
||||
let selectElement = $(this);
|
||||
|
||||
$.when(
|
||||
selectElement.select2({
|
||||
ajax: {
|
||||
type: 'POST',
|
||||
url: function(params){
|
||||
// add params to URL
|
||||
return Init.path.searchUniverseData + '/' + params.term;
|
||||
},
|
||||
dataType: 'json',
|
||||
delay: 250,
|
||||
timeout: 5000,
|
||||
cache: true,
|
||||
data: function(params){
|
||||
return {
|
||||
categories: options.categoryNames
|
||||
};
|
||||
},
|
||||
processResults: function(result, page) {
|
||||
let data = {results: []};
|
||||
if(result.hasOwnProperty('error')){
|
||||
showErrorNotification(result.error);
|
||||
}else{
|
||||
let mapChildren = function(item){
|
||||
return {
|
||||
id: item.id,
|
||||
text: item.name,
|
||||
categoryType: this
|
||||
};
|
||||
};
|
||||
|
||||
for(let category in result){
|
||||
// skip custom functions in case result = [] (array functions)
|
||||
if(result.hasOwnProperty(category)){
|
||||
data.results.push({
|
||||
text: category,
|
||||
children: result[category].map(mapChildren, category)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
error: function (jqXHR, status, error) {
|
||||
if( !Util.isXHRAborted(jqXHR) ){
|
||||
let reason = status + ' ' + jqXHR.status + ': ' + error;
|
||||
showErrorNotification(reason);
|
||||
}
|
||||
}
|
||||
},
|
||||
dropdownParent: selectElement.parents('.modal-body') ,
|
||||
minimumInputLength: 3,
|
||||
placeholder: '',
|
||||
allowClear: options.maxSelectionLength <= 1,
|
||||
maximumSelectionLength: options.maxSelectionLength,
|
||||
templateResult: formatCategoryTypeResultData,
|
||||
// templateSelection: formatSelectionData, // some issues with "clear" selection on single selects (empty option is needed)
|
||||
escapeMarkup: function(markup){
|
||||
// let our custom formatter work
|
||||
return markup;
|
||||
}
|
||||
}).on('change', function(e){
|
||||
// select changed
|
||||
}).on('select2:open', function(){
|
||||
// clear selected system (e.g. default system)
|
||||
// => improves usability (not necessary). There is a small "x" whe it could be cleared manually
|
||||
if(
|
||||
options.maxSelectionLength === 1 &&
|
||||
$(this).val() !== null
|
||||
){
|
||||
$(this).val('').trigger('change');
|
||||
}
|
||||
})
|
||||
).done(function(){
|
||||
// after init finish
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
$.fn.initUniverseTypeSelect = function(options) {
|
||||
|
||||
/**
|
||||
* get select option data by categoryIds
|
||||
* @param categoryIds
|
||||
* @returns {{results: Array}}
|
||||
*/
|
||||
let getOptionsData = categoryIds => {
|
||||
let data = [];
|
||||
|
||||
let mapChildren = function(type){
|
||||
return {
|
||||
id: type.id,
|
||||
text: type.name,
|
||||
groupId: this.groupId,
|
||||
categoryId: this.categoryId,
|
||||
categoryType: this.categoryType
|
||||
};
|
||||
};
|
||||
|
||||
for(let categoryId of categoryIds){
|
||||
let categoryData = Util.getObjVal(Init, 'universeCategories.' + categoryId);
|
||||
if(categoryData && categoryData.groups){
|
||||
// categoryId data exists and has groups...
|
||||
for(let groupData of categoryData.groups){
|
||||
if(groupData && groupData.types){
|
||||
// groupData exists and has types...
|
||||
data.push({
|
||||
text: groupData.name,
|
||||
children: groupData.types.map(mapChildren, {
|
||||
groupId: groupData.id,
|
||||
categoryId: categoryData.id,
|
||||
categoryType: 'inventory_type',
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
return this.each(function() {
|
||||
let selectElement = $(this);
|
||||
|
||||
$.when(
|
||||
selectElement.select2({
|
||||
data: getOptionsData(options.categoryIds),
|
||||
dropdownParent: selectElement.parents('.modal-body'),
|
||||
minimumInputLength: 0, // minimum number of characters required to start a search
|
||||
maximumInputLength: 100, // maximum number of characters that may be provided for a search term
|
||||
placeholder: '',
|
||||
allowClear: options.maxSelectionLength <= 1,
|
||||
multiple: options.maxSelectionLength > 1,
|
||||
maximumSelectionLength: options.maxSelectionLength,
|
||||
// maximumSelectionLength: options.maxSelectionLength > 1 ? options.maxSelectionLength > 1 : 0,
|
||||
// minimumResultsForSearch: 5, // minimum number of results required to display the search box
|
||||
templateResult: formatCategoryTypeResultData,
|
||||
escapeMarkup: function(markup){
|
||||
return markup;
|
||||
}
|
||||
}).on('select2:open', function(){
|
||||
// clear selected system (e.g. default system)
|
||||
// => improves usability (not necessary). There is a small "x" whe it could be cleared manually
|
||||
if(
|
||||
options.maxSelectionLength === 1 &&
|
||||
$(this).val() !== null
|
||||
){
|
||||
$(this).val('').trigger('change');
|
||||
}
|
||||
}).val(options.selected).trigger('change')
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
@@ -169,33 +169,6 @@ define([
|
||||
moduleElement.find('.' + config.descriptionArea).hideLoadingAnimation();
|
||||
};
|
||||
|
||||
/**
|
||||
* update a character counter field with current value length - maxCharLength
|
||||
* @param field
|
||||
* @param charCounterElement
|
||||
* @param maxCharLength
|
||||
*/
|
||||
let updateCounter = function(field, charCounterElement, maxCharLength){
|
||||
let value = field.val();
|
||||
let inputLength = value.length;
|
||||
|
||||
// line breaks are 2 characters!
|
||||
let newLines = value.match(/(\r\n|\n|\r)/g);
|
||||
let addition = 0;
|
||||
if (newLines != null) {
|
||||
addition = newLines.length;
|
||||
}
|
||||
inputLength += addition;
|
||||
|
||||
charCounterElement.text(maxCharLength - inputLength);
|
||||
|
||||
if(maxCharLength <= inputLength){
|
||||
charCounterElement.toggleClass('txt-color-red', true);
|
||||
}else{
|
||||
charCounterElement.toggleClass('txt-color-red', false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* get module element
|
||||
* @param parentElement
|
||||
@@ -319,10 +292,10 @@ define([
|
||||
textarea.parent().next().append(charCounter);
|
||||
|
||||
// update character counter
|
||||
updateCounter(textarea, charCounter, maxDescriptionLength);
|
||||
Util.updateCounter(textarea, charCounter, maxDescriptionLength);
|
||||
|
||||
textarea.on('keyup', function(){
|
||||
updateCounter($(this), charCounter, maxDescriptionLength);
|
||||
Util.updateCounter($(this), charCounter, maxDescriptionLength);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
628
public/js/v1.3.5/app/ui/system_intel.js
Normal file
628
public/js/v1.3.5/app/ui/system_intel.js
Normal file
@@ -0,0 +1,628 @@
|
||||
/**
|
||||
* system route module
|
||||
*/
|
||||
|
||||
define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'bootbox'
|
||||
], ($, Init, Util, bootbox) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
// module info
|
||||
modulePosition: 1,
|
||||
moduleName: 'systemIntel',
|
||||
moduleHeadClass: 'pf-module-head', // class for module header
|
||||
moduleHandlerClass: 'pf-module-handler-drag', // class for "drag" handler
|
||||
moduleTypeClass: 'pf-system-intel-module', // class for this module
|
||||
|
||||
// headline toolbar
|
||||
moduleHeadlineIconClass: 'pf-module-icon-button', // class for toolbar icons in the head
|
||||
moduleHeadlineIconAddClass: 'pf-module-icon-button-add', // class for "add structure" icon
|
||||
moduleHeadlineIconRefreshClass: 'pf-module-icon-button-refresh', // class for "refresh" icon
|
||||
|
||||
// system intel module
|
||||
systemStructuresTableClass: 'pf-system-structure-table', // class for route tables
|
||||
|
||||
// structure dialog
|
||||
structureDialogId: 'pf-structure-dialog', // id for "structure" dialog
|
||||
typeSelectId: 'pf-structure-dialog-type-select', // id for "type" select
|
||||
corporationSelectId: 'pf-structure-dialog-corporation-select', // id for "corporation" select
|
||||
descriptionTextareaId: 'pf-structure-dialog-description-textarea', // id for "description" textarea
|
||||
descriptionTextareaCharCounter: 'pf-form-field-char-count', // class for "character counter" element for form field
|
||||
|
||||
// dataTable
|
||||
tableRowIdPrefix: 'pf-structure-row_', // id prefix for table rows
|
||||
tableCellImageClass: 'pf-table-image-smaller-cell', // class for table "image" cells
|
||||
tableCellCounterClass: 'pf-table-counter-cell', // class for table "counter" cells
|
||||
tableCellEllipsisClass: 'pf-table-cell-ellipses-auto', // class for table "ellipsis" cells
|
||||
dataTableActionCellClass: 'pf-table-action-cell' // class for "action" cells
|
||||
};
|
||||
|
||||
let maxDescriptionLength = 512;
|
||||
|
||||
/**
|
||||
* get status icon for structure
|
||||
* @param statusData
|
||||
* @returns {string}
|
||||
*/
|
||||
let getStatusData = (statusData) => {
|
||||
return '<i class="fas fa-fw fa-circle ' + statusData.class + '" title="' + statusData.label + '"></i>';
|
||||
};
|
||||
|
||||
/**
|
||||
* get <tr> DOM id by id
|
||||
* @param tableApi
|
||||
* @param id
|
||||
* @returns {*}
|
||||
*/
|
||||
let getRowId = (tableApi, id) => {
|
||||
return tableApi.rows().ids().toArray().find(rowId => rowId === config.tableRowIdPrefix + id);
|
||||
};
|
||||
|
||||
/**
|
||||
* callback -> add structure rows from responseData
|
||||
* @param context
|
||||
* @param responseData
|
||||
*/
|
||||
let callbackAddStructureRows = (context, responseData) => {
|
||||
let systemData = Util.getObjVal(responseData, 'system');
|
||||
callbackUpdateStructureRows(context, systemData);
|
||||
};
|
||||
|
||||
/**
|
||||
* callback -> add structure rows from systemData
|
||||
* @param context
|
||||
* @param systemData
|
||||
*/
|
||||
let callbackUpdateStructureRows = (context, systemData) => {
|
||||
let touchedRows = [];
|
||||
if(systemData){
|
||||
let corporations = Util.getObjVal(systemData, 'structures');
|
||||
if(corporations) {
|
||||
for (let [corporationId, corporationData] of Object.entries(corporations)){
|
||||
if(corporationData.structures && corporationData.structures.length){
|
||||
for(let structureData of corporationData.structures){
|
||||
let rowId = getRowId(context.tableApi, structureData.id);
|
||||
|
||||
// add corporation data
|
||||
structureData.corporation = {
|
||||
id: corporationData.id,
|
||||
name: corporationData.name
|
||||
};
|
||||
|
||||
if(rowId){
|
||||
// update row
|
||||
let api = context.tableApi.row('#' + rowId).data(structureData);
|
||||
api.nodes().to$().data('animationStatus', 'changed').destroyTimestampCounter();
|
||||
|
||||
touchedRows.push(api.id());
|
||||
}else{
|
||||
// insert new row
|
||||
//context.tableApi.row.add(structureData).nodes().to$().data('animationStatus', 'added');
|
||||
let api = context.tableApi.row.add(structureData);
|
||||
api.nodes().to$().data('animationStatus', 'added');
|
||||
|
||||
touchedRows.push(api.id());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(touchedRows)
|
||||
|
||||
|
||||
if(context.removeMissing){
|
||||
context.tableApi.rows((idx, data, node) => !touchedRows.includes(node.id)).remove();
|
||||
}
|
||||
|
||||
context.tableApi.draw();
|
||||
};
|
||||
|
||||
/**
|
||||
* callback -> delete structure rows
|
||||
* @param context
|
||||
* @param responseData
|
||||
*/
|
||||
let callbackDeleteStructures = (context, responseData) => {
|
||||
let structureIds = Util.getObjVal(responseData, 'deletedStructureIds');
|
||||
if(structureIds && structureIds.length){
|
||||
for(let structureId of structureIds){
|
||||
let rowId = getRowId(context.tableApi, structureId);
|
||||
if(rowId){
|
||||
context.tableApi.row('#' + rowId).remove();
|
||||
}
|
||||
}
|
||||
context.tableApi.draw();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* send ajax request
|
||||
* @param url
|
||||
* @param requestData
|
||||
* @param context
|
||||
* @param callback
|
||||
*/
|
||||
let sendRequest = (url, requestData, context, callback) => {
|
||||
context.moduleElement.showLoadingAnimation();
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: requestData,
|
||||
context: context
|
||||
}).done(function(data){
|
||||
callback(this, data);
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
let reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': System intel data', text: reason, type: 'warning'});
|
||||
$(document).setProgramStatus('problem');
|
||||
}).always(function(){
|
||||
// hide loading animation
|
||||
this.moduleElement.hideLoadingAnimation();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* requests system data
|
||||
* @param requestData
|
||||
* @param context
|
||||
* @param callback
|
||||
*/
|
||||
let getStructureData = (requestData, context, callback) => {
|
||||
sendRequest(Init.path.getSystemData, requestData, context, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* save structure data
|
||||
* @param requestData
|
||||
* @param context
|
||||
* @param callback
|
||||
*/
|
||||
let saveStructureData = (requestData, context, callback) => {
|
||||
sendRequest(Init.path.saveStructureData, requestData, context, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* delete structure
|
||||
* @param requestData
|
||||
* @param context
|
||||
* @param callback
|
||||
*/
|
||||
let deleteStructure = (requestData, context, callback) => {
|
||||
sendRequest(Init.path.deleteStructureData, requestData, context, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* show structure dialog
|
||||
* @param moduleElement
|
||||
* @param tableApi
|
||||
* @param systemId
|
||||
* @param structureData
|
||||
*/
|
||||
let showStructureDialog = (moduleElement, tableApi, systemId, structureData) => {
|
||||
let structureStatusData = Util.getObjVal(Init, 'structureStatus');
|
||||
let structureTypeData = Util.getObjVal(Init, 'structureStatus');
|
||||
|
||||
let data = {
|
||||
id: config.structureDialogId,
|
||||
structureData: structureData,
|
||||
structureStatus: Object.keys(structureStatusData).map((k) => {
|
||||
let data = structureStatusData[k];
|
||||
data.selected = data.id === Util.getObjVal(structureData, 'status.id');
|
||||
return data;
|
||||
}),
|
||||
typeSelectId: config.typeSelectId,
|
||||
corporationSelectId: config.corporationSelectId,
|
||||
descriptionTextareaId: config.descriptionTextareaId,
|
||||
descriptionTextareaCharCounter: config.descriptionTextareaCharCounter,
|
||||
maxDescriptionLength: maxDescriptionLength
|
||||
};
|
||||
|
||||
requirejs(['text!templates/dialog/structure.html', 'mustache'], (template, Mustache) => {
|
||||
let content = Mustache.render(template, data);
|
||||
|
||||
let structureDialog = bootbox.dialog({
|
||||
title: 'Structure',
|
||||
message: content,
|
||||
show: true,
|
||||
buttons: {
|
||||
close: {
|
||||
label: 'cancel',
|
||||
className: 'btn-default'
|
||||
},
|
||||
success: {
|
||||
label: '<i class="fas fa-fw fa-check"></i> save',
|
||||
className: 'btn-success',
|
||||
callback: function (){
|
||||
let form = this.find('form');
|
||||
|
||||
// validate form
|
||||
form.validator('validate');
|
||||
|
||||
// check whether the form is valid
|
||||
let formValid = form.isValidForm();
|
||||
|
||||
if(formValid){
|
||||
// get form data
|
||||
let formData = form.getFormValues();
|
||||
formData.id = Util.getObjVal(structureData, 'id') | 0;
|
||||
formData.structureId = Util.getObjVal(formData, 'structureId') | 0;
|
||||
formData.corporationId = Util.getObjVal(formData, 'corporationId') | 0;
|
||||
formData.systemId = systemId | 0;
|
||||
|
||||
saveStructureData(formData,{
|
||||
moduleElement: moduleElement,
|
||||
tableApi: tableApi
|
||||
}, callbackUpdateStructureRows);
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
structureDialog.on('shown.bs.modal', function(e) {
|
||||
// init type select live search
|
||||
let selectElementType = $(this).find('#' + config.typeSelectId);
|
||||
selectElementType.initUniverseTypeSelect({
|
||||
categoryIds: [65],
|
||||
maxSelectionLength: 1,
|
||||
selected: [Util.getObjVal(structureData, 'structure.id')]
|
||||
});
|
||||
|
||||
// init corporation select live search
|
||||
let selectElementCorporation = $(this).find('#' + config.corporationSelectId);
|
||||
selectElementCorporation.initUniverseSearch({
|
||||
categoryNames: ['corporation'],
|
||||
maxSelectionLength: 1
|
||||
});
|
||||
|
||||
// init character counter
|
||||
let textarea = $(this).find('#' + config.descriptionTextareaId);
|
||||
let charCounter = $(this).find('.' + config.descriptionTextareaCharCounter);
|
||||
Util.updateCounter(textarea, charCounter, maxDescriptionLength);
|
||||
|
||||
textarea.on('keyup', function(){
|
||||
Util.updateCounter($(this), charCounter, maxDescriptionLength);
|
||||
});
|
||||
|
||||
// set form validator (after select2 init finish)
|
||||
$(this).find('form').initFormValidation();
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* get module element
|
||||
* @returns {*}
|
||||
*/
|
||||
let getModule = (parentElement, mapId, systemData) => {
|
||||
let corporationId = Util.getCurrentUserInfo('corporationId');
|
||||
|
||||
// create new module container
|
||||
let moduleElement = $('<div>').append(
|
||||
$('<div>', {
|
||||
class: config.moduleHeadClass
|
||||
}).append(
|
||||
$('<h5>', {
|
||||
class: config.moduleHandlerClass
|
||||
}),
|
||||
$('<h5>', {
|
||||
class: 'pull-right'
|
||||
}).append(
|
||||
$('<i>', {
|
||||
class: ['fas', 'fa-fw', 'fa-plus', config.moduleHeadlineIconClass, config.moduleHeadlineIconAddClass].join(' '),
|
||||
title: 'add'
|
||||
}).attr('data-html', 'true').attr('data-toggle', 'tooltip'),
|
||||
$('<i>', {
|
||||
class: ['fas', 'fa-fw', 'fa-sync', config.moduleHeadlineIconClass, config.moduleHeadlineIconRefreshClass].join(' '),
|
||||
title: 'refresh all'
|
||||
}).attr('data-html', 'true').attr('data-toggle', 'tooltip')
|
||||
),
|
||||
$('<h5>', {
|
||||
text: 'Intel'
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
let table = $('<table>', {
|
||||
class: ['compact', 'stripe', 'order-column', 'row-border', 'pf-table-fixed', config.systemStructuresTableClass].join(' ')
|
||||
});
|
||||
moduleElement.append(table);
|
||||
|
||||
let structureTable = table.DataTable({
|
||||
paging: false,
|
||||
lengthChange: false,
|
||||
ordering: true,
|
||||
order: [[ 10, 'desc' ], [ 0, 'asc' ]],
|
||||
info: false,
|
||||
searching: false,
|
||||
hover: false,
|
||||
autoWidth: false,
|
||||
rowId: rowData => config.tableRowIdPrefix + rowData.id,
|
||||
language: {
|
||||
emptyTable: 'No structures recorded',
|
||||
info: '_START_ to _END_ of _MAX_',
|
||||
infoEmpty: ''
|
||||
},
|
||||
rowGroup: {
|
||||
enable: true,
|
||||
dataSrc: 'systemId'
|
||||
},
|
||||
columnDefs: [
|
||||
{
|
||||
targets: 0,
|
||||
title: '',
|
||||
width: 2,
|
||||
class: 'text-center',
|
||||
data: 'status',
|
||||
render: {
|
||||
display: data => getStatusData(data),
|
||||
sort: data => data.id
|
||||
},
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
$(cell).find('i').tooltip();
|
||||
}
|
||||
},{
|
||||
targets: 1,
|
||||
title: '',
|
||||
width: 26,
|
||||
orderable: false,
|
||||
className: [config.tableCellImageClass, 'text-center'].join(' '),
|
||||
data: 'structure.id',
|
||||
defaultContent: '<i class="fas fa-question txt-color txt-color-orangeDark"></i>',
|
||||
render: {
|
||||
_: function(data, type, row, meta){
|
||||
let value = data;
|
||||
if(type === 'display' && value){
|
||||
value = '<img src="' + Init.url.ccpImageServer + '/Type/' + value + '_32.png" />';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
},{
|
||||
targets: 2,
|
||||
title: 'structure',
|
||||
width: 50,
|
||||
className: [config.tableCellEllipsisClass].join(' '),
|
||||
data: 'structure.name',
|
||||
defaultContent: '<i class="fas fa-question txt-color txt-color-orangeDark"></i>',
|
||||
},{
|
||||
targets: 3,
|
||||
title: 'name',
|
||||
width: 60,
|
||||
className: [config.tableCellEllipsisClass].join(' '),
|
||||
data: 'name'
|
||||
},{
|
||||
targets: 4,
|
||||
title: '',
|
||||
width: 26,
|
||||
orderable: false,
|
||||
className: [config.tableCellImageClass, 'text-center'].join(' '),
|
||||
data: 'owner.id',
|
||||
defaultContent: '<i class="fas fa-question txt-color txt-color-orangeDark"></i>',
|
||||
render: {
|
||||
_: function(data, type, row, meta){
|
||||
let value = data;
|
||||
if(type === 'display' && value){
|
||||
value = '<img src="' + Init.url.ccpImageServer + '/Corporation/' + value + '_32.png" />';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
},{
|
||||
targets: 5,
|
||||
title: 'owner',
|
||||
width: 50,
|
||||
className: [config.tableCellEllipsisClass].join(' '),
|
||||
data: 'owner.name',
|
||||
defaultContent: '<i class="fas fa-question txt-color txt-color-orangeDark"></i>',
|
||||
},{
|
||||
targets: 6,
|
||||
title: 'note',
|
||||
className: [config.tableCellEllipsisClass].join(' '),
|
||||
data: 'description'
|
||||
},{
|
||||
targets: 7,
|
||||
title: 'updated',
|
||||
width: 80,
|
||||
className: ['text-right', config.tableCellCounterClass].join(' '),
|
||||
data: 'updated.updated'
|
||||
},{
|
||||
targets: 8,
|
||||
title: '',
|
||||
orderable: false,
|
||||
width: 10,
|
||||
class: ['text-center', config.dataTableActionCellClass, config.moduleHeadlineIconClass].join(' '),
|
||||
data: null,
|
||||
render: {
|
||||
display: data => {
|
||||
let icon = '<i class="fas fa-pencil-alt"></i>';
|
||||
if(data.corporation.id !== corporationId){
|
||||
icon = '';
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
},
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
let tableApi = this.api();
|
||||
|
||||
if($(cell).is(':empty')){
|
||||
$(cell).removeClass(config.dataTableActionCellClass + ' ' + config.moduleHeadlineIconClass);
|
||||
}else{
|
||||
$(cell).on('click', function(e) {
|
||||
// get current row data (important!)
|
||||
// -> "rowData" param is not current state, values are "on createCell()" state
|
||||
rowData = tableApi.row( $(cell).parents('tr')).data();
|
||||
showStructureDialog(moduleElement, tableApi, systemData.systemId, rowData);
|
||||
});
|
||||
}
|
||||
}
|
||||
},{
|
||||
targets: 9,
|
||||
title: '',
|
||||
orderable: false,
|
||||
width: 10,
|
||||
class: ['text-center', config.dataTableActionCellClass].join(' '),
|
||||
data: null,
|
||||
render: {
|
||||
display: data => {
|
||||
let icon = '<i class="fas fa-times txt-color txt-color-redDarker"></i>';
|
||||
if(data.corporation.id !== corporationId){
|
||||
icon = '<i class="fas fa-ban txt-color txt-color-grayLight" title="restricted" data-placement="left"></i>';
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
},
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
let tableApi = this.api();
|
||||
|
||||
if($(cell).find('.fa-ban').length){
|
||||
$(cell).removeClass(config.dataTableActionCellClass + ' ' + config.moduleHeadlineIconClass);
|
||||
$(cell).find('i').tooltip();
|
||||
}else{
|
||||
let confirmationSettings = {
|
||||
container: 'body',
|
||||
placement: 'left',
|
||||
btnCancelClass: 'btn btn-sm btn-default',
|
||||
btnCancelLabel: 'cancel',
|
||||
btnCancelIcon: 'fas fa-fw fa-ban',
|
||||
title: 'delete structure',
|
||||
btnOkClass: 'btn btn-sm btn-danger',
|
||||
btnOkLabel: 'delete',
|
||||
btnOkIcon: 'fas fa-fw fa-times',
|
||||
onConfirm : function(e, target){
|
||||
// get current row data (important!)
|
||||
// -> "rowData" param is not current state, values are "on createCell()" state
|
||||
rowData = tableApi.row( $(cell).parents('tr')).data();
|
||||
|
||||
// let deleteRowElement = $(cell).parents('tr');
|
||||
// tableApi.rows(deleteRowElement).remove().draw();
|
||||
deleteStructure({
|
||||
id: rowData.id
|
||||
},{
|
||||
moduleElement: moduleElement,
|
||||
tableApi: tableApi
|
||||
}, callbackDeleteStructures);
|
||||
}
|
||||
};
|
||||
|
||||
// init confirmation dialog
|
||||
$(cell).confirmation(confirmationSettings);
|
||||
}
|
||||
}
|
||||
},{
|
||||
targets: 10,
|
||||
name: 'corporation',
|
||||
data: 'corporation',
|
||||
visible: false,
|
||||
render: {
|
||||
sort: function(data){
|
||||
return data.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
drawCallback: function (settings){
|
||||
let tableApi = this.api();
|
||||
let columnCount = tableApi.columns(':visible').count();
|
||||
let rows = tableApi.rows( {page:'current'} ).nodes();
|
||||
let last= null;
|
||||
|
||||
tableApi.column('corporation:name', {page:'current'} ).data().each( function ( group, i ) {
|
||||
if ( !last || last.id !== group.id ) {
|
||||
$(rows).eq(i).before(
|
||||
'<tr class="group">' +
|
||||
'<td></td>' +
|
||||
'<td class="' + config.tableCellImageClass + '">' +
|
||||
'<img src="' + Init.url.ccpImageServer + '/Corporation/' + group.id + '_32.png" />' +
|
||||
'</td>' +
|
||||
'<td colspan="' + (columnCount - 2 ) + '">' + group.name + '</td>' +
|
||||
'</tr>'
|
||||
);
|
||||
last = group;
|
||||
}
|
||||
});
|
||||
|
||||
rows.to$().find('.' + config.tableCellCounterClass + ':not([data-counter])').initTimestampCounter();
|
||||
|
||||
let animationRows = rows.to$().filter(function() {
|
||||
return (
|
||||
$(this).data('animationStatus') ||
|
||||
$(this).data('animationTimer')
|
||||
);
|
||||
});
|
||||
|
||||
for(let i = 0; i < animationRows.length; i++){
|
||||
let animationRow = $(animationRows[i]);
|
||||
animationRow.pulseTableRow(animationRow.data('animationStatus'));
|
||||
animationRow.removeData('animationStatus');
|
||||
}
|
||||
},
|
||||
initComplete: function(settings){
|
||||
let tableApi = this.api();
|
||||
|
||||
// initial structure data request
|
||||
getStructureData({
|
||||
mapId: mapId,
|
||||
systemId: systemData.id
|
||||
},{
|
||||
moduleElement: moduleElement,
|
||||
tableApi: tableApi
|
||||
}, callbackAddStructureRows);
|
||||
}
|
||||
});
|
||||
|
||||
// init tooltips for this module
|
||||
let tooltipElements = moduleElement.find('[data-toggle="tooltip"]');
|
||||
tooltipElements.tooltip({
|
||||
container: 'body'
|
||||
});
|
||||
|
||||
return moduleElement;
|
||||
};
|
||||
|
||||
/**
|
||||
* init intel module
|
||||
* @param moduleElement
|
||||
* @param mapId
|
||||
* @param systemData
|
||||
*/
|
||||
let initModule = (moduleElement, mapId, systemData) => {
|
||||
|
||||
let structureTableElement = moduleElement.find('.' + config.systemStructuresTableClass);
|
||||
let tableApi = structureTableElement.DataTable();
|
||||
|
||||
// init structure dialog --------------------------------------------------------------------------------------
|
||||
moduleElement.find('.' + config.moduleHeadlineIconAddClass).on('click', function(e){
|
||||
showStructureDialog(moduleElement, tableApi, systemData.systemId);
|
||||
});
|
||||
|
||||
// init refresh button ----------------------------------------------------------------------------------------
|
||||
moduleElement.find('.' + config.moduleHeadlineIconRefreshClass).on('click', function(e){
|
||||
getStructureData({
|
||||
mapId: mapId,
|
||||
systemId: systemData.id
|
||||
},{
|
||||
moduleElement: moduleElement,
|
||||
tableApi: tableApi,
|
||||
removeMissing: true
|
||||
}, callbackAddStructureRows);
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
config: config,
|
||||
getModule: getModule,
|
||||
initModule: initModule
|
||||
};
|
||||
|
||||
});
|
||||
@@ -46,6 +46,11 @@ define([
|
||||
return label;
|
||||
};
|
||||
|
||||
/**
|
||||
* show killMails
|
||||
* @param moduleElement
|
||||
* @param killboardData
|
||||
*/
|
||||
let showKillmails = function(moduleElement, killboardData){
|
||||
|
||||
// show number of killMails
|
||||
|
||||
@@ -8,7 +8,7 @@ define([
|
||||
'app/util',
|
||||
'bootbox',
|
||||
'app/map/util'
|
||||
], function($, Init, Util, bootbox, MapUtil) {
|
||||
], ($, Init, Util, bootbox, MapUtil) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
@@ -103,7 +103,7 @@ define([
|
||||
* @param context
|
||||
* @param routesData
|
||||
*/
|
||||
let callbackAddRouteRow = (context, routesData) => {
|
||||
let callbackAddRouteRows = (context, routesData) => {
|
||||
|
||||
if(routesData.length > 0){
|
||||
for(let i = 0; i < routesData.length; i++){
|
||||
@@ -170,7 +170,6 @@ define([
|
||||
return rowElement;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* requests route data from eveCentral API and execute callback
|
||||
* @param requestData
|
||||
@@ -210,7 +209,7 @@ define([
|
||||
routeData.push( getRouteRequestDataFromRowData( this.data() ));
|
||||
});
|
||||
|
||||
getRouteData({routeData: routeData}, context, callbackAddRouteRow);
|
||||
getRouteData({routeData: routeData}, context, callbackAddRouteRows);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -261,7 +260,7 @@ define([
|
||||
mapSelectOptions: mapSelectOptions
|
||||
};
|
||||
|
||||
requirejs(['text!templates/dialog/route.html', 'mustache'], function(template, Mustache) {
|
||||
requirejs(['text!templates/dialog/route.html', 'mustache'], (template, Mustache) => {
|
||||
|
||||
let content = Mustache.render(template, data);
|
||||
|
||||
@@ -326,7 +325,7 @@ define([
|
||||
}]
|
||||
};
|
||||
|
||||
getRouteData(requestData, context, callbackAddRouteRow);
|
||||
getRouteData(requestData, context, callbackAddRouteRows);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -418,7 +417,7 @@ define([
|
||||
routeData: requestRouteData
|
||||
};
|
||||
|
||||
getRouteData(requestData, contextData, callbackAddRouteRow);
|
||||
getRouteData(requestData, contextData, callbackAddRouteRows);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -432,7 +431,7 @@ define([
|
||||
let showSettingsDialog = (dialogData, moduleElement, systemFromData, routesTable) => {
|
||||
|
||||
let promiseStore = MapUtil.getLocaleData('map', dialogData.mapId);
|
||||
promiseStore.then(function(dataStore) {
|
||||
promiseStore.then(dataStore => {
|
||||
// selected systems (if already stored)
|
||||
let systemSelectOptions = [];
|
||||
if(
|
||||
@@ -902,7 +901,6 @@ define([
|
||||
)
|
||||
);
|
||||
|
||||
// crate new route table
|
||||
let table = $('<table>', {
|
||||
class: ['compact', 'stripe', 'order-column', 'row-border', config.systemInfoRoutesTableClass].join(' ')
|
||||
});
|
||||
@@ -1039,7 +1037,7 @@ define([
|
||||
routeData: [routeData]
|
||||
};
|
||||
|
||||
getRouteData(requestData, context, callbackAddRouteRow);
|
||||
getRouteData(requestData, context, callbackAddRouteRows);
|
||||
});
|
||||
}
|
||||
},{
|
||||
@@ -1074,7 +1072,7 @@ define([
|
||||
routeData: [routeData]
|
||||
};
|
||||
|
||||
getRouteData(requestData, context, callbackAddRouteRow);
|
||||
getRouteData(requestData, context, callbackAddRouteRows);
|
||||
});
|
||||
}
|
||||
},{
|
||||
@@ -1122,10 +1120,10 @@ define([
|
||||
});
|
||||
|
||||
for(let i = 0; i < animationRows.length; i++){
|
||||
$(animationRows[i]).pulseTableRow($(animationRows[i]).data('animationStatus'));
|
||||
$(animationRows[i]).removeData('animationStatus');
|
||||
let animationRow = $(animationRows[i]);
|
||||
animationRow.pulseTableRow(animationRow.data('animationStatus'));
|
||||
animationRow.removeData('animationStatus');
|
||||
}
|
||||
|
||||
},
|
||||
initComplete: function(settings, json){
|
||||
// click on "fake connection" -------------------------------------------------------------------------
|
||||
@@ -1231,7 +1229,6 @@ define([
|
||||
};
|
||||
|
||||
let routesTableElement = moduleElement.find('.' + config.systemInfoRoutesTableClass);
|
||||
|
||||
let routesTable = routesTableElement.DataTable();
|
||||
|
||||
// init refresh routes --------------------------------------------------------------------
|
||||
|
||||
@@ -15,7 +15,8 @@ define([
|
||||
'easyPieChart',
|
||||
'hoverIntent',
|
||||
'bootstrapConfirmation',
|
||||
'bootstrapToggle'
|
||||
'bootstrapToggle',
|
||||
'select2'
|
||||
], ($, Init, SystemEffect, SignatureType, bootbox, localforage) => {
|
||||
|
||||
'use strict';
|
||||
@@ -55,6 +56,8 @@ define([
|
||||
mapWrapperClass: 'pf-map-wrapper', // wrapper div (scrollable)
|
||||
mapClass: 'pf-map' , // class for all maps
|
||||
|
||||
// select2
|
||||
select2Class: 'pf-select2', // class for all "Select2" <select> elements
|
||||
|
||||
// animation
|
||||
animationPulseSuccessClass: 'pf-animation-pulse-success', // animation class
|
||||
@@ -962,14 +965,78 @@ define([
|
||||
};
|
||||
|
||||
/**
|
||||
* set default configuration for "Bootbox" dialogs
|
||||
* set default configuration for "Bootbox"
|
||||
*/
|
||||
let initDefaultBootboxConfig = function(){
|
||||
let initDefaultBootboxConfig = () => {
|
||||
bootbox.setDefaults({
|
||||
onEscape: true // enables close dialogs on ESC key
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* set default configuration for "Select2"
|
||||
*/
|
||||
let initDefaultSelect2Config = () => {
|
||||
$.fn.select2.defaults.set('theme', 'pathfinder');
|
||||
|
||||
let initScrollbar = (resultsWrapper) => {
|
||||
// default 'mousewheel' event set by select2 needs to be disabled
|
||||
// in order to make mCustomScrollbar mouseWheel enable works correctly
|
||||
$(resultsWrapper).find('ul.select2-results__options').off('mousewheel');
|
||||
|
||||
resultsWrapper.mCustomScrollbar({
|
||||
mouseWheel: {
|
||||
enable: true,
|
||||
scrollAmount: 'auto',
|
||||
axis: 'y',
|
||||
preventDefault: true
|
||||
},
|
||||
keyboard: {
|
||||
enable: false,
|
||||
scrollType: 'stepless',
|
||||
scrollAmount: 'auto'
|
||||
},
|
||||
scrollbarPosition: 'inside',
|
||||
autoDraggerLength: true,
|
||||
autoHideScrollbar: false,
|
||||
advanced: {
|
||||
updateOnContentResize: true
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let getResultsWrapper = (selectElement) => {
|
||||
let wrapper = null;
|
||||
let selectElementId = selectElement.getAttribute('data-select2-id');
|
||||
if(selectElementId){
|
||||
let resultsOptions = $('#select2-' + selectElementId + '-results');
|
||||
if(resultsOptions.length) {
|
||||
let resultsWrapper = resultsOptions.parents('.select2-results');
|
||||
if(resultsWrapper.length){
|
||||
wrapper = resultsWrapper;
|
||||
}
|
||||
}
|
||||
}
|
||||
return wrapper;
|
||||
};
|
||||
|
||||
// global open event
|
||||
$(document).on('select2:open', '.' + config.select2Class, function(e){
|
||||
let resultsWrapper = getResultsWrapper(this);
|
||||
if(resultsWrapper){
|
||||
initScrollbar(resultsWrapper);
|
||||
}
|
||||
});
|
||||
|
||||
// global select2:closing event
|
||||
$(document).on('select2:closing', '.' + config.select2Class, function(e){
|
||||
let resultsWrapper = getResultsWrapper(this);
|
||||
if(resultsWrapper){
|
||||
resultsWrapper.mCustomScrollbar('destroy');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* get the current main trigger delay for the main trigger functions
|
||||
* optional in/decrease the delay
|
||||
@@ -1104,6 +1171,33 @@ define([
|
||||
return duration;
|
||||
};
|
||||
|
||||
/**
|
||||
* update a character counter field with current value length - maxCharLength
|
||||
* @param field
|
||||
* @param charCounterElement
|
||||
* @param maxCharLength
|
||||
*/
|
||||
let updateCounter = function(field, charCounterElement, maxCharLength){
|
||||
let value = field.val();
|
||||
let inputLength = value.length;
|
||||
|
||||
// line breaks are 2 characters!
|
||||
let newLines = value.match(/(\r\n|\n|\r)/g);
|
||||
let addition = 0;
|
||||
if (newLines != null) {
|
||||
addition = newLines.length;
|
||||
}
|
||||
inputLength += addition;
|
||||
|
||||
charCounterElement.text(maxCharLength - inputLength);
|
||||
|
||||
if(maxCharLength <= inputLength){
|
||||
charCounterElement.toggleClass('txt-color-red', true);
|
||||
}else{
|
||||
charCounterElement.toggleClass('txt-color-red', false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* trigger main logging event with log information
|
||||
* @param logKey
|
||||
@@ -2413,12 +2507,14 @@ define([
|
||||
showVersionInfo: showVersionInfo,
|
||||
initPrototypes: initPrototypes,
|
||||
initDefaultBootboxConfig: initDefaultBootboxConfig,
|
||||
initDefaultSelect2Config: initDefaultSelect2Config,
|
||||
getCurrentTriggerDelay: getCurrentTriggerDelay,
|
||||
getServerTime: getServerTime,
|
||||
convertTimestampToServerTime: convertTimestampToServerTime,
|
||||
getTimeDiffParts: getTimeDiffParts,
|
||||
timeStart: timeStart,
|
||||
timeStop: timeStop,
|
||||
updateCounter: updateCounter,
|
||||
log: log,
|
||||
showNotify: showNotify,
|
||||
stopTabBlink: stopTabBlink,
|
||||
|
||||
@@ -0,0 +1,414 @@
|
||||
/*! RowGroup 1.0.3-dev
|
||||
* ©2017-2018 SpryMedia Ltd - datatables.net/license
|
||||
*/
|
||||
|
||||
/**
|
||||
* @summary RowGroup
|
||||
* @description RowGrouping for DataTables
|
||||
* @version 1.0.3-dev
|
||||
* @file dataTables.rowGroup.js
|
||||
* @author SpryMedia Ltd (www.sprymedia.co.uk)
|
||||
* @contact datatables.net
|
||||
* @copyright Copyright 2017-2018 SpryMedia Ltd.
|
||||
*
|
||||
* This source file is free software, available under the following license:
|
||||
* MIT license - http://datatables.net/license/mit
|
||||
*
|
||||
* This source file is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
|
||||
*
|
||||
* For details please refer to: http://www.datatables.net
|
||||
*/
|
||||
|
||||
(function( factory ){
|
||||
if ( typeof define === 'function' && define.amd ) {
|
||||
// AMD
|
||||
define( ['jquery', 'datatables.net'], function ( $ ) {
|
||||
return factory( $, window, document );
|
||||
} );
|
||||
}
|
||||
else if ( typeof exports === 'object' ) {
|
||||
// CommonJS
|
||||
module.exports = function (root, $) {
|
||||
if ( ! root ) {
|
||||
root = window;
|
||||
}
|
||||
|
||||
if ( ! $ || ! $.fn.dataTable ) {
|
||||
$ = require('datatables.net')(root, $).$;
|
||||
}
|
||||
|
||||
return factory( $, root, root.document );
|
||||
};
|
||||
}
|
||||
else {
|
||||
// Browser
|
||||
factory( jQuery, window, document );
|
||||
}
|
||||
}(function( $, window, document, undefined ) {
|
||||
'use strict';
|
||||
var DataTable = $.fn.dataTable;
|
||||
|
||||
|
||||
var RowGroup = function ( dt, opts ) {
|
||||
// Sanity check that we are using DataTables 1.10 or newer
|
||||
if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.8' ) ) {
|
||||
throw 'RowGroup requires DataTables 1.10.8 or newer';
|
||||
}
|
||||
|
||||
// User and defaults configuration object
|
||||
this.c = $.extend( true, {},
|
||||
DataTable.defaults.rowGroup,
|
||||
RowGroup.defaults,
|
||||
opts
|
||||
);
|
||||
|
||||
// Internal settings
|
||||
this.s = {
|
||||
dt: new DataTable.Api( dt ),
|
||||
|
||||
dataFn: DataTable.ext.oApi._fnGetObjectDataFn( this.c.dataSrc )
|
||||
};
|
||||
|
||||
// DOM items
|
||||
this.dom = {
|
||||
|
||||
};
|
||||
|
||||
// Check if row grouping has already been initialised on this table
|
||||
var settings = this.s.dt.settings()[0];
|
||||
var existing = settings.rowGroup;
|
||||
if ( existing ) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
settings.rowGroup = this;
|
||||
this._constructor();
|
||||
};
|
||||
|
||||
|
||||
$.extend( RowGroup.prototype, {
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* API methods for DataTables API interface
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get/set the grouping data source - need to call draw after this is
|
||||
* executed as a setter
|
||||
* @returns string~RowGroup
|
||||
*/
|
||||
dataSrc: function ( val )
|
||||
{
|
||||
if ( val === undefined ) {
|
||||
return this.c.dataSrc;
|
||||
}
|
||||
|
||||
var dt = this.s.dt;
|
||||
|
||||
this.c.dataSrc = val;
|
||||
this.s.dataFn = DataTable.ext.oApi._fnGetObjectDataFn( this.c.dataSrc );
|
||||
|
||||
$(dt.table().node()).triggerHandler( 'rowgroup-datasrc.dt', [ dt, val ] );
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Disable - need to call draw after this is executed
|
||||
* @returns RowGroup
|
||||
*/
|
||||
disable: function ()
|
||||
{
|
||||
this.c.enable = false;
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Enable - need to call draw after this is executed
|
||||
* @returns RowGroup
|
||||
*/
|
||||
enable: function ( flag )
|
||||
{
|
||||
if ( flag === false ) {
|
||||
return this.disable();
|
||||
}
|
||||
|
||||
this.c.enable = true;
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Constructor
|
||||
*/
|
||||
_constructor: function ()
|
||||
{
|
||||
var that = this;
|
||||
var dt = this.s.dt;
|
||||
var rows = dt.rows();
|
||||
var groups = [];
|
||||
|
||||
rows.every( function () {
|
||||
var d = this.data();
|
||||
var group = that.s.dataFn( d );
|
||||
|
||||
if ( groups.indexOf(group) == -1 ) {
|
||||
groups.push( group );
|
||||
}
|
||||
} );
|
||||
|
||||
dt.on( 'draw.dtrg', function () {
|
||||
if ( that.c.enable ) {
|
||||
that._draw();
|
||||
}
|
||||
} );
|
||||
|
||||
dt.on( 'column-visibility.dt.dtrg responsive-resize.dt.dtrg', function () {
|
||||
that._adjustColspan();
|
||||
} );
|
||||
|
||||
dt.on( 'destroy', function () {
|
||||
dt.off( '.dtrg' );
|
||||
} );
|
||||
},
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Private methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adjust column span when column visibility changes
|
||||
* @private
|
||||
*/
|
||||
_adjustColspan: function ()
|
||||
{
|
||||
$( 'tr.'+this.c.className, this.s.dt.table().body() )
|
||||
.attr( 'colspan', this._colspan() );
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the number of columns that a grouping row should span
|
||||
* @private
|
||||
*/
|
||||
_colspan: function ()
|
||||
{
|
||||
return this.s.dt.columns().visible().reduce( function (a, b) {
|
||||
return a + b;
|
||||
}, 0 );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update function that is called whenever we need to draw the grouping rows
|
||||
* @private
|
||||
*/
|
||||
_draw: function ()
|
||||
{
|
||||
var that = this;
|
||||
var dt = this.s.dt;
|
||||
var rows = dt.rows( { page: 'current' } );
|
||||
var groupedRows = [];
|
||||
var last, display;
|
||||
|
||||
rows.every( function () {
|
||||
var d = this.data();
|
||||
var group = that.s.dataFn( d );
|
||||
|
||||
if ( group === null || group === undefined ) {
|
||||
group = that.c.emptyDataGroup;
|
||||
}
|
||||
|
||||
if ( last === undefined || group !== last ) {
|
||||
groupedRows.push( [] );
|
||||
last = group;
|
||||
}
|
||||
|
||||
groupedRows[ groupedRows.length - 1 ].push( this.index() );
|
||||
} );
|
||||
|
||||
for ( var i=0, ien=groupedRows.length ; i<ien ; i++ ) {
|
||||
var group = groupedRows[i];
|
||||
var firstRow = dt.row(group[0]);
|
||||
var groupName = this.s.dataFn( firstRow.data() );
|
||||
|
||||
if ( this.c.startRender ) {
|
||||
display = this.c.startRender.call( this, dt.rows(group), groupName );
|
||||
|
||||
this
|
||||
._rowWrap( display, this.c.startClassName )
|
||||
.insertBefore( firstRow.node() );
|
||||
}
|
||||
|
||||
if ( this.c.endRender ) {
|
||||
display = this.c.endRender.call( this, dt.rows(group), groupName );
|
||||
|
||||
this
|
||||
._rowWrap( display, this.c.endClassName )
|
||||
.insertAfter( dt.row( group[ group.length-1 ] ).node() );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Take a rendered value from an end user and make it suitable for display
|
||||
* as a row, by wrapping it in a row, or detecting that it is a row.
|
||||
* @param [node|jQuery|string] display Display value
|
||||
* @param [string] className Class to add to the row
|
||||
* @private
|
||||
*/
|
||||
_rowWrap: function ( display, className )
|
||||
{
|
||||
var row;
|
||||
|
||||
if ( display === null || display === undefined ) {
|
||||
display = this.c.emptyDataGroup;
|
||||
}
|
||||
|
||||
if ( typeof display === 'object' && display.nodeName && display.nodeName.toLowerCase() === 'tr') {
|
||||
row = $(display);
|
||||
}
|
||||
else if (display instanceof $ && display.length && display[0].nodeName.toLowerCase() === 'tr') {
|
||||
row = display;
|
||||
}
|
||||
else {
|
||||
row = $('<tr/>')
|
||||
.append(
|
||||
$('<td/>')
|
||||
.attr( 'colspan', this._colspan() )
|
||||
.append( display )
|
||||
);
|
||||
}
|
||||
|
||||
return row
|
||||
.addClass( this.c.className )
|
||||
.addClass( className );
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
/**
|
||||
* RowGroup default settings for initialisation
|
||||
*
|
||||
* @namespace
|
||||
* @name RowGroup.defaults
|
||||
* @static
|
||||
*/
|
||||
RowGroup.defaults = {
|
||||
/**
|
||||
* Class to apply to grouping rows - applied to both the start and
|
||||
* end grouping rows.
|
||||
* @type string
|
||||
*/
|
||||
className: 'group',
|
||||
|
||||
/**
|
||||
* Data property from which to read the grouping information
|
||||
* @type string|integer
|
||||
*/
|
||||
dataSrc: 0,
|
||||
|
||||
/**
|
||||
* Text to show if no data is found for a group
|
||||
* @type string
|
||||
*/
|
||||
emptyDataGroup: 'No group',
|
||||
|
||||
/**
|
||||
* Initial enablement state
|
||||
* @boolean
|
||||
*/
|
||||
enable: true,
|
||||
|
||||
/**
|
||||
* Class name to give to the end grouping row
|
||||
* @type string
|
||||
*/
|
||||
endClassName: 'group-end',
|
||||
|
||||
/**
|
||||
* End grouping label function
|
||||
* @function
|
||||
*/
|
||||
endRender: null,
|
||||
|
||||
/**
|
||||
* Class name to give to the start grouping row
|
||||
* @type string
|
||||
*/
|
||||
startClassName: 'group-start',
|
||||
|
||||
/**
|
||||
* Start grouping label function
|
||||
* @function
|
||||
*/
|
||||
startRender: function ( rows, group ) {
|
||||
return group;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
RowGroup.version = "1.0.3-dev";
|
||||
|
||||
|
||||
$.fn.dataTable.RowGroup = RowGroup;
|
||||
$.fn.DataTable.RowGroup = RowGroup;
|
||||
|
||||
|
||||
DataTable.Api.register( 'rowGroup()', function () {
|
||||
return this;
|
||||
} );
|
||||
|
||||
DataTable.Api.register( 'rowGroup().disable()', function () {
|
||||
return this.iterator( 'table', function (ctx) {
|
||||
if ( ctx.rowGroup ) {
|
||||
ctx.rowGroup.enable( false );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
||||
DataTable.Api.register( 'rowGroup().enable()', function ( opts ) {
|
||||
return this.iterator( 'table', function (ctx) {
|
||||
if ( ctx.rowGroup ) {
|
||||
ctx.rowGroup.enable( opts === undefined ? true : opts );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
||||
DataTable.Api.register( 'rowGroup().dataSrc()', function ( val ) {
|
||||
if ( val === undefined ) {
|
||||
return this.context[0].rowGroup.dataSrc();
|
||||
}
|
||||
|
||||
return this.iterator( 'table', function (ctx) {
|
||||
if ( ctx.rowGroup ) {
|
||||
ctx.rowGroup.dataSrc( val );
|
||||
}
|
||||
} );
|
||||
} );
|
||||
|
||||
|
||||
// Attach a listener to the document which listens for DataTables initialisation
|
||||
// events so we can automatically initialise
|
||||
/*
|
||||
$(document).on( 'preInit.dt.dtrg', function (e, settings, json) {
|
||||
if ( e.namespace !== 'dt' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var init = settings.oInit.rowGroup;
|
||||
var defaults = DataTable.defaults.rowGroup;
|
||||
|
||||
if ( init || defaults ) {
|
||||
var opts = $.extend( {}, defaults, init );
|
||||
|
||||
if ( init !== false ) {
|
||||
new RowGroup( settings, opts );
|
||||
}
|
||||
}
|
||||
} );
|
||||
*/
|
||||
|
||||
return RowGroup;
|
||||
|
||||
}));
|
||||
@@ -0,0 +1,55 @@
|
||||
describe( 'rowGroup().dataSrc()', function() {
|
||||
var table;
|
||||
|
||||
dt.libs( {
|
||||
js: [ 'jquery', 'datatables', 'rowgroup' ],
|
||||
css: [ 'datatables', 'rowgroup' ]
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'A DataTable can be created with RowGrouping', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0) td:eq(0)').html() ).toBe( 'Edinburgh' );
|
||||
expect( $('#example tbody tr:eq(1) td:eq(0)').html() ).toBe( 'Tiger Nixon' );
|
||||
} );
|
||||
|
||||
it( 'Get the current data source', function () {
|
||||
expect( table.rowGroup().dataSrc() ).toBe( 2 );
|
||||
} );
|
||||
|
||||
it( 'Can change the data source', function () {
|
||||
table.rowGroup().dataSrc( 3 ).draw();
|
||||
|
||||
expect( $('#example tbody tr:eq(0) td:eq(0)').html() ).toBe( '61' );
|
||||
expect( $('#example tbody tr:eq(1) td:eq(0)').html() ).toBe( 'Tiger Nixon' );
|
||||
expect( $('#example tbody tr:eq(2) td:eq(0)').html() ).toBe( '22' );
|
||||
expect( $('#example tbody tr:eq(3) td:eq(0)').html() ).toBe( 'Cedric Kelly' );
|
||||
} );
|
||||
|
||||
it( 'Return as a setter is an API instance', function () {
|
||||
expect( table.rowGroup().dataSrc( 3 ) instanceof $.fn.dataTable.Api ).toBe( true );
|
||||
} );
|
||||
|
||||
it( 'Read the set value back', function () {
|
||||
expect( table.rowGroup().dataSrc() ).toBe( 3 );
|
||||
} );
|
||||
|
||||
it( 'Setting does not show any difference until redraw', function () {
|
||||
table.rowGroup().dataSrc( 0 );
|
||||
|
||||
expect( $('#example tbody tr:eq(0) td:eq(0)').html() ).toBe( '61' );
|
||||
} );
|
||||
|
||||
it( 'Setting does not show any difference until redraw', function () {
|
||||
table.draw();
|
||||
|
||||
expect( $('#example tbody tr:eq(0) td:eq(0)').html() ).toBe( 'Tiger Nixon' );
|
||||
} );
|
||||
} );
|
||||
@@ -0,0 +1,35 @@
|
||||
describe( 'rowGroup().disable()', function() {
|
||||
var table;
|
||||
|
||||
dt.libs( {
|
||||
js: [ 'jquery', 'datatables', 'rowgroup' ],
|
||||
css: [ 'datatables', 'rowgroup' ]
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'A DataTable can be created with RowGrouping', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0) td:eq(0)').html() ).toBe( 'Edinburgh' );
|
||||
expect( $('#example tbody tr:eq(1) td:eq(0)').html() ).toBe( 'Tiger Nixon' );
|
||||
} );
|
||||
|
||||
it( 'Does not redraw automatically', function () {
|
||||
table.rowGroup().disable();
|
||||
|
||||
expect( $('#example tbody tr:eq(0) td:eq(0)').html() ).toBe( 'Edinburgh' );
|
||||
expect( $('#example tbody tr:eq(1) td:eq(0)').html() ).toBe( 'Tiger Nixon' );
|
||||
} );
|
||||
|
||||
it( 'Disabled after a redraw', function () {
|
||||
table.draw();
|
||||
|
||||
expect( $('#example tbody tr:eq(0) td:eq(0)').html() ).toBe( 'Tiger Nixon' );
|
||||
} );
|
||||
} );
|
||||
@@ -0,0 +1,48 @@
|
||||
describe( 'rowGroup().enable()', function() {
|
||||
var table;
|
||||
|
||||
dt.libs( {
|
||||
js: [ 'jquery', 'datatables', 'rowgroup' ],
|
||||
css: [ 'datatables', 'rowgroup' ]
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'A DataTable can be created with RowGrouping', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0) td:eq(0)').html() ).toBe( 'Edinburgh' );
|
||||
expect( $('#example tbody tr:eq(1) td:eq(0)').html() ).toBe( 'Tiger Nixon' );
|
||||
} );
|
||||
|
||||
it( 'Disable', function () {
|
||||
table.rowGroup().disable().draw();
|
||||
|
||||
expect( $('#example tbody tr:eq(0) td:eq(0)').html() ).toBe( 'Tiger Nixon' );
|
||||
} );
|
||||
|
||||
it( 'Can be enabled', function () {
|
||||
table.rowGroup().enable().draw();
|
||||
|
||||
expect( $('#example tbody tr:eq(0) td:eq(0)').html() ).toBe( 'Edinburgh' );
|
||||
expect( $('#example tbody tr:eq(1) td:eq(0)').html() ).toBe( 'Tiger Nixon' );
|
||||
} );
|
||||
|
||||
it( 'Can be used as a toggle to disable', function () {
|
||||
table.rowGroup().enable( false ).draw();
|
||||
|
||||
expect( $('#example tbody tr:eq(0) td:eq(0)').html() ).toBe( 'Tiger Nixon' );
|
||||
} );
|
||||
|
||||
it( 'Can be used as a toggle to enable', function () {
|
||||
table.rowGroup().enable( true ).draw();
|
||||
|
||||
expect( $('#example tbody tr:eq(0) td:eq(0)').html() ).toBe( 'Edinburgh' );
|
||||
expect( $('#example tbody tr:eq(1) td:eq(0)').html() ).toBe( 'Tiger Nixon' );
|
||||
} );
|
||||
} );
|
||||
@@ -0,0 +1,52 @@
|
||||
describe( 'rowgroup-datasrc', function() {
|
||||
var table;
|
||||
var args;
|
||||
|
||||
dt.libs( {
|
||||
js: [ 'jquery', 'datatables', 'rowgroup' ],
|
||||
css: [ 'datatables', 'rowgroup' ]
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'A DataTable can be created with RowGrouping', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0) td:eq(0)').html() ).toBe( 'Edinburgh' );
|
||||
expect( $('#example tbody tr:eq(1) td:eq(0)').html() ).toBe( 'Tiger Nixon' );
|
||||
} );
|
||||
|
||||
it( 'Change in the data source will trigger rowgroup-datasrc', function ( done ) {
|
||||
table.on( 'rowgroup-datasrc', function () {
|
||||
args = arguments;
|
||||
done();
|
||||
} );
|
||||
|
||||
table.rowGroup().dataSrc( 3 ).draw();
|
||||
} );
|
||||
|
||||
it( 'Three arguments', function () {
|
||||
expect( args.length ).toBe( 3 );
|
||||
} );
|
||||
|
||||
it( 'First is jQuery object', function () {
|
||||
expect( args[0] instanceof $.Event ).toBe( true );
|
||||
} );
|
||||
|
||||
it( 'Second is DataTable API instance', function () {
|
||||
expect( args[1] instanceof $.fn.dataTable.Api ).toBe( true );
|
||||
} );
|
||||
|
||||
it( 'Third is the new data source value', function () {
|
||||
expect( args[2] ).toBe( 3 );
|
||||
} );
|
||||
|
||||
it( 'Event is triggered with .dt namespace', function () {
|
||||
expect( args[0].namespace ).toBe( 'dt' );
|
||||
} );
|
||||
} );
|
||||
@@ -0,0 +1,26 @@
|
||||
describe( 'RowGroup exists and can be initialised', function() {
|
||||
var table;
|
||||
|
||||
dt.libs( {
|
||||
js: [ 'jquery', 'datatables', 'rowgroup' ],
|
||||
css: [ 'datatables', 'rowgroup' ]
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Exists', function () {
|
||||
expect( $.fn.dataTable.RowGroup ).toBeDefined();
|
||||
} );
|
||||
|
||||
it( 'A DataTable can be created with RowGrouping', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0) td:eq(0)').html() ).toBe( 'Edinburgh' );
|
||||
expect( $('#example tbody tr:eq(1) td:eq(0)').html() ).toBe( 'Tiger Nixon' );
|
||||
} );
|
||||
} );
|
||||
@@ -0,0 +1,56 @@
|
||||
describe( 'Class name', function() {
|
||||
var table;
|
||||
|
||||
dt.libs( {
|
||||
js: [ 'jquery', 'datatables', 'rowgroup' ],
|
||||
css: [ 'datatables', 'rowgroup' ]
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Default is `group`', function () {
|
||||
expect( $.fn.dataTable.RowGroup.defaults.className ).toBe( 'group' );
|
||||
} );
|
||||
|
||||
it( 'Is used for header rows', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0)').hasClass('group') ).toBe( true );
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Can be set to a different value', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2,
|
||||
className: 'test'
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0)').hasClass('group') ).toBe( false );
|
||||
expect( $('#example tbody tr:eq(0)').hasClass('test') ).toBe( true );
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Is applied to the footer grouping row', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2,
|
||||
endRender: function () {
|
||||
return 'Test';
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(10)').hasClass('group') ).toBe( true );
|
||||
} );
|
||||
} );
|
||||
@@ -0,0 +1,43 @@
|
||||
describe( 'dataSrc', function() {
|
||||
var table;
|
||||
|
||||
dt.libs( {
|
||||
js: [ 'jquery', 'datatables', 'rowgroup' ],
|
||||
css: [ 'datatables', 'rowgroup' ]
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Default is 0', function () {
|
||||
expect( $.fn.dataTable.RowGroup.defaults.dataSrc ).toBe( 0 );
|
||||
} );
|
||||
|
||||
it( 'Is indeed 0 when run', function () {
|
||||
table = $('#example').DataTable( {
|
||||
rowGroup: true
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0)').text() ).toBe( 'Airi Satou' );
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Can be used with object data', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
columns: [
|
||||
{ data: 'name' },
|
||||
{ data: 'position' },
|
||||
{ data: 'office' },
|
||||
{ data: 'age' },
|
||||
{ data: 'startDate' },
|
||||
{ data: 'salary' }
|
||||
],
|
||||
rowGroup: {
|
||||
dataSrc: 'office'
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0)').text() ).toBe( 'Edinburgh' );
|
||||
} );
|
||||
} );
|
||||
@@ -0,0 +1,40 @@
|
||||
describe( 'Enable', function() {
|
||||
var table;
|
||||
|
||||
dt.libs( {
|
||||
js: [ 'jquery', 'datatables', 'rowgroup' ],
|
||||
css: [ 'datatables', 'rowgroup' ]
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Default is enable', function () {
|
||||
expect( $.fn.dataTable.RowGroup.defaults.enable ).toBe( true );
|
||||
} );
|
||||
|
||||
it( 'Is indeed enabled', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0)').hasClass('group') ).toBe( true );
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Can be disabled', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2,
|
||||
enable: false
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0)').hasClass('group') ).toBe( false );
|
||||
expect( $('#example tbody tr').length ).toBe( 10 );
|
||||
} );
|
||||
} );
|
||||
@@ -0,0 +1,46 @@
|
||||
describe( 'End class name', function() {
|
||||
var table;
|
||||
|
||||
dt.libs( {
|
||||
js: [ 'jquery', 'datatables', 'rowgroup' ],
|
||||
css: [ 'datatables', 'rowgroup' ]
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Default is `group-end`', function () {
|
||||
expect( $.fn.dataTable.RowGroup.defaults.endClassName ).toBe( 'group-end' );
|
||||
} );
|
||||
|
||||
it( 'Is used', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2,
|
||||
endRender: function () {
|
||||
return 'Test';
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(10)').hasClass('group-end') ).toBe( true );
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Can be changed', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2,
|
||||
endRender: function () {
|
||||
return 'Test';
|
||||
},
|
||||
endClassName: 'test'
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(10)').hasClass('group-end') ).toBe( false );
|
||||
expect( $('#example tbody tr:eq(10)').hasClass('test') ).toBe( true );
|
||||
} );
|
||||
} );
|
||||
@@ -0,0 +1,88 @@
|
||||
describe( 'End render', function() {
|
||||
var table;
|
||||
|
||||
dt.libs( {
|
||||
js: [ 'jquery', 'datatables', 'rowgroup' ],
|
||||
css: [ 'datatables', 'rowgroup' ]
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Default is null', function () {
|
||||
expect( $.fn.dataTable.RowGroup.defaults.endRender ).toBe( null );
|
||||
} );
|
||||
|
||||
it( 'Can be used to show the grouping data name', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2,
|
||||
endRender: function ( rows, group ) {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(10)').text() ).toBe( 'Edinburgh' );
|
||||
expect( $('#example tbody tr:eq(13)').text() ).toBe( 'London' );
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Will show a static value', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2,
|
||||
endRender: function ( rows, group ) {
|
||||
return 'Test';
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(10)').text() ).toBe( 'Test' );
|
||||
expect( $('#example tbody tr:eq(13)').text() ).toBe( 'Test' );
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
var a1 = [];
|
||||
var a2 = [];
|
||||
|
||||
it( 'Renderer is called with two arguments', function () {
|
||||
var args;
|
||||
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2,
|
||||
endRender: function ( rows, group ) {
|
||||
a1.push( rows );
|
||||
a2.push( group );
|
||||
args = arguments.length;
|
||||
return group;
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
expect( args ).toBe( 2 );
|
||||
} );
|
||||
|
||||
it( 'Is called once for each group on the page', function () {
|
||||
expect( a1.length ).toBe( 2 );
|
||||
} );
|
||||
|
||||
it( 'First argument is an API instance', function () {
|
||||
expect( a1[0] instanceof $.fn.dataTable.Api ).toBe( true );
|
||||
} );
|
||||
|
||||
it( 'First argument has the rows for the group in it', function () {
|
||||
expect( a1[0].count() ).toBe( 9 );
|
||||
expect( a1[1].count() ).toBe( 1 );
|
||||
} );
|
||||
|
||||
it( 'Second argument has the group name', function () {
|
||||
expect( a2[0] ).toBe( 'Edinburgh' );
|
||||
expect( a2[1] ).toBe( 'London' );
|
||||
} );
|
||||
} );
|
||||
@@ -0,0 +1,40 @@
|
||||
describe( 'Start class name', function() {
|
||||
var table;
|
||||
|
||||
dt.libs( {
|
||||
js: [ 'jquery', 'datatables', 'rowgroup' ],
|
||||
css: [ 'datatables', 'rowgroup' ]
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Default is `group-start`', function () {
|
||||
expect( $.fn.dataTable.RowGroup.defaults.startClassName ).toBe( 'group-start' );
|
||||
} );
|
||||
|
||||
it( 'Is used', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0)').hasClass('group-start') ).toBe( true );
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Can be changed', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2,
|
||||
startClassName: 'test'
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0)').hasClass('group-start') ).toBe( false );
|
||||
expect( $('#example tbody tr:eq(0)').hasClass('test') ).toBe( true );
|
||||
} );
|
||||
} );
|
||||
@@ -0,0 +1,121 @@
|
||||
describe( 'Start render', function() {
|
||||
var table;
|
||||
|
||||
dt.libs( {
|
||||
js: [ 'jquery', 'datatables', 'rowgroup' ],
|
||||
css: [ 'datatables', 'rowgroup' ]
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Default is defined as a function', function () {
|
||||
expect( typeof $.fn.dataTable.RowGroup.defaults.startRender ).toBe( 'function' );
|
||||
} );
|
||||
|
||||
it( 'Default is to show the grouping data name', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0)').text() ).toBe( 'Edinburgh' );
|
||||
expect( $('#example tbody tr:eq(10)').text() ).toBe( 'London' );
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Will show a static value', function () {
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2,
|
||||
startRender: function ( rows, group ) {
|
||||
return 'Test';
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0)').text() ).toBe( 'Test' );
|
||||
expect( $('#example tbody tr:eq(10)').text() ).toBe( 'Test' );
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
var a1 = [];
|
||||
var a2 = [];
|
||||
|
||||
it( 'Renderer is called with two arguments', function () {
|
||||
var args;
|
||||
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2,
|
||||
startRender: function ( rows, group ) {
|
||||
a1.push( rows );
|
||||
a2.push( group );
|
||||
args = arguments.length;
|
||||
return group;
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
expect( args ).toBe( 2 );
|
||||
} );
|
||||
|
||||
it( 'Is called once for each group on the page', function () {
|
||||
expect( a1.length ).toBe( 2 );
|
||||
} );
|
||||
|
||||
it( 'First argument is an API instance', function () {
|
||||
expect( a1[0] instanceof $.fn.dataTable.Api ).toBe( true );
|
||||
} );
|
||||
|
||||
it( 'First argument has the rows for the group in it', function () {
|
||||
expect( a1[0].count() ).toBe( 9 );
|
||||
expect( a1[1].count() ).toBe( 1 );
|
||||
} );
|
||||
|
||||
it( 'Second argument has the group name', function () {
|
||||
expect( a2[0] ).toBe( 'Edinburgh' );
|
||||
expect( a2[1] ).toBe( 'London' );
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Can return a jQuery object', function () {
|
||||
var args;
|
||||
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2,
|
||||
startRender: function ( rows, group ) {
|
||||
return $('<tr><td>Test jQuery</td></tr>');
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0)').text() ).toBe( 'Test jQuery' );
|
||||
} );
|
||||
|
||||
dt.html( 'basic' );
|
||||
|
||||
it( 'Can return a node', function () {
|
||||
var args;
|
||||
|
||||
table = $('#example').DataTable( {
|
||||
order: [[2, 'asc']],
|
||||
rowGroup: {
|
||||
dataSrc: 2,
|
||||
startRender: function ( rows, group ) {
|
||||
return $('<tr><td>Test node</td></tr>')[0];
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
expect( $('#example tbody tr:eq(0)').text() ).toBe( 'Test node' );
|
||||
} );
|
||||
} );
|
||||
4
public/js/v1.3.5/lib/select2.min.js
vendored
4
public/js/v1.3.5/lib/select2.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -306,7 +306,7 @@
|
||||
<div class="col-sm-10">
|
||||
<div class="input-group" title="add/remove character">
|
||||
<label for="{{characterSelectId}}"></label>
|
||||
<select id="{{characterSelectId}}" name="mapCharacters[]" multiple="multiple">
|
||||
<select id="{{characterSelectId}}" class="pf-select2" name="mapCharacters[]" multiple="multiple">
|
||||
{{#accessCharacter}}
|
||||
<option value="{{id}}" selected>{{name}}</option>
|
||||
{{/accessCharacter}}
|
||||
@@ -328,7 +328,7 @@
|
||||
<div class="col-sm-9">
|
||||
<div class="input-group" title="add/remove corporations">
|
||||
<label for="{{corporationSelectId}}"></label>
|
||||
<select id="{{corporationSelectId}}" name="mapCorporations[]" multiple="multiple">
|
||||
<select id="{{corporationSelectId}}" class="pf-select2" name="mapCorporations[]" multiple="multiple">
|
||||
{{#accessCorporation}}
|
||||
<option value="{{id}}" selected="selected" >{{name}}</option>
|
||||
{{/accessCorporation}}
|
||||
@@ -350,7 +350,7 @@
|
||||
<div class="col-sm-10">
|
||||
<div class="input-group" title="add/remove alliances">
|
||||
<label for="{{allianceSelectId}}"></label>
|
||||
<select id="{{allianceSelectId}}" name="mapAlliances[]" multiple="multiple" >
|
||||
<select id="{{allianceSelectId}}" class="pf-select2" name="mapAlliances[]" multiple="multiple" >
|
||||
{{#accessAlliance}}
|
||||
<option value="{{id}}" selected="selected" >{{name}}</option>
|
||||
{{/accessAlliance}}
|
||||
|
||||
75
public/templates/dialog/structure.html
Normal file
75
public/templates/dialog/structure.html
Normal file
@@ -0,0 +1,75 @@
|
||||
<div id="{{id}}">
|
||||
<form role="form" class="form-horizontal">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-6 ">
|
||||
<div class="form-group">
|
||||
<label for="form_name" class="col-sm-2 control-label">Name</label>
|
||||
<div class="col-sm-10">
|
||||
<input name="name" type="text" class="form-control" id="form_name" value="{{structureData.name}}" data-error="Name required" data-minlength="3" data-minlength-error="Min. of 3 characters" required>
|
||||
<span class="note help-block with-errors">Choose a meaningful name</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<div class="form-group">
|
||||
<label for="form_status" class="col-sm-4 control-label">Status</label>
|
||||
<div class="col-sm-8">
|
||||
<select name="statusId" id="form_status" class="form-control">
|
||||
{{#structureStatus}}
|
||||
<option value="{{id}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/structureStatus}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="{{typeSelectId}}">Type</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="input-group">
|
||||
<label for="{{typeSelectId}}"></label>
|
||||
<select id="{{typeSelectId}}" class="pf-select2" name="structureId"></select>
|
||||
<span class="note help-block with-errors"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label" for="{{corporationSelectId}}">Owner</label>
|
||||
<div class="col-sm-10">
|
||||
<div class="input-group">
|
||||
<label for="{{corporationSelectId}}"></label>
|
||||
<select id="{{corporationSelectId}}" class="pf-select2" name="corporationId">
|
||||
{{#structureData.owner}}
|
||||
<option value="{{id}}" selected="selected">{{name}}</option>
|
||||
{{/structureData.owner}}
|
||||
</select>
|
||||
<span class="note help-block with-errors"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-8 col-sm-12">
|
||||
<div class="form-group">
|
||||
<label for="{{descriptionTextareaId}}" class="col-sm-1 control-label">Note
|
||||
<kbd class="{{descriptionTextareaCharCounter}} txt-color text-right"> </kbd>
|
||||
</label>
|
||||
<div class="col-sm-6">
|
||||
<textarea id="{{descriptionTextareaId}}" name="description" class="form-control" maxlength="{{maxDescriptionLength}}" rows="3">{{structureData.description}}</textarea>
|
||||
<div class="note help-block with-errors"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
@@ -8,7 +8,7 @@
|
||||
<div class="col-sm-10">
|
||||
<div class="input-group">
|
||||
<label for="form_system"></label>
|
||||
<select id="form_system" name="systemId" class="{{selectClass}}" data-error="Choose a valid system" required>
|
||||
<select id="form_system" name="systemId" class="pf-select2 {{selectClass}}" data-error="Choose a valid system" required>
|
||||
{{#currentSystem}}
|
||||
<option value="{{id}}">{{name}}</option>
|
||||
{{/currentSystem}}
|
||||
|
||||
@@ -215,6 +215,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
// structure dialog ===========================================================
|
||||
#pf-structure-dialog{
|
||||
#pf-structure-dialog-corporation-select, #pf-structure-dialog-type-select{
|
||||
width: 267px !important;
|
||||
}
|
||||
}
|
||||
|
||||
// jump info dialog ===========================================================
|
||||
.pf-jump-info-dialog{
|
||||
blockquote{
|
||||
|
||||
@@ -30,6 +30,11 @@ input, select{
|
||||
&[disabled]{
|
||||
@include placeholder(transparent);
|
||||
}
|
||||
|
||||
&.pf-select2{
|
||||
height: 32px; // supposed to be select2 field (before initialization)
|
||||
padding: 6px 12px;
|
||||
}
|
||||
}
|
||||
|
||||
textarea{
|
||||
@@ -139,3 +144,9 @@ fieldset[disabled]{
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.pf-form-field-char-count{
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
@@ -209,7 +209,8 @@ select:active, select:hover {
|
||||
.dataTable{
|
||||
th{
|
||||
&.pf-table-image-cell,
|
||||
&.pf-table-image-small-cell{
|
||||
&.pf-table-image-small-cell,
|
||||
&.pf-table-image-smaller-cell{
|
||||
// no padding for image content
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
@@ -223,8 +224,17 @@ select:active, select:hover {
|
||||
}
|
||||
}
|
||||
|
||||
tr.group{
|
||||
background-color: rgba($gray-darker, 0.4);
|
||||
}
|
||||
|
||||
// "special" column styles
|
||||
td{
|
||||
|
||||
> .fa-circle{
|
||||
font-size: 9px !important; // should not be "so big" (10px default)
|
||||
}
|
||||
|
||||
&.pf-table-link-cell{
|
||||
cursor: pointer;
|
||||
@extend .txt-color;
|
||||
@@ -254,7 +264,6 @@ select:active, select:hover {
|
||||
}
|
||||
|
||||
&.pf-table-image-cell{
|
||||
// no padding for image content
|
||||
padding: 0 !important;
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
|
||||
@@ -275,6 +284,16 @@ select:active, select:hover {
|
||||
}
|
||||
}
|
||||
|
||||
&.pf-table-image-smaller-cell{
|
||||
padding: 0 !important;
|
||||
img{
|
||||
width: 25px; // smaller image (default 32)
|
||||
// overwrite "default" border for image cells
|
||||
border-left: 1px solid transparent;
|
||||
border-right: 1px solid transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&.pf-table-button-sm-cell{
|
||||
padding: 0 5px;
|
||||
}
|
||||
@@ -955,6 +974,18 @@ table{
|
||||
|
||||
}
|
||||
|
||||
// structure status ===============================================================================
|
||||
.pf-structure-status-unknown{
|
||||
color: $teal-lighter;
|
||||
}
|
||||
|
||||
.pf-structure-status-online{
|
||||
color: $green;
|
||||
}
|
||||
|
||||
.pf-structure-status-offline{
|
||||
color: $red-darker;
|
||||
}
|
||||
|
||||
// global tooltip settings ========================================================================
|
||||
.tooltip-inner{
|
||||
|
||||
@@ -28,11 +28,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pf-form-field-char-count{
|
||||
display: block;
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +149,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
// intel module ============================================================
|
||||
.pf-system-intel-module{
|
||||
|
||||
.pf-system-structure-table{
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
// killboard module ========================================================
|
||||
.pf-system-killboard-module{
|
||||
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
border: 1px solid transparent;
|
||||
overflow: hidden;
|
||||
@include box-shadow(0 6px 12px rgba(0,0,0, 0.3));
|
||||
|
||||
img{
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
width: 21px;
|
||||
}
|
||||
}
|
||||
|
||||
.select2-dropdown--above {
|
||||
@@ -34,12 +39,14 @@
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.select2-results > .select2-results__options {
|
||||
.select2-results {
|
||||
max-height: $results-max-height;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.select2-results__option {
|
||||
padding: 3px 6px;
|
||||
|
||||
&[role=group] {
|
||||
padding: 0;
|
||||
}
|
||||
@@ -71,7 +78,9 @@
|
||||
.select2-results__group {
|
||||
cursor: default;
|
||||
display: block;
|
||||
padding: 6px;
|
||||
padding: 3px 6px;
|
||||
background-color: $gray;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
&.select2-container--open .select2-dropdown {
|
||||
|
||||
@@ -3,15 +3,18 @@
|
||||
border: 1px solid $border-color;
|
||||
border-radius: $border-radius;
|
||||
outline: 0;
|
||||
|
||||
height: 32px;
|
||||
padding: 6px 12px;
|
||||
|
||||
&:focus {
|
||||
border: 1px solid $focus-border-color;
|
||||
}
|
||||
|
||||
.select2-selection__rendered {
|
||||
font-family: 'Oxygen Bold';
|
||||
color: $gray-lighter;
|
||||
line-height: 28px;
|
||||
line-height: 1.5;
|
||||
padding: 0 10px 0 0;
|
||||
}
|
||||
|
||||
.select2-selection__clear {
|
||||
|
||||
Reference in New Issue
Block a user