Version 5.0.0 beta 1

This commit is contained in:
Neo committed 2025-12-19 16:27:35 -08:00
1 parent 25ddeb65d6
commit 15c7beabc5
6736 files changed
+627902 -497943

No files matched your search

+85 -72
View File
@@ -11,9 +11,25 @@
namespace IPS\Helpers\Form;
/* To prevent PHP errors (extending class does not exist) revealing path */
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
use Exception;
use IPS\Helpers\Form;
use IPS\IPS;
use IPS\Login;
use IPS\Request;
use IPS\Session;
use IPS\Theme;
use Throwable;
use function count;
use function defined;
use function in_array;
use function is_array;
use function is_object;
use function is_string;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
@@ -46,95 +62,95 @@ if ( $values = $matrix->values() )
\IPS\Output::i()->output = $matrix;
* @endcode
*/
class _Matrix extends \IPS\Helpers\Form
class Matrix extends Form
{
/**
* @brief Input Elements array
*/
public $elements = NULL;
public array $elements = array();
/**
* @brief Columns array
*/
public $columns = array();
public array $columns = array();
/**
* @brief Widths
*/
public $widths = array();
public array $widths = array();
/**
* @brief Columns to have "check all" checkboxes
*/
public $checkAlls = array();
public array $checkAlls = array();
/**
* @brief Should rows have all/none toggles?
*/
public $checkAllRows = FALSE;
public bool $checkAllRows = FALSE;
/**
* @brief Rows array
*/
public $rows = array();
public array $rows = array();
/**
* @brief Manageable? (Rows can be added and deleted)
*/
public $manageable = TRUE;
public bool $manageable = TRUE;
/**
* @brief Sortable?
*/
public $sortable = FALSE;
public bool $sortable = FALSE;
/**
* @brief Squash fields? (values in the matrix are json_encode'd as a single value to get around max_post_vars limits)
*/
public $squashFields = TRUE;
public bool $squashFields = TRUE;
/**
* @brief Added rows
* @see \IPS\Helpers\Form\Matrix::values
* @see Matrix::values
*/
public $addedRows = array();
public array $addedRows = array();
/**
* @brief Changed rows
* @see \IPS\Helpers\Form\Matrix::values
* @see Matrix::values
*/
public $changedRows = array();
public array $changedRows = array();
/**
* @brief Removed rows
* @see \IPS\Helpers\Form\Matrix::elements
* @see Matrix::elements
*/
public $removedRows = array();
public array $removedRows = array();
/**
* @brief Prefix to add to the language keys used for column headers
*/
public $langPrefix = '';
public string $langPrefix = '';
/**
* @brief Classnames to add to the table within the matrix
*/
public $classes = array();
public array $classes = array();
/**
* @brief Show tooltips in each cell?
*/
public $showTooltips = FALSE;
public bool $showTooltips = FALSE;
/**
* @brief Form Id, Set it Matrix is part of a form
* @brief Form ID, Set if Matrix is part of a form
*/
public $formId = NULL;
public ?string $formId = NULL;
/**
* @brief Determines whether the Row Titles are processed as raw html instead of a language string. Not needed if $langPrefix is set
*/
public $styledRowTitle = FALSE;
public bool $styledRowTitle = FALSE;
/**
* Get HTML
@@ -145,15 +161,12 @@ class _Matrix extends \IPS\Helpers\Form
{
try
{
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->matrix( $this->id, array_keys( $this->columns ), $this->elements(), $this->action, $this->hiddenValues, $this->actionButtons, $this->langPrefix, $this->calculateWidths(), $this->manageable, $this->checkAlls, $this->checkAllRows, $this->classes, $this->showTooltips, $this->squashFields, $this->sortable, $this->styledRowTitle );
return Theme::i()->getTemplate( 'forms', 'core', 'global' )->matrix( $this->id, array_keys( $this->columns ), $this->elements(), $this->action, $this->hiddenValues, $this->actionButtons, $this->langPrefix, $this->calculateWidths(), $this->manageable, $this->checkAlls, $this->checkAllRows, $this->classes, $this->showTooltips, $this->squashFields, $this->sortable, $this->styledRowTitle );
}
catch ( \Exception $e )
catch ( Exception|Throwable $e )
{
\IPS\IPS::exceptionHandler( $e );
}
catch ( \Throwable $e )
{
\IPS\IPS::exceptionHandler( $e );
IPS::exceptionHandler( $e );
return '';
}
}
@@ -162,9 +175,9 @@ class _Matrix extends \IPS\Helpers\Form
*
* @return string
*/
public function nested()
public function nested(): string
{
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->matrixNested( $this->id, array_keys( $this->columns ), $this->elements(), $this->action, $this->hiddenValues, $this->actionButtons, $this->langPrefix, $this->calculateWidths(), $this->manageable, $this->checkAlls, $this->checkAllRows, $this->classes, $this->showTooltips, $this->squashFields, $this->sortable, $this->styledRowTitle );
return Theme::i()->getTemplate( 'forms', 'core', 'global' )->matrixNested( $this->id, array_keys( $this->columns ), $this->elements(), $this->action, $this->hiddenValues, $this->actionButtons, $this->langPrefix, $this->calculateWidths(), $this->manageable, $this->checkAlls, $this->checkAllRows, $this->classes, $this->showTooltips, $this->squashFields, $this->sortable, $this->styledRowTitle );
}
/**
@@ -172,10 +185,10 @@ class _Matrix extends \IPS\Helpers\Form
*
* @return array
*/
protected function calculateWidths()
protected function calculateWidths(): array
{
$widths = $this->widths;
$width = ( ( 100 - array_sum( $this->widths ) ) / \count( $this->columns ) );
$width = ( ( 100 - array_sum( $this->widths ) ) / count( $this->columns ) );
foreach ( array_keys( $this->columns ) as $c )
{
if ( !isset( $widths[ $c ] ) )
@@ -186,22 +199,22 @@ class _Matrix extends \IPS\Helpers\Form
return $widths;
}
/**
* Get elements
*
* @param bool $getValues Get values?
* @return array
* @param bool $getValues Get values?
* @return array|null
*/
public function elements( $getValues=TRUE )
public function elements( bool $getValues=TRUE ): ?array
{
if ( $this->elements === NULL )
if( !count( $this->elements ) )
{
/* Stuff about our form */
$name = "{$this->id}_submitted";
$formName = $this->formId ? "{$this->formId}_submitted" : NULL;
$matrixName = "{$this->id}_matrixRows";
$matrixValues = \IPS\Request::i()->$matrixName;
$matrixValues = Request::i()->$matrixName;
/* Loop our defined rows */
$this->elements = array();
@@ -209,7 +222,7 @@ class _Matrix extends \IPS\Helpers\Form
{
/* Have we deleted this row? */
$deleteKey = "{$rowId}_delete";
if ( $this->manageable and ( isset( \IPS\Request::i()->$name ) or ( $formName and isset( \IPS\Request::i()->$formName ) ) ) and ( isset( \IPS\Request::i()->$deleteKey ) or !isset( $matrixValues[ $rowId ] ) or !$matrixValues[ $rowId ] ) )
if ( $this->manageable and ( isset( Request::i()->$name ) or ( $formName and isset( Request::i()->$formName ) ) ) and ( isset( Request::i()->$deleteKey ) or !isset( $matrixValues[ $rowId ] ) or !$matrixValues[ $rowId ] ) )
{
$this->removedRows[] = $rowId;
continue;
@@ -226,10 +239,10 @@ class _Matrix extends \IPS\Helpers\Form
}
/* Look for added ones */
if ( isset( \IPS\Request::i()->_new_ ) )
if ( isset( Request::i()->_new_ ) )
{
$i = 1;
foreach ( \IPS\Request::i()->_new_ as $newId => $data )
foreach ( Request::i()->_new_ as $newId => $data )
{
$added = TRUE;
if ( $newId === 'x_unlimited' )
@@ -252,11 +265,11 @@ class _Matrix extends \IPS\Helpers\Form
if ( $added )
{
/* Select lists can have user-supplied input, so look for that too */
foreach( \IPS\Request::i() as $inputKey => $inputValue )
foreach( Request::i() as $inputKey => $inputValue )
{
if( $pos = mb_strpos( $inputKey, '_new_' ) AND $inputKey !== '_new_' )
{
if( \is_array( $inputValue ) AND isset( $inputValue[ $newId ] ) )
if( is_array( $inputValue ) AND isset( $inputValue[ $newId ] ) )
{
/* @note This previously used an array_merge() however this was causing elements to be overwritten with a blank value in some cases */
foreach( $inputValue[ $newId ] AS $key => $value )
@@ -287,12 +300,12 @@ class _Matrix extends \IPS\Helpers\Form
if ( $this->sortable )
{
$matrixOrderName = "{$this->id}_matrixOrder";
if ( isset( \IPS\Request::i()->$matrixOrderName ) )
if ( isset( Request::i()->$matrixOrderName ) )
{
$matrixOrderValues = \IPS\Request::i()->$matrixOrderName;
$matrixOrderValues = Request::i()->$matrixOrderName;
uksort( $this->elements, function( $a, $b ) use ( $matrixOrderValues ) {
if ( \in_array( $a, $matrixOrderValues ) and \in_array( $b, $matrixOrderValues ) )
if ( in_array( $a, $matrixOrderValues ) and in_array( $b, $matrixOrderValues ) )
{
return array_search( $a, $matrixOrderValues ) - array_search( $b, $matrixOrderValues );
}
@@ -304,18 +317,18 @@ class _Matrix extends \IPS\Helpers\Form
return $this->elements;
}
/**
* Build Row
*
* @param mixed $rowId Row identifier
* @param array $data Values
* @return array
* @param mixed $rowId Row identifier
* @param mixed $data Values
* @return array|string
*/
protected function buildRow( $rowId, $data )
protected function buildRow( mixed $rowId, mixed $data ): array|string
{
$row = array();
if ( \is_string( $data ) )
if ( is_string( $data ) )
{
return $data;
}
@@ -324,20 +337,20 @@ class _Matrix extends \IPS\Helpers\Form
$inputName = "{$rowId}[{$columnName}]";
/* Create using array */
if ( \is_array( $columnData ) )
if ( is_array( $columnData ) )
{
$classname = '\IPS\Helpers\Form\\' . $columnData[0];
$row[ $columnName ] = new $classname(
$inputName,
isset( $data[ $columnName ] ) ? $data[ $columnName ] : ( isset( $columnData[1] ) ? $columnData[1] : NULL ),
isset( $columnData[2] ) ? $columnData[2] : FALSE,
isset( $columnData[3] ) ? $columnData[3] : array()
$data[$columnName] ?? ( $columnData[1] ?? NULL ),
$columnData[2] ?? FALSE,
$columnData[3] ?? array()
);
}
/* Create using callback function */
else
{
$row[ $columnName ] = $columnData( $inputName, isset( $data[ $columnName ] ) ? $data[ $columnName ] : NULL, $data );
$row[ $columnName ] = $columnData( $inputName, $data[$columnName] ?? NULL, $data );
}
}
if ( isset( $data['_level'] ) )
@@ -351,42 +364,42 @@ class _Matrix extends \IPS\Helpers\Form
/**
* Get submitted values
*
* @param bool $force If true, wil not check if form was submitted (used for nested matrixes)
* @param bool $stringValues If true, wil not check if form was submitted (used for nested matrixes)
* @return array|FALSE Array of field values or FALSE if the form has not been submitted or if there were validation errors
*/
public function values( $force=FALSE )
public function values( bool $stringValues=FALSE ): array|false
{
$values = array();
$name = "{$this->id}_submitted";
if( $force or ( isset( \IPS\Request::i()->$name ) and \IPS\Login::compareHashes( (string) \IPS\Session::i()->csrfKey, (string) \IPS\Request::i()->csrfKey ) ) )
if( $stringValues or ( isset( Request::i()->$name ) and Login::compareHashes( Session::i()->csrfKey, (string) Request::i()->csrfKey ) ) )
{
// Do we need to unsquash any values?
// Squashed values are json_encoded by javascript to prevent us exceeding max_post_vars
$squashedField = $this->id . '_squashed';
// If 'squashedField' isn't in the request it might indicate the user didn't have JS enabled
if ( $this->squashFields && isset( \IPS\Request::i()->$squashedField ) )
if ( $this->squashFields && isset( Request::i()->$squashedField ) )
{
if ( isset( \IPS\Request::i()->$squashedField ) )
if ( isset( Request::i()->$squashedField ) )
{
$unsquashed = json_decode( \IPS\Request::i()->$squashedField, TRUE );
$unsquashed = json_decode( Request::i()->$squashedField, TRUE );
foreach( $unsquashed as $key => $value )
{
\IPS\Request::i()->$key = $value;
Request::i()->$key = $value;
}
}
}
foreach ( $this->elements( FALSE ) as $rowId => $columns )
{
if ( \is_array( $columns ) )
if ( is_array( $columns ) )
{
foreach ( $columns as $columnName => $element )
{
/* If this was a ehader or something, skip it */
if ( !\is_object( $element ) )
if ( !is_object( $element ) )
{
continue;
}
@@ -398,7 +411,7 @@ class _Matrix extends \IPS\Helpers\Form
}
/* If the "check all" box was checked, set it to TRUE */
if ( $element instanceof Checkbox and isset( \IPS\Request::i()->__all[ $columnName ] ) and ! $element->options['disabled'] )
if ( $element instanceof Checkbox and isset( Request::i()->__all[ $columnName ] ) and ! $element->options['disabled'] )
{
$element->value = TRUE;
}
@@ -407,7 +420,7 @@ class _Matrix extends \IPS\Helpers\Form
if ( isset( $element->options['unlimited'] ) )
{
$unlimitedKey = "{$rowId}[{$columnName}_unlimited]";
$value = \IPS\Request::i()->valueFromArray( $unlimitedKey );
$value = Request::i()->valueFromArray( $unlimitedKey );
if ( $value !== NULL )
{
$element->value = $value;
@@ -417,7 +430,7 @@ class _Matrix extends \IPS\Helpers\Form
if ( isset( $element->options['nullLang'] ) )
{
$nullKey = "{$rowId}[{$columnName}_null]";
if ( $value = \IPS\Request::i()->valueFromArray( $nullKey ) )
if ( $value = Request::i()->valueFromArray( $nullKey ) )
{
$element->value = NULL;
}