- UI changes to "build index" button on /setup

- updated `wormhole.csv`
- upgrade SDE dump `eve_lifeblood.sql` -> `eve_abyss.sql`
- upgrade endpoint "getUniverseSystemData()" `v3` -> `v4`
- upgrade endpoint "getUniverseStructureData()" `v1` -> `v2`
- some minor code improvements
This commit is contained in:
Mark Friedrich
2018-06-02 19:29:00 +02:00
parent 0417aafa97
commit c805a2ea0c
30 changed files with 876 additions and 1910 deletions

View File

@@ -54,4 +54,7 @@ deleteAuthenticationData = Cron\CharacterUpdate->deleteAuthenticati
deleteExpiredCacheData = Cron\Cache->deleteExpiredData, @downtime
; delete old statistics (activity log) data
deleteStatisticsData = Cron\StatisticsUpdate->deleteStatisticsData, @weekly
deleteStatisticsData = Cron\StatisticsUpdate->deleteStatisticsData, @weekly
; setup universe DB with static data from ESI
; setup = Cron\Universe->setup, @instant

View File

@@ -91,6 +91,15 @@ class Setup extends Controller\Controller {
$return->countBuildAll = $categoryUniverseModel->getById($categoryId, 0)->getTypesCount(false);
$return->progress = $percent($return->countAll, $return->countBuildAll);
break;
case 'SystemNeighbourModel':
// Becomes deprecated with new Universe DB!!!
$this->setupSystemJumpTable();
$return->countAll = 5214;
$return->countBuild = Database::instance()->getRowCount('system_neighbour');
$return->countBuildAll = $return->countBuild;
$return->progress = $percent($return->countAll, $return->countBuildAll);
break;
}
if($return->countBuildAll < $return->countAll){
@@ -130,5 +139,74 @@ class Setup extends Controller\Controller {
echo json_encode($return);
}
/**
* This function is just for setting up the cache table 'system_neighbour' which is used
* for system jump calculation. Call this function manually when CCP adds Systems/Stargates
*/
protected function setupSystemJumpTable(){
$pfDB = $this->getDB('PF');
$ccpDB = $this->getDB('CCP');
$query = "SELECT
map_sys.solarSystemID system_id,
map_sys.regionID region_id,
map_sys.constellationID constellation_id,
map_sys.solarSystemName system_name,
ROUND( map_sys.security, 4) system_security,
(
SELECT
GROUP_CONCAT( NULLIF(map_sys_inner.solarSystemName, NULL) SEPARATOR ':')
FROM
mapSolarSystemJumps map_jump INNER JOIN
mapSolarSystems map_sys_inner ON
map_sys_inner.solarSystemID = map_jump.toSolarSystemID
WHERE
map_jump.fromSolarSystemID = map_sys.solarSystemID
) system_neighbours
FROM
mapSolarSystems map_sys
HAVING
-- skip systems without neighbors (e.g. WHs)
system_neighbours IS NOT NULL
";
$rows = $ccpDB->exec($query);
if(count($rows) > 0){
// switch DB back to pathfinder DB
// clear cache table
$pfDB->exec("TRUNCATE system_neighbour");
foreach($rows as $row){
$pfDB->exec("
INSERT INTO
system_neighbour(
regionId,
constellationId,
systemName,
systemId,
jumpNodes,
trueSec
)
VALUES(
:regionId,
:constellationId,
:systemName,
:systemId,
:jumpNodes,
:trueSec
)",
[
':regionId' => $row['region_id'],
':constellationId' => $row['constellation_id'],
':systemName' => $row['system_name'],
':systemId' => $row['system_id'],
':jumpNodes' => $row['system_neighbours'],
':trueSec' => $row['system_security']
]);
}
}
}
}

View File

@@ -112,14 +112,14 @@ class Setup extends Controller {
'Model\Universe\GroupModel',
'Model\Universe\CategoryModel',
'Model\Universe\StructureModel',
'Model\Universe\WormholeModel',
'Model\Universe\StargateModel',
'Model\Universe\StarModel',
'Model\Universe\PlanetModel',
'Model\Universe\SystemModel',
'Model\Universe\ConstellationModel',
'Model\Universe\RegionModel',
'Model\Universe\SystemStaticModel'
// 'Model\Universe\WormholeModel',
// 'Model\Universe\StargateModel',
// 'Model\Universe\StarModel',
// 'Model\Universe\PlanetModel',
// 'Model\Universe\SystemModel',
// 'Model\Universe\ConstellationModel',
// 'Model\Universe\RegionModel',
// 'Model\Universe\SystemStaticModel'
],
'tables' => []
],
@@ -231,9 +231,6 @@ class Setup extends Controller {
case 'fixCols':
$fixColumns = true;
break;
case 'buildIndex':
$this->setupSystemJumpTable();
break;
case 'importTable':
$this->importTable($params['model']);
break;
@@ -1354,14 +1351,15 @@ class Setup extends Controller {
protected function getIndexData(\Base $f3){
// active DB and tables are required for obtain index data
if(!$this->databaseHasError){
$categoryUniverseModel = Model\Universe\BasicUniverseModel::getNew('CategoryModel');
$systemUniverseModel = Model\Universe\BasicUniverseModel::getNew('SystemModel');
//$categoryUniverseModel = Model\Universe\BasicUniverseModel::getNew('CategoryModel');
//$systemUniverseModel = Model\Universe\BasicUniverseModel::getNew('SystemModel');
$systemNeighbourModel = Model\BasicModel::getNew('SystemNeighbourModel');
$wormholeModel = Model\BasicModel::getNew('WormholeModel');
$systemWormholeModel = Model\BasicModel::getNew('SystemWormholeModel');
$constellationWormholeModel = Model\BasicModel::getNew('ConstellationWormholeModel');
$indexInfo = [
/*
'Systems' => [
'task' => [
[
@@ -1408,7 +1406,8 @@ class Setup extends Controller {
'countBuild' => $categoryUniverseModel->getById(6, 0)->getTypesCount(false),
'countAll' => (int)$f3->get('REQUIREMENTS.DATA.SHIPS'),
'tooltip' => 'import all ships types from ESI. Runtime: ~2min'
],
], */
// All following rows become deprecated
'SystemNeighbourModel' => [
'task' => [
[
@@ -1456,7 +1455,7 @@ class Setup extends Controller {
],
'label' => 'system_wormhole',
'countBuild' => $this->dbLib->getRowCount($systemWormholeModel->getTable()),
'countAll' => 233
'countAll' => 234
],
'ConstellationWormholeModel' => [
'task' => [
@@ -1474,91 +1473,21 @@ class Setup extends Controller {
],
'label' => 'constellation_wormhole',
'countBuild' => $this->dbLib->getRowCount( $constellationWormholeModel->getTable() ),
'countAll' => 460
'countAll' => 461
]
];
}else{
$indexInfo = [
'SystemNeighbourModel' => [
'task' => [],
'table' => 'Fix database errors first!'
'label' => 'Fix database errors first!'
]
];
}
//var_dump($indexInfo); die();
return $indexInfo;
}
/**
* This function is just for setting up the cache table 'system_neighbour' which is used
* for system jump calculation. Call this function manually when CCP adds Systems/Stargates
*/
protected function setupSystemJumpTable(){
$pfDB = $this->getDB('PF');
$ccpDB = $this->getDB('CCP');
$query = "SELECT
map_sys.solarSystemID system_id,
map_sys.regionID region_id,
map_sys.constellationID constellation_id,
map_sys.solarSystemName system_name,
ROUND( map_sys.security, 4) system_security,
(
SELECT
GROUP_CONCAT( NULLIF(map_sys_inner.solarSystemName, NULL) SEPARATOR ':')
FROM
mapSolarSystemJumps map_jump INNER JOIN
mapSolarSystems map_sys_inner ON
map_sys_inner.solarSystemID = map_jump.toSolarSystemID
WHERE
map_jump.fromSolarSystemID = map_sys.solarSystemID
) system_neighbours
FROM
mapSolarSystems map_sys
HAVING
-- skip systems without neighbors (e.g. WHs)
system_neighbours IS NOT NULL
";
$rows = $ccpDB->exec($query);
if(count($rows) > 0){
// switch DB back to pathfinder DB
// clear cache table
$pfDB->exec("TRUNCATE system_neighbour");
foreach($rows as $row){
$pfDB->exec("
INSERT INTO
system_neighbour(
regionId,
constellationId,
systemName,
systemId,
jumpNodes,
trueSec
)
VALUES(
:regionId,
:constellationId,
:systemName,
:systemId,
:jumpNodes,
:trueSec
)",
[
':regionId' => $row['region_id'],
':constellationId' => $row['constellation_id'],
':systemName' => $row['system_name'],
':systemId' => $row['system_id'],
':jumpNodes' => $row['system_neighbours'],
':trueSec' => $row['system_security']
]);
}
}
}
/**
* import table data from existing dump file (e.g *.csv)
* @param string $modelClass

View File

@@ -156,13 +156,13 @@ class Universe {
/**
* imports static universe data from ESI
* >> php index.php "/cron/setup?model=system&offset=0&length=5"
* >> php index.php "/cron/setup?type=system&offset=0&length=5"
* @param \Base $f3
* @throws \Exception
*/
function setup(\Base $f3){
$params = (array)$f3->get('GET');
$type = (string)$params['model'];
$type = (string)$params['type'];
$paramOffset = (int)$params['offset'];
$paramLength = (int)$params['length'];
$timeTotalStart = microtime(true);

View File

@@ -40,9 +40,6 @@ class AllianceModel extends BasicModel {
'allianceCharacters' => [
'has-many' => ['Model\CharacterModel', 'allianceId']
],
'alliancCorporations' => [
'has-many' => ['Model\CharacterModel', 'allianceId']
],
'mapAlliances' => [
'has-many' => ['Model\AllianceMapModel', 'allianceId']
]

View File

@@ -99,9 +99,7 @@ abstract class BasicUniverseModel extends BasicModel {
* -> stores getData() result into Cache (RAM) for faster access
*/
public function buildIndex(){
$hashKeyId = $this->getHashKey();
$hashKeyName = $this->getHashKey('name');
if($hashKeyId && $hashKeyName){
if($hashKeyId = $this->getHashKey()){
$f3 = self::getF3();
$hashKeyTable = self::generateHashKeyTable($this->getTable());
@@ -109,18 +107,16 @@ abstract class BasicUniverseModel extends BasicModel {
$cachedData = [];
}
if( !in_array($hashKeyName, $cachedData) ){
$cachedData[] = $hashKeyName;
if( !in_array($hashKeyId, $cachedData) ){
$cachedData[] = $hashKeyId;
}
// value update does not update ttl -> delete key from cache and add again
$f3->clear($hashKeyId);
$f3->clear($hashKeyName);
$f3->clear($hashKeyTable);
// straight into cache (no $f->set() ), no sync with hive here -> save ram
self::setCacheValue($hashKeyId, $this->getData(), self::CACHE_INDEX_EXPIRE_KEY);
self::setCacheValue($hashKeyName, $hashKeyId, self::CACHE_INDEX_EXPIRE_KEY);
self::setCacheValue($hashKeyTable, $cachedData, self::CACHE_INDEX_EXPIRE_KEY);
}
}

View File

@@ -52,7 +52,6 @@ class GroupModel extends BasicUniverseModel {
$groupData->id = $this->id;
$groupData->name = $this->name;
if($typesData = $this->getTypesData()){
$groupData->types = $typesData;
}

View File

@@ -8,10 +8,8 @@
namespace Model\Universe;
use DB\SQL;
use DB\SQL\Schema;
use lib\Util;
class StructureModel extends BasicUniverseModel {
@@ -81,32 +79,25 @@ class StructureModel extends BasicUniverseModel {
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
$data = self::getF3()->ccpClient->getUniverseStructureData($id, $accessToken, $additionalOptions);
if(!empty($data)){
/**
* @var $type TypeModel
*/
$type = $this->rel('typeId');
$type->loadById($data['typeId'], $accessToken, $additionalOptions);
$data['typeId'] = $type;
$this->copyfrom($data);
$this->copyfrom($data, ['id', 'name', 'systemId', 'typeId', 'position']);
$this->save();
}
}
/**
* @param array|string $key
* @param null $fields
* @return NULL
*/
public function copyfrom($key, $fields = null){
// flatten array (e.g. "position" key)
$key = Util::arrayFlattenByKey((array)$key);
parent::copyfrom($key, $fields);
}
/**
* overwrites parent
* @param null|SQL $db
* @param null $table
* @param null $fields
* @return bool
* @throws \Exception
*/
public static function setup($db=null, $table=null, $fields=null){
if($status = parent::setup($db,$table,$fields)){

View File

@@ -107,12 +107,15 @@ class SystemModel extends BasicUniverseModel {
$systemData->id = $this->_id;
$systemData->name = $this->name;
$systemData->constellation = $this->constellationId->getData();
$systemData->star = $this->starId->getData();
$systemData->security = $this->security;
$systemData->trueSec = $this->trueSec;
$systemData->effect = $this->effect;
$systemData->shattered = $this->shattered;
if($this->starId){
$systemData->star = $this->starId->getData();
}
if( !empty($planetsData = $this->getPlanetsData()) ){
$systemData->planets = $planetsData;
}
@@ -128,6 +131,20 @@ class SystemModel extends BasicUniverseModel {
return $systemData;
}
/**
* setter for system name
* @param $name
* @return mixed
*/
public function set_name($name){
// name should never change
// -> important for "Abyssal" systems where ESI don´t have correct system name
if(!empty($this->name)){
$name = $this->name;
}
return $name;
}
/**
* setter for row (un-formatted) trueSec
* @param $secStatus
@@ -144,13 +161,24 @@ class SystemModel extends BasicUniverseModel {
$this->trueSec = $trueSec;
// set 'security' for NON wormhole systems! -> those get updated from csv import
if(!preg_match('/^j\d+$/i', $this->name)){
if($trueSec <= 0){
$security = '0.0';
}elseif($trueSec < 0.5){
$security = 'L';
// check for "Abyssal" system
if(
$this->get('constellationId', true) >= 22000001 &&
$this->get('constellationId', true) <= 22000025
){
// "Abyssal" system
$security = 'A';
}else{
$security = 'H';
// k-space system
if($trueSec <= 0){
$security = '0.0';
}elseif($trueSec < 0.5){
$security = 'L';
}else{
$security = 'H';
}
}
$this->security = $security;
}
return $secStatus;
@@ -297,6 +325,7 @@ class SystemModel extends BasicUniverseModel {
*/
protected function loadData(int $id, string $accessToken = '', array $additionalOptions = []){
$data = self::getF3()->ccpClient->getUniverseSystemData($id);
if(!empty($data)){
/**
* @var $constellation ConstellationModel
@@ -305,12 +334,15 @@ class SystemModel extends BasicUniverseModel {
$constellation->loadById($data['constellationId'], $accessToken, $additionalOptions);
$data['constellationId'] = $constellation;
/**
* @var $star StarModel
*/
$star = $this->rel('starId');
$star->loadById($data['starId'], $accessToken, $additionalOptions);
$data['starId'] = $star;
// starId is optional since ESI v4 (e.g. Abyssal systems)
if($data['starId']){
/**
* @var $star StarModel
*/
$star = $this->rel('starId');
$star->loadById($data['starId'], $accessToken, $additionalOptions);
$data['starId'] = $star;
}
$this->copyfrom($data, ['id', 'name', 'constellationId', 'starId', 'securityStatus', 'securityClass', 'position']);
$this->save();
@@ -323,7 +355,8 @@ class SystemModel extends BasicUniverseModel {
public function loadPlanetsData(){
if( !$this->dry() ){
$data = self::getF3()->ccpClient->getUniverseSystemData($this->_id);
if(!empty($data)){
if($data['planets']){
// planets are optional since ESI v4 (e.g. Abyssal systems)
foreach((array)$data['planets'] as $planetData){
/**
* @var $planet PlanetModel

View File

@@ -36,7 +36,7 @@
"37";"M609";"C4";"1000000000";"20000000";;"16";"4";
"38";"N062";"C5";"3000000000";"300000000";;"24";"2.5";
"39";"N110";"H";"1000000000";"20000000";;"24";"10";
"40";"N290";"L";"3000000000";"1800000000";"500000000";"24";;
"40";"N290";"L";"3000000000";"1350000000";"500000000";"24";;
"41";"N432";"C5";"3000000000";"1350000000";;"24";"10";
"42";"N766";"C2";"2000000000";"300000000";;"16";"4";
"43";"N770";"C5";"3000000000";"300000000";;"24";"2.5";
@@ -56,7 +56,7 @@
"57";"S804";"C6";"1000000000";"20000000";;"24";"1.25";
"58";"T405";"C4";"2000000000";"300000000";;"16";"6.67";
"59";"U210";"L";"3000000000";"300000000";;"24";"10";
"60";"U319";"C6";"3000000000";"1800000000";"500000000";"48";;
"60";"U319";"C6";"3000000000";"1350000000";"500000000";"48";;
"61";"U574";"C6";"3000000000";"300000000";;"24";"1.25";
"62";"V283";"0.0";"3000000000";"1000000000";;"24";"2.5";
"63";"V301";"C1";"500000000";"20000000";;"16";"5";
1 Id Name Security MassTotal MassIndividual MassRegeneration MaxStableTime SignatureStrength
36 37 M609 C4 1000000000 20000000 16 4
37 38 N062 C5 3000000000 300000000 24 2.5
38 39 N110 H 1000000000 20000000 24 10
39 40 N290 L 3000000000 1800000000 1350000000 500000000 24
40 41 N432 C5 3000000000 1350000000 24 10
41 42 N766 C2 2000000000 300000000 16 4
42 43 N770 C5 3000000000 300000000 24 2.5
56 57 S804 C6 1000000000 20000000 24 1.25
57 58 T405 C4 2000000000 300000000 16 6.67
58 59 U210 L 3000000000 300000000 24 10
59 60 U319 C6 3000000000 1800000000 1350000000 500000000 48
60 61 U574 C6 3000000000 300000000 24 1.25
61 62 V283 0.0 3000000000 1000000000 24 2.5
62 63 V301 C1 500000000 20000000 16 5

File diff suppressed because it is too large Load Diff

View File

@@ -101,7 +101,7 @@ define(['jquery'], function($) {
4: 'M609 - C4',
5: 'L614 - C5',
6: 'S804 - C6',
7: 'F135 - Thera'
7: 'F353 - Thera'
},
6: { // ORE
1: 'Ordinary Perimeter Deposit', //*

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,414 +0,0 @@
/*! 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;
}));

View File

@@ -1,55 +0,0 @@
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' );
} );
} );

View File

@@ -1,35 +0,0 @@
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' );
} );
} );

View File

@@ -1,48 +0,0 @@
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' );
} );
} );

View File

@@ -1,52 +0,0 @@
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' );
} );
} );

View File

@@ -1,26 +0,0 @@
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' );
} );
} );

View File

@@ -1,56 +0,0 @@
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 );
} );
} );

View File

@@ -1,43 +0,0 @@
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' );
} );
} );

View File

@@ -1,40 +0,0 @@
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 );
} );
} );

View File

@@ -1,46 +0,0 @@
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 );
} );
} );

View File

@@ -1,88 +0,0 @@
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' );
} );
} );

View File

@@ -1,40 +0,0 @@
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 );
} );
} );

View File

@@ -1,121 +0,0 @@
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' );
} );
} );

View File

@@ -927,17 +927,19 @@
<span class="btn disabled btn-fake">{{ @indexData.label }}</span>
</div>
<div class="col-xs-3 text-right">
<check if="{{ @indexData.countBuild >= @indexData.countAll }}">
<kbd class="txt-color txt-color-success">{{ @indexData.countBuild }}/{{ @indexData.countAll }}</kbd>
</check>
<check if="{{ @indexData.countBuild > 0 && @indexData.countBuild < @indexData.countAll}}">
<kbd class="txt-color txt-color-warning">{{ @indexData.countBuild }}/{{ @indexData.countAll }}</kbd>
</check>
<check if="{{ @indexData.countBuild <= 0 }}">
<kbd class="txt-color txt-color-danger">{{ @indexData.countBuild }}/{{ @indexData.countAll }}</kbd>
</check>
<check if="{{ @indexData.tooltip }}">
<i class="fas fa-fw fa-sm fa-question-circle pf-help-light" title="{{ @indexData.tooltip }}"></i>
<check if="{{ isset(@indexData.countAll) }}">
<check if="{{ @indexData.countBuild >= @indexData.countAll }}">
<kbd class="txt-color txt-color-success">{{ @indexData.countBuild }}/{{ @indexData.countAll }}</kbd>
</check>
<check if="{{ @indexData.countBuild > 0 && @indexData.countBuild < @indexData.countAll}}">
<kbd class="txt-color txt-color-warning">{{ @indexData.countBuild }}/{{ @indexData.countAll }}</kbd>
</check>
<check if="{{ @indexData.countBuild <= 0 }}">
<kbd class="txt-color txt-color-danger">{{ @indexData.countBuild }}/{{ @indexData.countAll }}</kbd>
</check>
<check if="{{ @indexData.tooltip }}">
<i class="fas fa-fw fa-sm fa-question-circle pf-help-light" title="{{ @indexData.tooltip }}"></i>
</check>
</check>
</div>
<div class="col-xs-5">

View File

@@ -124,6 +124,7 @@ fieldset[disabled]{
display: block;
height: 100%;
background-color: rgba($green, .2 );
max-width: 100%;
width: 0;
top: 0;
left: 0;