Version 4.5.0

This commit is contained in:
Neo committed 2025-12-19 05:51:58 -08:00
1 parent 1a0c7fd3c2
commit f79dcf067a
3791 files changed
+248032 -76372

No files matched your search

+131 -14
View File
@@ -11,7 +11,7 @@
namespace IPS\Helpers\Chart;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
@@ -66,6 +66,11 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
* @brief Type
*/
public $type;
/**
* @brief Search term
*/
public $searchTerm = null;
/**
* @brief Available Types
@@ -102,6 +107,11 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
*/
public $timezoneError = FALSE;
/**
* @brief If we need to show a timezone warning, we usually include a link to learn more - set this to TRUE to hide the link
*/
public $hideTimezoneLink = FALSE;
/**
* @brief If set to an \IPS\DateTime instance, minimum time will be checked against this value
*/
@@ -157,11 +167,11 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
$this->title = $title;
$this->options = $options;
$this->timescale = $defaultTimescale;
$this->start = $defaultTimes['start'];
$this->end = $defaultTimes['end'];
$this->start = $defaultTimes['start'] ?: \IPS\DateTime::create()->sub( new \DateInterval('P6M') );
$this->end = $defaultTimes['end'] ?: \IPS\DateTime::create();
$this->minimumDate = $minimumDate;
if ( isset( \IPS\Request::i()->type[ $this->identifier ] ) and in_array( \IPS\Request::i()->type[ $this->identifier ], $this->availableTypes ) )
if ( isset( \IPS\Request::i()->type[ $this->identifier ] ) and \in_array( \IPS\Request::i()->type[ $this->identifier ], $this->availableTypes ) )
{
$this->type = \IPS\Request::i()->type[ $this->identifier ];
$url = $url->setQueryString( 'type', array( $this->identifier => $this->type ) );
@@ -171,7 +181,14 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
$this->type = $defaultType;
}
if ( isset( \IPS\Request::i()->timescale[ $this->identifier ] ) and in_array( \IPS\Request::i()->timescale[ $this->identifier ], array( 'hourly', 'daily', 'weekly', 'monthly' ) ) )
/* Are we searching? The chart controller should inspect this property if it supports searching to limit the series it adds. */
if( isset( $this->options['limitSearch'] ) AND isset( \IPS\Request::i()->search[ $this->identifier ] ) )
{
$this->searchTerm = \IPS\Request::i()->search[ $this->identifier ];
}
/* Change timescale */
if ( isset( \IPS\Request::i()->timescale[ $this->identifier ] ) and \in_array( \IPS\Request::i()->timescale[ $this->identifier ], array( 'hourly', 'daily', 'weekly', 'monthly' ) ) )
{
if( \IPS\Request::i()->timescale[ $this->identifier ] != 'hourly' OR ( \IPS\Request::i()->timescale[ $this->identifier ] == 'hourly' AND $this->enableHourly === TRUE ) )
{
@@ -190,13 +207,17 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
$this->addHeader( \IPS\Member::loggedIn()->language()->addToStack('date'), ( $this->timescale == 'none' OR $this->timescale == 'hourly' ) ? 'datetime' : 'date' );
}
if ( isset( \IPS\Request::i()->start[ $this->identifier ] ) and \IPS\Request::i()->start[ $this->identifier ] )
if ( isset( \IPS\Request::i()->start[ $this->identifier ] ) )
{
try
{
$originalStart = $this->start;
if ( is_numeric( \IPS\Request::i()->start[ $this->identifier ] ) )
if( !\IPS\Request::i()->start[ $this->identifier ] )
{
$this->start = 0;
}
elseif ( \is_numeric( \IPS\Request::i()->start[ $this->identifier ] ) )
{
$this->start = \IPS\DateTime::ts( \IPS\Request::i()->start[ $this->identifier ] );
}
@@ -223,11 +244,15 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
catch ( \Exception $e ) {}
}
if ( isset( \IPS\Request::i()->end[ $this->identifier ] ) and \IPS\Request::i()->end[ $this->identifier ] )
if ( isset( \IPS\Request::i()->end[ $this->identifier ] ) )
{
try
{
if ( is_numeric( \IPS\Request::i()->end[ $this->identifier ] ) )
if( !\IPS\Request::i()->end[ $this->identifier ] )
{
$this->end = \IPS\DateTime::create();
}
elseif ( \is_numeric( \IPS\Request::i()->end[ $this->identifier ] ) )
{
$this->end = \IPS\DateTime::ts( \IPS\Request::i()->end[ $this->identifier ] );
}
@@ -251,7 +276,7 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
$this->url = $url;
if ( \IPS\Member::loggedIn()->timezone and in_array( \IPS\Member::loggedIn()->timezone, \DateTimeZone::listIdentifiers() ) )
if ( \IPS\Member::loggedIn()->timezone and \in_array( \IPS\Member::loggedIn()->timezone, \DateTimeZone::listIdentifiers() ) )
{
try
{
@@ -280,6 +305,14 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
}
}
/**
* Compile Data for Output
*
* @param array $data The data
* @return void
*/
abstract public function compileForOutput(): void;
/**
* Get the chart output
*
@@ -302,7 +335,7 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
try
{
/* If we have filters, we can save them */
if( count( $this->availableFilters ) > 0 )
if( \count( $this->availableFilters ) > 0 )
{
/* We have an existing chart ID */
if( isset( \IPS\Request::i()->chartId ) AND \IPS\Request::i()->chartId != '_default' )
@@ -404,7 +437,7 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
{
$chartOutput = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->dynamicChart( $this, $output );
if( count( $this->availableFilters ) > 0 AND ( !\IPS\Request::i()->isAjax() OR ( \IPS\Request::i()->tab AND !\IPS\Request::i()->chartId ) ) )
if( \count( $this->availableFilters ) > 0 AND ( !\IPS\Request::i()->isAjax() OR ( \IPS\Request::i()->tab AND !\IPS\Request::i()->chartId ) ) )
{
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->tabs( $this->getChartTabs(), ( isset( \IPS\Request::i()->chartId ) ) ? \IPS\Request::i()->chartId : NULL, $chartOutput, $this->url, 'chartId', 'ipsTabs_small ipsTabs_contained' );
}
@@ -471,7 +504,7 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
{
$filters = $this->currentFilters;
if ( in_array( $filter, $filters ) )
if ( \in_array( $filter, $filters ) )
{
unset( $filters[ array_search( $filter, $filters ) ] );
}
@@ -502,7 +535,7 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
case 'hourly':
$data[ $date->format( 'Y-n-j-h-i-s' ) ] = array();
$date->add( new \DateInterval( 'P1H' ) );
$date->add( new \DateInterval( 'PT1H' ) );
break;
case 'daily':
@@ -530,4 +563,88 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
return $data;
}
/**
* Download as CSV
*
* @param array|NULL $headers Headers, or NULL to use headers defined by this object.
* @param array|NULL $rows Rows, or NULL to use rows defined by this object.
* @param string|NULL $fileName File Name, or NULL to use the title defined by this object.
* @return void
*/
public function download( ?array $rawHeaders = NULL, ?array $rawRows = NULL, ?string $fileName = NULL ): void
{
/* Compile the data */
$file = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );
$fh = fopen( $file, 'w' );
/* Set headers */
$headers = array();
if ( $rawHeaders === NULL )
{
$rawHeaders = $this->headers;
}
foreach( $rawHeaders AS $data )
{
$headers[] = $data['label'];
}
fputcsv( $fh, $headers );
/* Set Rows */
if ( $rawRows === NULL )
{
$rawRows = $this->rows;
}
foreach( $rawRows AS $row )
{
$i = 0;
$save = array();
foreach( $rawHeaders AS $data )
{
switch( $data['type'] )
{
/* Booleans convert to string 'true' or 'false' */
case 'bool':
$save[] = ( $row[$i] ) ? 'true' : 'false';
break;
/* Make dates human readable */
case 'date':
case 'datetime':
case 'timeofday':
$save[] = ( new \IPS\DateTime( $row[$i] ) )->fullYearLocaleDate();
break;
/* Anything else can just save as-is */
default:
$save[] = $row[$i];
break;
}
$i++;
}
fputcsv( $fh, $save );
}
fclose( $fh );
$csv = \file_get_contents( $file );
if ( $fileName )
{
$name = $fileName;
}
else if ( $this->title )
{
$name = $this->title;
}
else
{
$name = \IPS\Output::i()->title;
}
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $name );
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $csv );
\IPS\Output::i()->sendOutput( $csv, 200, 'text/csv', array( 'Content-Disposition' => \IPS\Output::getContentDisposition( 'attachment', "{$name}.csv" ) ), FALSE, FALSE, FALSE );
}
}