Version 5.0.0 beta 1
This commit is contained in:
1 parent
25ddeb65d6
commit
15c7beabc5
6736 files changed
+627902
-497943
No files matched your search
+117
-149
@@ -11,16 +11,38 @@
|
||||
namespace IPS\Helpers\Form;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use IPS\Db;
|
||||
use IPS\Dispatcher;
|
||||
use IPS\IPS;
|
||||
use IPS\Member;
|
||||
use IPS\Node\Model;
|
||||
use IPS\Output;
|
||||
use IPS\Patterns\ActiveRecordIterator;
|
||||
use IPS\Request;
|
||||
use IPS\Settings;
|
||||
use IPS\Theme;
|
||||
use function count;
|
||||
use function defined;
|
||||
use function get_class;
|
||||
use function in_array;
|
||||
use function is_array;
|
||||
use function is_callable;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Text input class for Form Builder
|
||||
*/
|
||||
class _Node extends FormAbstract
|
||||
class Node extends FormAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Default Options
|
||||
@@ -49,7 +71,7 @@ class _Node extends FormAbstract
|
||||
);
|
||||
* @endcode
|
||||
*/
|
||||
protected $defaultOptions = array(
|
||||
protected array $defaultOptions = array(
|
||||
'url' => NULL,
|
||||
'class' => NULL,
|
||||
'permissionCheck' => NULL,
|
||||
@@ -71,31 +93,30 @@ class _Node extends FormAbstract
|
||||
'clubs' => FALSE,
|
||||
'maxResults' => FALSE,
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $name Name
|
||||
* @param mixed $defaultValue Default value
|
||||
* @param bool|NULL $required Required? (NULL for not required, but appears to be so)
|
||||
* @param array $options Type-specific options
|
||||
* @param callback $customValidationCode Custom validation code
|
||||
* @param string $prefix HTML to show before input field
|
||||
* @param string $suffix HTML to show after input field
|
||||
* @param string $id The ID to add to the row
|
||||
* @return void
|
||||
* @param string $name Name
|
||||
* @param mixed $defaultValue Default value
|
||||
* @param bool|null $required Required? (NULL for not required, but appears to be so)
|
||||
* @param array $options Type-specific options
|
||||
* @param callable|null $customValidationCode Custom validation code
|
||||
* @param string|null $prefix HTML to show before input field
|
||||
* @param string|null $suffix HTML to show after input field
|
||||
* @param string|null $id The ID to add to the row
|
||||
*/
|
||||
public function __construct( $name, $defaultValue=NULL, $required=FALSE, $options=array(), $customValidationCode=NULL, $prefix=NULL, $suffix=NULL, $id=NULL )
|
||||
public function __construct( string $name, mixed $defaultValue=NULL, ?bool $required=FALSE, array $options=array(), callable $customValidationCode=NULL, string $prefix=NULL, string $suffix=NULL, string $id=NULL )
|
||||
{
|
||||
parent::__construct( $name, $defaultValue, $required, $options, $customValidationCode, $prefix, $suffix, $id );
|
||||
|
||||
if ( !$this->options['url'] )
|
||||
{
|
||||
$this->options['url'] = \IPS\Request::i()->url();
|
||||
$this->options['url'] = Request::i()->url();
|
||||
}
|
||||
$this->options['url'] = $this->options['url']->setQueryString( '_nodeSelectName', $this->name );
|
||||
|
||||
if ( $this->options['clubs'] and ( !\IPS\Settings::i()->clubs or !\IPS\IPS::classUsesTrait( $this->options['class'], 'IPS\Content\ClubContainer' ) ) )
|
||||
if ( $this->options['clubs'] and ( !Settings::i()->clubs or !IPS::classUsesTrait( $this->options['class'], 'IPS\Content\ClubContainer' ) ) )
|
||||
{
|
||||
$this->options['clubs'] = FALSE;
|
||||
}
|
||||
@@ -115,40 +136,40 @@ class _Node extends FormAbstract
|
||||
* @note $selectable controls whether the node is selectable, not whether it is provided as an option or not.
|
||||
* @note $showable controls whether or not the node should be displayed at all. On the front end this is based on view permissions, and on the backend we display all nodes regardless of view permissions.
|
||||
*/
|
||||
public function html()
|
||||
public function html(): string
|
||||
{
|
||||
$nodeClass = $this->options['class'];
|
||||
$selectable = \is_string( $this->options['permissionCheck'] ) ? $this->options['permissionCheck'] : NULL;
|
||||
$selectable = is_string( $this->options['permissionCheck'] ) ? $this->options['permissionCheck'] : NULL;
|
||||
$showable = $this->_getShowable();
|
||||
$disabledCallback = \is_callable( $this->options['permissionCheck'] ) ? $this->options['permissionCheck'] : NULL;
|
||||
$disabledCallback = is_callable( $this->options['permissionCheck'] ) ? $this->options['permissionCheck'] : NULL;
|
||||
|
||||
if ( !$selectable and $showable and \IPS\Dispatcher::hasInstance() and \IPS\Dispatcher::i()->controllerLocation === 'front' )
|
||||
if ( !$selectable and $showable and Dispatcher::hasInstance() and Dispatcher::i()->controllerLocation === 'front' )
|
||||
{
|
||||
$selectable = 'view';
|
||||
}
|
||||
|
||||
/* Determine if we need a limit clause */
|
||||
$limit = $this->options['maxResults'] ?
|
||||
( ( isset( \IPS\Request::i()->_nodeSelectOffset ) ) ? array( (int) \IPS\Request::i()->_nodeSelectOffset, $this->options['maxResults'] ) : array( 0, $this->options['maxResults'] ) ) :
|
||||
( ( isset( Request::i()->_nodeSelectOffset ) ) ? array( (int) Request::i()->_nodeSelectOffset, $this->options['maxResults'] ) : array( 0, $this->options['maxResults'] ) ) :
|
||||
NULL;
|
||||
|
||||
/* Are we getting some AJAX stuff? */
|
||||
if ( isset( \IPS\Request::i()->_nodeSelectName ) and \IPS\Request::i()->_nodeSelectName === $this->name )
|
||||
if ( isset( Request::i()->_nodeSelectName ) and Request::i()->_nodeSelectName === $this->name )
|
||||
{
|
||||
$disabled = null;
|
||||
|
||||
if ( isset( \IPS\Request::i()->_disabled ) )
|
||||
if ( isset( Request::i()->_disabled ) )
|
||||
{
|
||||
$disabled = json_decode( \IPS\Request::i()->_disabled, true );
|
||||
$disabled = json_decode( Request::i()->_disabled, true );
|
||||
$disabled = ( $disabled === FALSE ) ? array() : $disabled;
|
||||
}
|
||||
|
||||
switch ( \IPS\Request::i()->_nodeSelect )
|
||||
switch ( Request::i()->_nodeSelect )
|
||||
{
|
||||
case 'children':
|
||||
try
|
||||
{
|
||||
$node = $showable ? $nodeClass::loadAndCheckPerms( \IPS\Request::i()->_nodeId, $showable ) : $nodeClass::load( \IPS\Request::i()->_nodeId );
|
||||
$node = $showable ? $nodeClass::loadAndCheckPerms( Request::i()->_nodeId, $showable ) : $nodeClass::load( Request::i()->_nodeId );
|
||||
|
||||
/* Note - we must check 'view' permissions here, so that the list can properly populate even if we do not have the original permission
|
||||
* - subsequent children may eventually have those permissions, so if the actual permCheck fails, add the node to the disabled list
|
||||
@@ -167,18 +188,17 @@ class _Node extends FormAbstract
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch ( Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->json( NULL, 404 );
|
||||
Output::i()->json( NULL, 404 );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->json( array( 'viewing' => $node->_id, 'title' => $node->_title, 'output' => \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->nodeCascade( $children, FALSE, $selectable, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, FALSE, NULL, $this->options['class'], $this->options['where'], $this->options['disabledIds'], NULL, array(), NULL, $this->options['togglePermPBR'], $this->options['toggleIdsOff'] ) ) );
|
||||
break;
|
||||
Output::i()->json( array( 'viewing' => $node->_id, 'title' => $node->_title, 'output' => Theme::i()->getTemplate( 'forms', 'core', 'global' )->nodeCascade( $children, FALSE, $selectable, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, FALSE, NULL, $this->options['class'], $this->options['where'], $this->options['disabledIds'], NULL, array(), NULL, $this->options['togglePermPBR'], $this->options['toggleIdsOff'] ) ) );
|
||||
|
||||
case 'parent':
|
||||
try
|
||||
{
|
||||
$node = $showable ? $nodeClass::loadAndCheckPerms( \IPS\Request::i()->_nodeId, $showable ) : $nodeClass::load( \IPS\Request::i()->_nodeId );
|
||||
$node = $showable ? $nodeClass::loadAndCheckPerms( Request::i()->_nodeId, $showable ) : $nodeClass::load( Request::i()->_nodeId );
|
||||
$parent = $node->parent();
|
||||
|
||||
$children = $parent ? $parent->children( $showable, NULL, $this->options['subnodes'], $disabled, $this->options['where'] ) : $nodeClass::roots( $showable, NULL, $this->options['where'] );
|
||||
@@ -194,29 +214,27 @@ class _Node extends FormAbstract
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
catch ( Exception $e )
|
||||
{
|
||||
\IPS\Output::i()->json( $e->getMessage(), 404 );
|
||||
Output::i()->json( $e->getMessage(), 404 );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->json( array( 'viewing' => $parent ? $parent->_id : 0, 'title' => $parent ? $parent->_title : \IPS\Member::loggedIn()->language()->addToStack( $nodeClass::$nodeTitle ), 'output' => \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->nodeCascade( $children, FALSE, $selectable, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, FALSE, NULL, $this->options['class'], $this->options['where'], $this->options['disabledIds'], NULL, array(), NULL, $this->options['togglePermPBR'], $this->options['toggleIdsOff'] ) ) );
|
||||
break;
|
||||
Output::i()->json( array( 'viewing' => $parent ? $parent->_id : 0, 'title' => $parent ? $parent->_title : Member::loggedIn()->language()->addToStack( $nodeClass::$nodeTitle ), 'output' => Theme::i()->getTemplate( 'forms', 'core', 'global' )->nodeCascade( $children, FALSE, $selectable, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, FALSE, NULL, $this->options['class'], $this->options['where'], $this->options['disabledIds'], NULL, array(), NULL, $this->options['togglePermPBR'], $this->options['toggleIdsOff'] ) ) );
|
||||
|
||||
case 'search':
|
||||
$results = array();
|
||||
|
||||
$_results = $nodeClass::search( '_title', \IPS\Request::i()->q, '_title' );
|
||||
$_results = $nodeClass::search( '_title', Request::i()->q, '_title' );
|
||||
foreach ( $_results as $node )
|
||||
{
|
||||
if ( ( !$showable or $node->can( $showable ) ) AND ! \in_array( $node->_id, $disabled ) )
|
||||
if ( ( !$showable or $node->can( $showable ) ) AND ! in_array( $node->_id, $disabled ) )
|
||||
{
|
||||
$id = ( $node instanceof $nodeClass ? $node->_id : "s.{$node->_id}" );
|
||||
$results[ $id ] = $node;
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->nodeCascade( $results, TRUE, $selectable, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, FALSE, NULL, $this->options['class'], $this->options['where'], $this->options['disabled'], NULL, array(), NULL, $this->options['togglePermPBR'], $this->options['toggleIdsOff'] ) );
|
||||
break;
|
||||
Output::i()->sendOutput( Theme::i()->getTemplate( 'forms', 'core', 'global' )->nodeCascade( $results, TRUE, $selectable, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, FALSE, NULL, $this->options['class'], $this->options['where'], $this->options['disabled'], NULL, array(), NULL, $this->options['togglePermPBR'], $this->options['toggleIdsOff'] ) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +244,7 @@ class _Node extends FormAbstract
|
||||
$noParentNodes = array();
|
||||
if( isset( $nodeClass::$ownerTypes ) and $nodeClass::$ownerTypes !== NULL and $this->options['forceOwner'] !== FALSE )
|
||||
{
|
||||
$nodes = $nodeClass::loadByOwner( $this->options['forceOwner'] ?: \IPS\Member::loggedIn(), $this->options['where'] );
|
||||
$nodes = $nodeClass::loadByOwner( $this->options['forceOwner'] ?: Member::loggedIn(), $this->options['where'] );
|
||||
if ( $this->options['clubs'] )
|
||||
{
|
||||
$nodes = array_merge( $nodes, $nodeClass::clubNodes( $showable, NULL, $this->options['where'] ) );
|
||||
@@ -248,30 +266,30 @@ class _Node extends FormAbstract
|
||||
make the control harder to use, it will have a bad performance impact. So we'll go 3 levels deep or until 300 nodes are
|
||||
showing, whichever happens first */
|
||||
$totalLimit = 300;
|
||||
$currentCount = \count( $nodes );
|
||||
$currentCount = count( $nodes );
|
||||
if ( $currentCount < $totalLimit )
|
||||
{
|
||||
foreach( $nodes AS $node )
|
||||
{
|
||||
$this->_populate( $nodes, $disabled, 0, $node, $children, 3, NULL, FALSE, $totalLimit, $currentCount );
|
||||
$this->_populate($nodes, $disabled, 0, $node, $children, 3, NULL, $totalLimit, $currentCount);
|
||||
}
|
||||
}
|
||||
if ( $this->options['noParentNodes'] )
|
||||
{
|
||||
$subnodeClass = $nodeClass::$subnodeClass;
|
||||
$noParentNodes = iterator_to_array( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', $subnodeClass::$databaseTable, $subnodeClass::$databasePrefix . $subnodeClass::$parentNodeColumnId . '=0' )->setKeyField( $subnodeClass::$databasePrefix . $subnodeClass::$databaseColumnId ), $subnodeClass ) );
|
||||
$noParentNodes = iterator_to_array( new ActiveRecordIterator( Db::i()->select( '*', $subnodeClass::$databaseTable, $subnodeClass::$databasePrefix . $subnodeClass::$parentNodeColumnId . '=0' )->setKeyField( $subnodeClass::$databasePrefix . $subnodeClass::$databaseColumnId ), $subnodeClass ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Do we need to show a "load more" link? */
|
||||
$loadMoreLink = FALSE;
|
||||
|
||||
if( $this->options['maxResults'] AND \count( $nodes ) == $this->options['maxResults'] )
|
||||
if( $this->options['maxResults'] AND count( $nodes ) == $this->options['maxResults'] )
|
||||
{
|
||||
$loadMoreLink = (int) \IPS\Request::i()->_nodeSelectOffset + $this->options['maxResults'];
|
||||
$loadMoreLink = (int) Request::i()->_nodeSelectOffset + $this->options['maxResults'];
|
||||
}
|
||||
|
||||
if ( isset( $this->options['disabled'] ) and \is_array( $this->options['disabled'] ) )
|
||||
if ( isset( $this->options['disabled'] ) and is_array( $this->options['disabled'] ) )
|
||||
{
|
||||
$this->options['url'] = $this->options['url']->setQueryString( '_disabled', json_encode( $this->options['disabled'] ) );
|
||||
|
||||
@@ -293,16 +311,16 @@ class _Node extends FormAbstract
|
||||
{
|
||||
$selected = array();
|
||||
|
||||
if ( \is_array( $this->value ) )
|
||||
if ( is_array( $this->value ) )
|
||||
{
|
||||
foreach ( $this->value as $node )
|
||||
{
|
||||
$title = isset( $node::$titleLangPrefix ) ? \IPS\Member::loggedIn()->language()->addToStack( $node::$titleLangPrefix . $node->_id, FALSE, array( 'json' => TRUE, 'escape' => TRUE, 'striptags'=> TRUE ) ) : str_replace( "'", "'", htmlspecialchars( $node->_title, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', false ) );
|
||||
$title = isset( $node::$titleLangPrefix ) ? Member::loggedIn()->language()->addToStack( $node::$titleLangPrefix . $node->_id, FALSE, array( 'json' => TRUE, 'escape' => TRUE, 'striptags'=> TRUE ) ) : str_replace( "'", "'", htmlspecialchars( $node->_title, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', false ) );
|
||||
|
||||
$selected[ !( $node instanceof $nodeClass ) ? "{$node->_id}.s" : $node->_id ] = array( 'title' => $title, 'parents' => array_values( array_map( function( $val ){
|
||||
if( isset( $val::$titleLangPrefix ) )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( $val::$titleLangPrefix . $val->_id, FALSE, array( 'json' => TRUE, 'escape' => TRUE, 'striptags'=> TRUE ) );
|
||||
return Member::loggedIn()->language()->addToStack( $val::$titleLangPrefix . $val->_id, FALSE, array( 'json' => TRUE, 'escape' => TRUE, 'striptags'=> TRUE ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -311,14 +329,14 @@ class _Node extends FormAbstract
|
||||
}, iterator_to_array( $node->parents() ) ) ) );
|
||||
}
|
||||
}
|
||||
elseif ( $this->value instanceof \IPS\Node\Model )
|
||||
elseif ( $this->value instanceof Model )
|
||||
{
|
||||
$class = \get_class( $this->value );
|
||||
$title = isset( $nodeClass::$titleLangPrefix ) ? \IPS\Member::loggedIn()->language()->addToStack( $class::$titleLangPrefix . $this->value->_id, FALSE, array( 'json' => TRUE, 'escape' => TRUE, 'striptags'=> TRUE ) ) : str_replace( "'", "'", htmlspecialchars( $this->value->_title, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', false ) );
|
||||
$class = get_class( $this->value );
|
||||
$title = isset( $nodeClass::$titleLangPrefix ) ? Member::loggedIn()->language()->addToStack( $class::$titleLangPrefix . $this->value->_id, FALSE, array( 'json' => TRUE, 'escape' => TRUE, 'striptags'=> TRUE ) ) : str_replace( "'", "'", htmlspecialchars( $this->value->_title, ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', false ) );
|
||||
$selected[ !( $this->value instanceof $nodeClass ) ? "{$this->value->_id}.s" : $this->value->_id ] = array( 'title' => $title, 'parents' => array_values( array_map( function( $val ){
|
||||
if( isset( $val::$titleLangPrefix ) )
|
||||
{
|
||||
return \IPS\Member::loggedIn()->language()->addToStack( $val::$titleLangPrefix . $val->_id, FALSE, array( 'json' => TRUE, 'escape' => TRUE, 'striptags'=> TRUE ) );
|
||||
return Member::loggedIn()->language()->addToStack( $val::$titleLangPrefix . $val->_id, FALSE, array( 'json' => TRUE, 'escape' => TRUE, 'striptags'=> TRUE ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -330,112 +348,62 @@ class _Node extends FormAbstract
|
||||
$selected = json_encode( $selected );
|
||||
}
|
||||
|
||||
/* Do we need the no-JS fallback? We only do this if we know JS is disabled as it's intensive and may cause memory exhaustion if there are lots of nodes - it's a last resort */
|
||||
$noJS = NULL;
|
||||
if ( isset( \IPS\Request::i()->_noJs ) )
|
||||
{
|
||||
$options = array();
|
||||
$_children = array();
|
||||
$disabled = ( isset( $this->options['disabled'] ) and \is_array( $this->options['disabled'] ) ) ? $this->options['disabled'] : array();
|
||||
$currentCount = NULL;
|
||||
foreach ( $nodeClass::roots( $showable, NULL, $this->options['where'] ) as $root )
|
||||
{
|
||||
$this->_populate( $options, $disabled, 0, $root, $_children, NULL, NULL, TRUE, NULL, $currentCount );
|
||||
}
|
||||
|
||||
$value = NULL;
|
||||
if ( $this->value !== 0 )
|
||||
{
|
||||
if ( $this->options['multiple'] )
|
||||
{
|
||||
$value = array();
|
||||
if ( \is_array( $this->value ) )
|
||||
{
|
||||
$value = array_keys( $this->value );
|
||||
}
|
||||
elseif ( \is_object( $this->value ) )
|
||||
{
|
||||
$value = array( $this->value->_id );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( \is_numeric( $this->value ) )
|
||||
{
|
||||
$value = $this->value;
|
||||
}
|
||||
elseif ( \is_object( $this->value ) )
|
||||
{
|
||||
$value = array( $this->value->_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$noJS = \IPS\Theme::i()->getTemplate( 'forms', 'core' )->select( $this->name . ( $this->options['multiple'] ? '[]' : '' ), $value, $this->required, $options, $this->options['multiple'], '', $disabled );
|
||||
}
|
||||
|
||||
/* Were we just loading more? */
|
||||
if( isset( \IPS\Request::i()->_nodeSelectName ) and \IPS\Request::i()->_nodeSelectName === $this->name AND isset( \IPS\Request::i()->_nodeSelect ) AND \IPS\Request::i()->_nodeSelect == 'loadMore' )
|
||||
if( isset( Request::i()->_nodeSelectName ) and Request::i()->_nodeSelectName === $this->name AND isset( Request::i()->_nodeSelect ) AND Request::i()->_nodeSelect == 'loadMore' )
|
||||
{
|
||||
if ( $this->options['clubs'] )
|
||||
{
|
||||
\IPS\Output::i()->json( array( 'loadMore' => $loadMoreLink, 'globalOutput' => \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->nodeCascade( $nodes, FALSE, $selectable, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, FALSE, NULL, $this->options['class'], $this->options['where'], $this->options['disabledIds'], NULL, array(), FALSE, $this->options['togglePermPBR'], $this->options['toggleIdsOff'] ), 'clubsOutput' => \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->nodeCascade( $nodes, FALSE, $selectable, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, FALSE, NULL, $this->options['class'], $this->options['where'], $this->options['disabledIds'], NULL, array(), TRUE, $this->options['togglePermPBR'], $this->options['toggleIdsOff'] ) ) );
|
||||
Output::i()->json( array( 'loadMore' => $loadMoreLink, 'globalOutput' => Theme::i()->getTemplate( 'forms', 'core', 'global' )->nodeCascade( $nodes, FALSE, $selectable, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, FALSE, NULL, $this->options['class'], $this->options['where'], $this->options['disabledIds'], NULL, array(), FALSE, $this->options['togglePermPBR'], $this->options['toggleIdsOff'] ), 'clubsOutput' => Theme::i()->getTemplate( 'forms', 'core', 'global' )->nodeCascade( $nodes, FALSE, $selectable, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, FALSE, NULL, $this->options['class'], $this->options['where'], $this->options['disabledIds'], NULL, array(), TRUE, $this->options['togglePermPBR'], $this->options['toggleIdsOff'] ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->json( array( 'loadMore' => $loadMoreLink, 'output' => \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->nodeCascade( $nodes, FALSE, $selectable, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, FALSE, NULL, $this->options['class'], $this->options['where'], $this->options['disabledIds'], NULL, array(), NULL, $this->options['togglePermPBR'], $this->options['toggleIdsOff'] ) ) );
|
||||
Output::i()->json( array( 'loadMore' => $loadMoreLink, 'output' => Theme::i()->getTemplate( 'forms', 'core', 'global' )->nodeCascade( $nodes, FALSE, $selectable, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, FALSE, NULL, $this->options['class'], $this->options['where'], $this->options['disabledIds'], NULL, array(), NULL, $this->options['togglePermPBR'], $this->options['toggleIdsOff'] ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Display */
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->node( $this->name, $selected, $this->options['multiple'], $this->options['url'], $nodeClass::$nodeTitle, $nodes, $this->options['zeroVal'], $noJS, $selectable, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, $this->options['zeroValTogglesOn'], $this->options['zeroValTogglesOff'], $this->options['autoPopulate'], $children, $this->options['class'], $this->options['where'], \is_array( $this->options['disabledIds'] ) ? $this->options['disabledIds'] : array(), $this->options['noParentNodes'], $noParentNodes, $this->options['clubs'], $this->options['togglePermPBR'], $this->options['toggleIdsOff'], $loadMoreLink );
|
||||
return Theme::i()->getTemplate( 'forms', 'core', 'global' )->node( $this->name, $selected, $this->options['multiple'], $this->options['url'], $nodeClass::$nodeTitle, $nodes, $this->options['zeroVal'], $selectable, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, $this->options['zeroValTogglesOn'], $this->options['zeroValTogglesOff'], $this->options['autoPopulate'], $children, $this->options['class'], $this->options['where'], is_array( $this->options['disabledIds'] ) ? $this->options['disabledIds'] : array(), $this->options['noParentNodes'], $noParentNodes, $this->options['clubs'], $this->options['togglePermPBR'], $this->options['toggleIdsOff'], $loadMoreLink );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Populate array options
|
||||
*
|
||||
* @param array $nodes The list of nodes
|
||||
* @param array|boolean $disabled Disabled options
|
||||
* @param int $depth The current depth
|
||||
* @param \IPS\Node\Model $node The node
|
||||
* @param array $children Children of the node
|
||||
* @param int|NULL $depthLimit How deep the recursion should go
|
||||
* @param \IPS\Node\Model|NULL $parent If we are recursing on a child, this should be the parent node. Otherwise NULL if in the root.
|
||||
* @param bool $noJS No-javascript fallback
|
||||
* @return void
|
||||
* @param array $nodes The list of nodes
|
||||
* @param boolean|array $disabled Disabled options
|
||||
* @param int $depth The current depth
|
||||
* @param Model|null $node The node
|
||||
* @param array $children Children of the node
|
||||
* @param int|null $depthLimit How deep the recursion should go
|
||||
* @param Model|null $parent If we are recursing on a child, this should be the parent node. Otherwise NULL if in the root.
|
||||
* @param int|null $totalLimit
|
||||
* @param int $currentCount
|
||||
* @return void
|
||||
*/
|
||||
protected function _populate( &$nodes, &$disabled, $depth, $node, &$children, $depthLimit = NULL, $parent = NULL, $noJS = FALSE, $totalLimit = NULL, &$currentCount = 0 )
|
||||
protected function _populate(array &$nodes, bool|array|null &$disabled = NULL, int $depth = 0, ?Model $node = null, array &$children = array(), int $depthLimit = NULL, Model $parent = NULL, int $totalLimit = NULL, int &$currentCount = 0 ) : void
|
||||
{
|
||||
$showable = $this->_getShowable();
|
||||
|
||||
if ( ( !$showable OR $node->can( $showable ) ) and ( empty( $this->options['disabled'] ) or !\in_array( $node->_id, $this->options['disabled'] ) ) and !$node->deleteOrMoveQueued() )
|
||||
if ( ( !$showable OR $node->can( $showable ) ) and ( empty( $this->options['disabled'] ) or !in_array( $node->_id, $this->options['disabled'] ) ) and !$node->deleteOrMoveQueued() )
|
||||
{
|
||||
if ( $noJS )
|
||||
if ( $parent === NULL )
|
||||
{
|
||||
$nodes[ $node->_id . ( !( $node instanceof $this->options['class'] ) ? '.s' : '' ) ] = str_repeat( '- ', $depth ) . $node->_title;
|
||||
$nodes[ $node->_id ] = $node;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( $parent === NULL )
|
||||
{
|
||||
$nodes[ $node->_id ] = $node;
|
||||
}
|
||||
else
|
||||
{
|
||||
$children[ $parent->_id ][ $node->_id ] = $node;
|
||||
}
|
||||
$children[ $parent->_id ][ $node->_id ] = $node;
|
||||
}
|
||||
|
||||
if ( $this->options['permissionCheck'] )
|
||||
{
|
||||
if ( \is_string( $this->options['permissionCheck'] ) )
|
||||
if ( is_string( $this->options['permissionCheck'] ) )
|
||||
{
|
||||
if ( !$node->can( $this->options['permissionCheck'] ) )
|
||||
{
|
||||
$disabled[] = $node->_id;
|
||||
}
|
||||
}
|
||||
elseif ( \is_callable( $this->options['permissionCheck'] ) )
|
||||
elseif ( is_callable( $this->options['permissionCheck'] ) )
|
||||
{
|
||||
$permissionCheck = $this->options['permissionCheck'];
|
||||
if ( !$permissionCheck( $node ) )
|
||||
@@ -445,13 +413,13 @@ class _Node extends FormAbstract
|
||||
}
|
||||
}
|
||||
|
||||
if ( $depthLimit === NULL OR $depth < (int) $depthLimit )
|
||||
if ( $depthLimit === NULL OR $depth < $depthLimit )
|
||||
{
|
||||
if ( !$totalLimit or ( ( $currentCount += $node->childrenCount( $showable, NULL, $this->options['subnodes'], $this->options['where'] ) ) < $totalLimit ) )
|
||||
{
|
||||
foreach( $node->children( $showable, NULL, $this->options['subnodes'], NULL, $this->options['where'] ) AS $child )
|
||||
{
|
||||
$this->_populate( $nodes, $disabled, $depth + 1, $child, $children, $depthLimit, $node, $noJS, $totalLimit, $currentCount );
|
||||
$this->_populate($nodes, $disabled, $depth + 1, $child, $children, $depthLimit, $node, $totalLimit, $currentCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -463,7 +431,7 @@ class _Node extends FormAbstract
|
||||
*
|
||||
* @return string|NULL
|
||||
*/
|
||||
protected function _getShowable()
|
||||
protected function _getShowable(): ?string
|
||||
{
|
||||
if( $this->options['showAllNodes'] === TRUE )
|
||||
{
|
||||
@@ -475,19 +443,19 @@ class _Node extends FormAbstract
|
||||
}
|
||||
else
|
||||
{
|
||||
return ( \IPS\Dispatcher::hasInstance() and \IPS\Dispatcher::i()->controllerLocation === 'front' ) ? 'view' : NULL;
|
||||
return ( Dispatcher::hasInstance() and Dispatcher::i()->controllerLocation === 'front' ) ? 'view' : NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Value
|
||||
*
|
||||
* @return string|int
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue()
|
||||
public function getValue(): mixed
|
||||
{
|
||||
$zeroValName = "{$this->name}-zeroVal";
|
||||
if ( $this->options['zeroVal'] !== NULL and isset( \IPS\Request::i()->$zeroValName ) )
|
||||
if ( $this->options['zeroVal'] !== NULL and isset( Request::i()->$zeroValName ) )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -500,20 +468,20 @@ class _Node extends FormAbstract
|
||||
/**
|
||||
* Format Value
|
||||
*
|
||||
* @return \IPS\Node\Model|array|NULL
|
||||
* @return mixed
|
||||
*/
|
||||
public function formatValue()
|
||||
public function formatValue(): mixed
|
||||
{
|
||||
$nodeClass = $this->options['class'];
|
||||
$selectable = $this->options['permissionCheck'];
|
||||
$showable = $this->_getShowable();
|
||||
|
||||
if ( $this->value and !( $this->value instanceof \IPS\Node\Model ) )
|
||||
if ( $this->value and !( $this->value instanceof Model ) )
|
||||
{
|
||||
$return = array();
|
||||
foreach ( \is_array( $this->value ) ? $this->value : explode( ',', $this->value ) as $v )
|
||||
foreach ( is_array( $this->value ) ? $this->value : explode( ',', $this->value ) as $v )
|
||||
{
|
||||
if ( $v instanceof \IPS\Node\Model )
|
||||
if ( $v instanceof Model )
|
||||
{
|
||||
$return[ !( $v instanceof $nodeClass ) ? "s{$v->_id}" : $v->_id ] = $v;
|
||||
}
|
||||
@@ -525,12 +493,12 @@ class _Node extends FormAbstract
|
||||
$classToUse = ( isset( $exploded[1] ) and $exploded[1] === 's' ) ? $nodeClass::$subnodeClass : $nodeClass;
|
||||
$node = $classToUse::load( $exploded[0] );
|
||||
|
||||
if ( ( !$showable or $node->can( $showable ) ) and !$selectable or ( \is_string( $selectable ) and $node->can( $selectable ) ) or ( \is_callable( $selectable ) and $selectable( $node ) ) )
|
||||
if ( ( !$showable or $node->can( $showable ) ) and !$selectable or ( is_string( $selectable ) and $node->can( $selectable ) ) or ( is_callable( $selectable ) and $selectable( $node ) ) )
|
||||
{
|
||||
$return[ isset( $exploded[1] ) ? "s{$node->_id}" : $node->_id ] = $node;
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
catch ( Exception $e ) {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -550,15 +518,15 @@ class _Node extends FormAbstract
|
||||
/**
|
||||
* Validate
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
* @return TRUE
|
||||
*/
|
||||
public function validate()
|
||||
public function validate(): bool
|
||||
{
|
||||
/* We return a NULL value instead of an empty string, so we need to check that if field is required */
|
||||
if( ( $this->value === NULL OR ( \is_array( $this->value ) AND empty( $this->value ) ) ) and $this->required )
|
||||
if( ( $this->value === NULL OR ( is_array( $this->value ) AND empty( $this->value ) ) ) and $this->required )
|
||||
{
|
||||
throw new \InvalidArgumentException('form_required');
|
||||
throw new InvalidArgumentException('form_required');
|
||||
}
|
||||
|
||||
return parent::validate();
|
||||
@@ -568,15 +536,15 @@ class _Node extends FormAbstract
|
||||
* String Value
|
||||
*
|
||||
* @param mixed $value The value
|
||||
* @return string
|
||||
* @return string|int|null
|
||||
*/
|
||||
public static function stringValue( $value )
|
||||
public static function stringValue( mixed $value ): string|int|null
|
||||
{
|
||||
if ( \is_array( $value ) )
|
||||
if ( is_array( $value ) )
|
||||
{
|
||||
return implode( ',', array_keys( $value ) );
|
||||
}
|
||||
elseif ( \is_object( $value ) )
|
||||
elseif ( is_object( $value ) )
|
||||
{
|
||||
return $value->_id;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user