Version 4.1.19
This commit is contained in:
1 parent
28bd025b35
commit
2bd5025018
2674 files changed
+233518
-77766
No files matched your search
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Chart Helper
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 12 Jul 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Dynamic Chart Helper
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 27 Aug 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -219,7 +219,10 @@ class _Dynamic extends \IPS\Helpers\Chart
|
||||
{
|
||||
$this->end = new \IPS\DateTime( \IPS\Request::i()->end[ $this->identifier ], new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) );
|
||||
}
|
||||
|
||||
|
||||
/* The end date should include items to the end of the day */
|
||||
$this->end->setTime( 23, 59, 59 );
|
||||
|
||||
$url = $url->setQueryString( 'end', array( $this->identifier => $this->end->getTimestamp() ) );
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
@@ -318,39 +321,41 @@ class _Dynamic extends \IPS\Helpers\Chart
|
||||
switch ( $this->timescale )
|
||||
{
|
||||
case 'daily':
|
||||
$data[ $date->format( 'j n Y' ) ] = array();
|
||||
$data[ $date->format( 'Y-n-j' ) ] = array();
|
||||
|
||||
if( $this->groupBy )
|
||||
{
|
||||
foreach( $this->groupByKeys as $key )
|
||||
{
|
||||
$data[ $date->format( 'j n Y' ) ][ $key ] = 0;
|
||||
$data[ $date->format( 'Y-n-j' ) ][ $key ] = 0;
|
||||
}
|
||||
}
|
||||
$date->add( new \DateInterval( 'P1D' ) );
|
||||
break;
|
||||
|
||||
case 'weekly':
|
||||
$data[ $date->format( 'W Y' ) ] = array();
|
||||
/* o is the ISO year number, which we need when years roll over.
|
||||
@see http://php.net/manual/en/function.date.php#106974 */
|
||||
$data[ $date->format( 'o-W' ) ] = array();
|
||||
|
||||
if( $this->groupBy )
|
||||
{
|
||||
foreach( $this->groupByKeys as $key )
|
||||
{
|
||||
$data[ $date->format( 'W Y' ) ][ $key ] = 0;
|
||||
$data[ $date->format( 'o-W' ) ][ $key ] = 0;
|
||||
}
|
||||
}
|
||||
$date->add( new \DateInterval( 'P7D' ) );
|
||||
break;
|
||||
|
||||
case 'monthly':
|
||||
$data[ $date->format( 'n Y' ) ] = array();
|
||||
$data[ $date->format( 'Y-n' ) ] = array();
|
||||
|
||||
if( $this->groupBy )
|
||||
{
|
||||
foreach( $this->groupByKeys as $key )
|
||||
{
|
||||
$data[ $date->format( 'n Y' ) ][ $key ] = 0;
|
||||
$data[ $date->format( 'Y-n' ) ][ $key ] = 0;
|
||||
}
|
||||
}
|
||||
$date->add( new \DateInterval( 'P1M' ) );
|
||||
@@ -365,6 +370,7 @@ class _Dynamic extends \IPS\Helpers\Chart
|
||||
{
|
||||
/* Work out where clause */
|
||||
$where = $this->where;
|
||||
$where[] = array( "{$this->dateField}>?", 0 );
|
||||
if ( $this->start )
|
||||
{
|
||||
$where[] = array( "{$this->dateField}>?", $this->start->getTimestamp() );
|
||||
@@ -378,15 +384,15 @@ class _Dynamic extends \IPS\Helpers\Chart
|
||||
switch ( $this->timescale )
|
||||
{
|
||||
case 'daily':
|
||||
$timescale = '%e %c %Y';
|
||||
$timescale = '%Y-%c-%e';
|
||||
break;
|
||||
|
||||
case 'weekly':
|
||||
$timescale = '%u %Y';
|
||||
$timescale = '%Y-%u';
|
||||
break;
|
||||
|
||||
case 'monthly':
|
||||
$timescale = '%c %Y';
|
||||
$timescale = '%Y-%c';
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -410,7 +416,7 @@ class _Dynamic extends \IPS\Helpers\Chart
|
||||
"{$key}" . ( $this->groupBy ? ", {$this->groupBy}" : '' ),
|
||||
$this->table,
|
||||
$where,
|
||||
"{$this->dateField} ASC",
|
||||
NULL,
|
||||
NULL,
|
||||
$this->groupBy
|
||||
)->setKeyField( $this->groupBy )->setValueField( $key );
|
||||
@@ -435,7 +441,7 @@ class _Dynamic extends \IPS\Helpers\Chart
|
||||
"DATE_FORMAT( FROM_UNIXTIME( IFNULL( {$this->dateField}, 0 ) ), '{$timescale}' ) AS time, " . implode( ', ', array_unique( $this->series ) ) . ( $this->groupBy ? ", " . $this->groupBy : '' ),
|
||||
$this->table,
|
||||
$where,
|
||||
"{$this->dateField} ASC",
|
||||
'time ASC',
|
||||
NULL,
|
||||
$this->groupBy ? array( 'time', $this->groupBy ) : 'time'
|
||||
);
|
||||
@@ -474,6 +480,8 @@ class _Dynamic extends \IPS\Helpers\Chart
|
||||
|
||||
$data[ $row['time'] ] = $result;
|
||||
}
|
||||
|
||||
ksort( $data, SORT_NATURAL );
|
||||
|
||||
/* Add to graph */
|
||||
$min = NULL;
|
||||
@@ -496,21 +504,21 @@ class _Dynamic extends \IPS\Helpers\Chart
|
||||
}
|
||||
|
||||
$datetime->setTime( 0, 0, 0 );
|
||||
$exploded = explode( ' ', $time );
|
||||
$exploded = explode( '-', $time );
|
||||
switch ( $this->timescale )
|
||||
{
|
||||
case 'daily':
|
||||
$datetime->setDate( $exploded[2], $exploded[1], $exploded[0] );
|
||||
$datetime->setDate( (float) $exploded[0], $exploded[1], $exploded[2] );
|
||||
//$datetime = $datetime->localeDate();
|
||||
break;
|
||||
|
||||
case 'weekly':
|
||||
$datetime->setISODate( $exploded[1], $exploded[0] );
|
||||
$datetime->setISODate( (float) $exploded[0], $exploded[1] );
|
||||
//$datetime = $datetime->localeDate();
|
||||
break;
|
||||
|
||||
case 'monthly':
|
||||
$datetime->setDate( $exploded[1], $exploded[0], 1 );
|
||||
$datetime->setDate( (float) $exploded[0], $exploded[1], 1 );
|
||||
//$datetime = $datetime->format( 'F Y' );
|
||||
break;
|
||||
}
|
||||
@@ -579,6 +587,10 @@ class _Dynamic extends \IPS\Helpers\Chart
|
||||
{
|
||||
\IPS\IPS::exceptionHandler( $e );
|
||||
}
|
||||
catch ( \Throwable $e )
|
||||
{
|
||||
\IPS\IPS::exceptionHandler( $e );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Cover Photo Controller
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 20 May 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -47,7 +47,11 @@ abstract class _Controller extends \IPS\Dispatcher\Controller
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
|
||||
$returnURL = new \IPS\Http\Url( $_SERVER['HTTP_REFERER'] );
|
||||
$returnURL = ( isset( $_SERVER['HTTP_REFERER'] ) AND $_SERVER['HTTP_REFERER'] ) ? \IPS\Http\Url::createFromString( $_SERVER['HTTP_REFERER'] ) : \IPS\Request::i()->url()->stripQueryString( 'do' );
|
||||
if ( !( $returnURL instanceof \IPS\Http\Url\Internal ) )
|
||||
{
|
||||
$returnURL = \IPS\Request::i()->url()->stripQueryString( 'do' );
|
||||
}
|
||||
$this->_coverPhotoSet( new \IPS\Helpers\CoverPhoto( $values['cover_photo'], 0 ) );
|
||||
\IPS\Output::i()->redirect( $returnURL->setQueryString( array( '_position' => 1 ) ) );
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Cover Photo Helper
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 20 May 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -62,11 +62,6 @@ class _CoverPhoto
|
||||
*/
|
||||
public function __construct( \IPS\File $file = NULL, $offset = 0, $editable = FALSE )
|
||||
{
|
||||
if( !\IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_core.js', 'core' ) );
|
||||
}
|
||||
|
||||
$this->file = $file;
|
||||
$this->offset = $offset;
|
||||
}
|
||||
@@ -78,6 +73,11 @@ class _CoverPhoto
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
if( !\IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_core.js', 'core' ) );
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->coverPhoto( $this->object->url(), $this );
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Address input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 11 Jul 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -55,7 +55,7 @@ class _Address extends FormAbstract
|
||||
}
|
||||
|
||||
/* Display */
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->address( $this->name, $this->value, \IPS\Settings::i()->googleplacesautocomplete, $this->options['minimize'] );
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->address( $this->name, $this->value, \IPS\Settings::i()->googleplacesautocomplete ? \IPS\Settings::i()->google_maps_api_key : NULL, $this->options['minimize'] );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,8 +99,8 @@ class _Address extends FormAbstract
|
||||
{
|
||||
/* Create the object */
|
||||
$input = parent::getValue();
|
||||
$value = new \IPS\GeoLocation;
|
||||
$value->addressLines = array_filter( $input['address'] );
|
||||
$value = new \IPS\GeoLocation;
|
||||
$value->addressLines = ( isset( $input['address'] ) and is_array( $input['address'] ) ) ? array_filter( $input['address'] ) : array();
|
||||
if ( empty( $value->addressLines ) )
|
||||
{
|
||||
$value->addressLines = array( NULL );
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Captcha class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Apr 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief keyCAPTCHA
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Apr 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -65,7 +65,7 @@ HTML;
|
||||
$explodedResponse = explode( '|', \IPS\Request::i()->keycaptcha );
|
||||
$explodedKey = explode( '0', \IPS\Settings::i()->keycaptcha_privatekey );
|
||||
|
||||
if( $explodedResponse[0] === md5( 'accept' . $explodedResponse[1] . $explodedKey[0] . $explodedResponse[2] ) )
|
||||
if( \IPS\Login::compareHashes( $explodedResponse[0], md5( 'accept' . $explodedResponse[1] . $explodedKey[0] . $explodedResponse[2] ) ) )
|
||||
{
|
||||
if( (string) \IPS\Http\Url::external( $explodedResponse[2] )->request()->get() === '1' )
|
||||
{
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief reCAPTCHA
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Apr 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -36,7 +36,7 @@ class _Recaptcha
|
||||
public function getHtml()
|
||||
{
|
||||
$publicKey = \IPS\Settings::i()->recaptcha_public_key;
|
||||
$theme = \IPS\Settings::i()->recaptcha_theme;
|
||||
$theme = \IPS\Theme::i()->settings['recaptcha_theme'];
|
||||
$lang = preg_replace( '/^(.+?)\..*$/', '$1', \IPS\Member::loggedIn()->language()->short );
|
||||
|
||||
return <<<HTML
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief reCAPTCHA
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 5 Dec 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -36,7 +36,7 @@ class _Recaptcha2
|
||||
public function getHtml()
|
||||
{
|
||||
$publicKey = \IPS\Settings::i()->recaptcha2_public_key;
|
||||
$theme = \IPS\Settings::i()->recaptcha2_theme;
|
||||
$theme = \IPS\Theme::i()->settings['recaptcha2_theme'];
|
||||
$lang = preg_replace( '/^(.+?)\..*$/', '$1', \IPS\Member::loggedIn()->language()->short );
|
||||
|
||||
return <<<HTML
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Checkbox class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 26 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -50,7 +50,7 @@ class _Checkbox extends FormAbstract
|
||||
{
|
||||
if ( !$this->htmlId )
|
||||
{
|
||||
$this->htmlId = md5( uniqid() );
|
||||
$this->htmlId = md5( 'ips_checkbox_' . $this->name );
|
||||
}
|
||||
|
||||
$checkboxName = preg_replace( '/^(.+?\[?.+?)(\])?$/', '$1_checkbox$2', $this->name );
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Checkbox Set class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 19 Jul 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -32,7 +32,7 @@ class _CheckboxSet extends Select
|
||||
{
|
||||
$args = func_get_args();
|
||||
$args[3]['multiple'] = TRUE;
|
||||
|
||||
|
||||
call_user_func_array( 'parent::__construct', $args );
|
||||
|
||||
if ( !isset( $this->options['descriptions'] ) )
|
||||
@@ -80,6 +80,13 @@ class _CheckboxSet extends Select
|
||||
$value = $this->value;
|
||||
}
|
||||
|
||||
/* If the value is NULL or an empty string, i.e. from a custom field, then we should not convert it into an array because the
|
||||
value will evaluate to 0 with an == check and the first option in the checkbox set will always be selected erroneously */
|
||||
if ( ! is_array( $value ) AND $value !== NULL AND $value !== '' )
|
||||
{
|
||||
$value = array( $value );
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->checkboxset( $this->name, $value, $this->required, $this->parseOptions(), $this->options['multiple'], $this->options['class'], $this->options['disabled'], $this->options['toggles'], NULL, $this->options['unlimited'], $this->options['unlimitedLang'], $this->options['unlimitedToggles'], $this->options['unlimitedToggleOn'], $descriptions );
|
||||
}
|
||||
|
||||
@@ -90,6 +97,8 @@ class _CheckboxSet extends Select
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
/* We need the array keys. For custom fields we will have 0 => 1, 1 => 1 if checkboxes 0 and 1 are checked, while for Content we will have
|
||||
customKey => 1, customOtherKey => 1 - we always need the array keys */
|
||||
$value = is_array( parent::getValue() ) ? array_keys( parent::getValue() ) : array();
|
||||
if ( $this->options['returnLabels'] )
|
||||
{
|
||||
@@ -107,6 +116,7 @@ class _CheckboxSet extends Select
|
||||
return $this->options['options'][ $value ];
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Codemirror class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 8 Jul 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Color input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 11 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Custom input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Date input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 8 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -161,7 +161,14 @@ class _Date extends FormAbstract
|
||||
public function formatValue()
|
||||
{
|
||||
$v = $this->value;
|
||||
$timezone = $this->options['timezone'] ?: ( \IPS\Member::loggedIn()->timezone ? new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) : NULL );
|
||||
try
|
||||
{
|
||||
$timezone = $this->options['timezone'] ?: ( \IPS\Member::loggedIn()->timezone ? new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) : NULL );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
$timezone = NULL;
|
||||
}
|
||||
|
||||
if ( $this->options['unlimited'] !== NULL and $v === $this->options['unlimited'] )
|
||||
{
|
||||
@@ -231,10 +238,10 @@ class _Date extends FormAbstract
|
||||
|
||||
$count = 0;
|
||||
$bits = array();
|
||||
foreach ( array( 'dd', 'mm', 'yy' ) as $k )
|
||||
foreach ( array( 'DD', 'MM', 'YY' ) as $k )
|
||||
{
|
||||
$regex = str_replace( $k, '(.+?)', preg_quote( $format, '/' ) );
|
||||
foreach ( array( 'dd', 'mm', 'yy' ) as $j )
|
||||
foreach ( array( 'DD', 'MM', 'YY' ) as $j )
|
||||
{
|
||||
if ( $k != $j )
|
||||
{
|
||||
@@ -245,7 +252,8 @@ class _Date extends FormAbstract
|
||||
$bits[ $k ] = preg_replace( "/^{$regex}$/", '$1', trim( $date ), 1, $_count );
|
||||
$count += $_count;
|
||||
}
|
||||
return ( $count == 3 ) ? "{$bits['yy']}-{$bits['mm']}-{$bits['dd']}" : $date;
|
||||
|
||||
return ( $count == 3 ) ? "{$bits['YY']}-{$bits['MM']}-{$bits['DD']}" : $date;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Date range input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -88,16 +88,23 @@ class _DateRange extends FormAbstract
|
||||
*/
|
||||
public function formatValue()
|
||||
{
|
||||
/* The start time may be offset a few hours depending on the users timezone, let's fix that now */
|
||||
$start = $this->start->formatValue();
|
||||
if ( $start instanceof \IPS\DateTime and $this->options['start']['time'] === FALSE )
|
||||
{
|
||||
$start->setTime( 00, 00, 00 );
|
||||
}
|
||||
|
||||
/* The end date needs to be 23:59:59 rather than 00:00:00 as we need to go right up to the end of the day */
|
||||
$end = $this->end->formatValue();
|
||||
if ( $end instanceof \IPS\DateTime and $this->options['end']['time'] === FALSE )
|
||||
{
|
||||
$end->setTime( 23, 59, 59 );
|
||||
}
|
||||
|
||||
|
||||
/* Return */
|
||||
return array(
|
||||
'start' => $this->start->formatValue(),
|
||||
'start' => $start,
|
||||
'end' => $end
|
||||
);
|
||||
}
|
||||
|
||||
+171
-49
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Editor class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 5 Apr 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -30,29 +30,39 @@ class _Editor extends FormAbstract
|
||||
'app' => 'core', // The application that owns this type of editor (as defined by an extension)
|
||||
'key' => 'Example', // The key for this type of editor (as defined by an extension)
|
||||
'autoSaveKey' => 'abc', // Pass a string which identifies this editor's purpose. For example, if the editor is for replying to a topic with ID 5, you could use "topic-reply-5". Make sure you pass the same key every time, but a different key for different editors.
|
||||
'attachIds' => array( // ID numbers to idenfity content for attachments if the content has been saved - the first two must be int or null, the third must be string or null. If content has not been saved yet, you must claim attachments after saving.
|
||||
'attachIds' => array( // ID numbers to identify content for attachments if the content has been saved - the first two must be int or null, the third must be string or null. If content has not been saved yet, you must claim attachments after saving.
|
||||
1,
|
||||
2,
|
||||
'foo'
|
||||
),
|
||||
'minimize' => 'clickme', // Language string to use for mimimized view. NULL will mean editor is not minimized.
|
||||
'minimize' => 'clickme', // Language string to use for minimized view. NULL will mean editor is not minimized.
|
||||
'minimizeIcon' => 'flag-us', // Icon to use for minimized view
|
||||
'allButtons' => FALSE, // Only used for the customisation ACP page. Do not use.
|
||||
'tags' => array(), // An array of extra insertable tags in key => value pair with key being what is inserted and value serving as a description
|
||||
'autoGrow' => FALSE, // Used to specify if editor should grow in size as content is added. Defaults to TRUE.
|
||||
'controller' => NULL, // Used to specify the editor controller. Defaults to NULL, which will use app=core&module=system&controller=editor
|
||||
'defaultIfNoAutoSave'=> FALSE, // If TRUE, the default value will not override any autosaved content
|
||||
'minimizeWithContent'=> FALSE, // If TRUE, the editor will be minimized even if there is default content
|
||||
'maxLength' => FALSE, // The maximum length. Note that the content is HTML, so this isn't the maximum number of visible characters, so should only be used for database limits. The database's max allowed packet will override if smaller
|
||||
'editorId' => NULL, // Passed to editorAttachments. Only necessary if the name may be changed
|
||||
);
|
||||
* @endcode
|
||||
*/
|
||||
protected $defaultOptions = array(
|
||||
'app' => NULL,
|
||||
'key' => NULL,
|
||||
'autoSaveKey' => NULL,
|
||||
'attachIds' => NULL,
|
||||
'minimize' => NULL,
|
||||
'minimizeIcon' => 'fa fa-comment-o',
|
||||
'allButtons' => FALSE,
|
||||
'tags' => array(),
|
||||
'autoGrow' => TRUE,
|
||||
'app' => NULL,
|
||||
'key' => NULL,
|
||||
'autoSaveKey' => NULL,
|
||||
'attachIds' => NULL,
|
||||
'minimize' => NULL,
|
||||
'minimizeIcon' => 'fa fa-comment-o',
|
||||
'allButtons' => FALSE,
|
||||
'tags' => array(),
|
||||
'autoGrow' => TRUE,
|
||||
'controller' => NULL,
|
||||
'defaultIfNoAutoSave' => FALSE,
|
||||
'minimizeWithContent' => FALSE,
|
||||
'maxLength' => 16777215, // The default for MEDIUMTEXT */
|
||||
'editorId' => NULL,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -75,6 +85,7 @@ class _Editor extends FormAbstract
|
||||
* Sets that the field is required if there is a minimum length and vice-versa
|
||||
*
|
||||
* @see \IPS\Helpers\Form\Abstract::__construct
|
||||
* @note $name and $htmlId must be different
|
||||
* @return void
|
||||
* @throws \OutOfBoundsException
|
||||
*/
|
||||
@@ -82,6 +93,8 @@ class _Editor extends FormAbstract
|
||||
{
|
||||
$args = func_get_args();
|
||||
$this->postKey = md5( $args[3]['autoSaveKey'] . ':' . session_id() );
|
||||
|
||||
$this->defaultOptions['controller'] = 'app=core&module=system&controller=editor';
|
||||
|
||||
/* Get our extension */
|
||||
if ( !isset( $args[3]['allButtons'] ) or !$args[3]['allButtons'] )
|
||||
@@ -95,8 +108,9 @@ class _Editor extends FormAbstract
|
||||
$this->extension = $extensions[ $args[3]['key'] ];
|
||||
}
|
||||
|
||||
/* Don't mimize if we have a value */
|
||||
if ( $args[1] or \IPS\Request::i()->$args[0] or ( isset( \IPS\Request::i()->cookie['vle_editor'] ) and \IPS\Request::i()->cookie['vle_editor'] ) )
|
||||
/* Don't minimize if we have a value */
|
||||
$name = isset( $args[3]['editorId'] ) ? $args[3]['editorId'] : $args[0];
|
||||
if ( ( !isset( $args[3]['minimizeWithContent'] ) or !$args[3]['minimizeWithContent'] ) and ( $args[1] or \IPS\Request::i()->$name or ( isset( \IPS\Request::i()->cookie['vle_editor'] ) and \IPS\Request::i()->cookie['vle_editor'] ) ) )
|
||||
{
|
||||
$args[3]['minimize'] = NULL;
|
||||
}
|
||||
@@ -105,20 +119,20 @@ class _Editor extends FormAbstract
|
||||
$this->options = array_merge( $this->defaultOptions, $args[3] );
|
||||
if ( $this->canAttach() )
|
||||
{
|
||||
if ( isset( \IPS\Request::i()->getUploader ) and \IPS\Request::i()->getUploader === $args[0] or ( isset( \IPS\Request::i()->postKey ) and \IPS\Request::i()->postKey === $this->postKey and isset( \IPS\Request::i()->deleteFile ) ) )
|
||||
if ( isset( \IPS\Request::i()->getUploader ) and \IPS\Request::i()->getUploader === $name or ( isset( \IPS\Request::i()->postKey ) and \IPS\Request::i()->postKey === $this->postKey and isset( \IPS\Request::i()->deleteFile ) ) )
|
||||
{
|
||||
if ( $uploader = $this->getUploader( $args[0]) )
|
||||
if ( $uploader = $this->getUploader( $name ) )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( $uploader->html() );
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->editorAttachmentsPlaceholder( $args[0], $this->postKey ) );
|
||||
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->editorAttachmentsPlaceholder( $name, $this->postKey ) );
|
||||
}
|
||||
}
|
||||
elseif( mb_strtolower( $_SERVER['REQUEST_METHOD'] ) == 'post' or !$this->options['minimize'] )
|
||||
{
|
||||
$this->uploader = $this->getUploader( $args[0] );
|
||||
$this->uploader = $this->getUploader( $name );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -126,8 +140,32 @@ class _Editor extends FormAbstract
|
||||
}
|
||||
}
|
||||
|
||||
/* Work out the biggest value MySQL will allow */
|
||||
if ( !isset( \IPS\Data\Store::i()->maxAllowedPacket ) )
|
||||
{
|
||||
$maxAllowedPacket = 0;
|
||||
foreach ( \IPS\Db::i()->query("SHOW VARIABLES LIKE 'max_allowed_packet'") as $row )
|
||||
{
|
||||
$maxAllowedPacket = $row['Value'];
|
||||
}
|
||||
\IPS\Data\Store::i()->maxAllowedPacket = $maxAllowedPacket;
|
||||
}
|
||||
if ( \IPS\Data\Store::i()->maxAllowedPacket )
|
||||
{
|
||||
if ( !isset( $args[3]['maxLength'] ) or $args[3]['maxLength'] > \IPS\Data\Store::i()->maxAllowedPacket )
|
||||
{
|
||||
$args[3]['maxLength'] = \IPS\Data\Store::i()->maxAllowedPacket;
|
||||
}
|
||||
}
|
||||
|
||||
/* Go */
|
||||
call_user_func_array( 'parent::__construct', $args );
|
||||
|
||||
/* Preview? */
|
||||
if ( \IPS\Request::i()->isAjax() and isset( \IPS\Request::i()->_previewField ) and \IPS\Request::i()->_previewField === $this->name )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( $this->getValue() );
|
||||
}
|
||||
|
||||
/* Include editor JS - but not if loaded via ajax. JS loader will handle that on demand */
|
||||
if( !\IPS\Request::i()->isAjax() )
|
||||
@@ -179,24 +217,36 @@ class _Editor extends FormAbstract
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Can we use HTML? */
|
||||
if ( $this->canUseHtml() === TRUE )
|
||||
{
|
||||
array_unshift( $allowed['desktop'][0]['items'], 'Source' );
|
||||
array_unshift( $allowed['tablet'][0]['items'], 'Source' );
|
||||
array_unshift( $allowed['phone'][0]['items'], 'Source' );
|
||||
if ( !empty( $allowed['desktop'][0]['items'] ) )
|
||||
{
|
||||
array_unshift( $allowed[ 'desktop' ][ 0 ][ 'items' ], 'Source' );
|
||||
}
|
||||
if ( !empty( $allowed['tablet'][0]['items'] ) )
|
||||
{
|
||||
array_unshift( $allowed[ 'tablet' ][ 0 ][ 'items' ], 'Source' );
|
||||
}
|
||||
if ( !empty( $allowed['phone'][0]['items'] ) )
|
||||
{
|
||||
array_unshift( $allowed[ 'phone' ][ 0 ][ 'items' ], 'Source' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean resources in ACP */
|
||||
$value = $this->value;
|
||||
\IPS\Output::i()->parseFileObjectUrls( $value );
|
||||
|
||||
if( \IPS\Dispatcher::hasInstance() AND \IPS\Dispatcher::i()->controllerLocation == 'admin' )
|
||||
{
|
||||
$value = \IPS\Text\Parser::mungeResources( $value );
|
||||
}
|
||||
|
||||
/* CKEditor will replace <p></p> (which doesn't display anything in a normal post) with <p><br></p> (which does)
|
||||
which creates a discrepency between wheat displays in a post and what displays in the editor */
|
||||
$value = preg_replace( '/<p>\s*<\/p>/', '', $value );
|
||||
|
||||
/* Show full uploader */
|
||||
if ( $this->uploader )
|
||||
@@ -283,13 +333,7 @@ class _Editor extends FormAbstract
|
||||
if ( $value )
|
||||
{
|
||||
$parser = $this->_getParser();
|
||||
$parsedValue = $parser->parse( $value );
|
||||
if( count( $parser->errors ) )
|
||||
{
|
||||
$error = new \DomainException( implode( '; ', array_unique( $parser->errors ) ) );
|
||||
}
|
||||
|
||||
$value = $parsedValue;
|
||||
$value = $parser->parse( $value );
|
||||
}
|
||||
|
||||
/* Add any attachments that weren't inserted in the content */
|
||||
@@ -306,7 +350,7 @@ class _Editor extends FormAbstract
|
||||
}
|
||||
else
|
||||
{
|
||||
$value .= \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->attachedFile( \IPS\Settings::i()->base_url . "applications/core/interface/file/attachment.php?id=" . $attachment['attach_id'], $attachment['attach_file'] );
|
||||
$value .= \IPS\Theme::i()->getTemplate( 'editor', 'core', 'global' )->attachedFile( \IPS\Http\Url::baseUrl( \IPS\Http\Url::PROTOCOL_RELATIVE ) . "applications/core/interface/file/attachment.php?id=" . $attachment['attach_id'], $attachment['attach_file'] );
|
||||
}
|
||||
|
||||
if ( !isset( $parser ) or !in_array( $attachment['attach_id'], $parser->mappedAttachments ) )
|
||||
@@ -322,7 +366,7 @@ class _Editor extends FormAbstract
|
||||
}
|
||||
}
|
||||
}
|
||||
if( count( $inserts ) )
|
||||
if( count( $inserts ) and !isset( \IPS\Request::i()->_previewField ) )
|
||||
{
|
||||
\IPS\Db::i()->insert( 'core_attachments_map', $inserts, TRUE );
|
||||
}
|
||||
@@ -367,7 +411,7 @@ class _Editor extends FormAbstract
|
||||
*/
|
||||
protected function _getParser()
|
||||
{
|
||||
return new \IPS\Text\Parser( TRUE, ( $this->options['attachIds'] === NULL ? md5( $this->options['autoSaveKey'] ) : $this->options['attachIds'] ), NULL, "{$this->options['app']}_{$this->options['key']}", TRUE, !$this->canUseHtml(), method_exists( $this->extension, 'htmlPurifierConfig' ) ? array( $this->extension, 'htmlPurifierConfig' ) : NULL );
|
||||
return new \IPS\Text\Parser( TRUE, ( $this->options['attachIds'] === NULL ? md5( $this->options['autoSaveKey'] ) : $this->options['attachIds'] ), NULL, "{$this->options['app']}_{$this->options['key']}", !$this->bypassFilterProfanity(), !$this->canUseHtml(), method_exists( $this->extension, 'htmlPurifierConfig' ) ? array( $this->extension, 'htmlPurifierConfig' ) : NULL );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -469,7 +513,7 @@ class _Editor extends FormAbstract
|
||||
'callback' => function( $file ) use ( $postKey )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_files_temp', array( 'contents=?', (string) $file ) );
|
||||
$attachment = $file->makeAttachment( $postKey );
|
||||
$attachment = $file->makeAttachment( $postKey, \IPS\Member::loggedIn() );
|
||||
return $attachment['attach_id'];
|
||||
}
|
||||
);
|
||||
@@ -506,22 +550,60 @@ class _Editor extends FormAbstract
|
||||
/* Handle delete calls */
|
||||
if ( isset( \IPS\Request::i()->postKey ) and \IPS\Request::i()->postKey == $this->postKey and isset( \IPS\Request::i()->deleteFile ) )
|
||||
{
|
||||
/* Get the attachment */
|
||||
try
|
||||
{
|
||||
$attachment = \IPS\Db::i()->select( '*', 'core_attachments', array( 'attach_id=?', \IPS\Request::i()->deleteFile ) )->first();
|
||||
\IPS\Db::i()->delete( 'core_attachments_map', array( array( 'location_key=?', "{$this->options['app']}_{$this->options['key']}" ), array( 'attachment_id=?', $attachment['attach_id'] ) ) );
|
||||
$otherMaps = \IPS\Db::i()->select( 'COUNT(*)', 'core_attachments_map', array( 'attachment_id=?', $attachment['attach_id'] ) )->first();
|
||||
if ( !$otherMaps )
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
\IPS\Output::i()->json( 'NO_ATTACHMENT' );
|
||||
}
|
||||
|
||||
/* Delete the maps - Only do this for attachments that have actually been saved (if they haven't been saved, there's nothing in core_attachments_map for us to delete */
|
||||
if ( isset( $this->options['attachIds'] ) and is_array( $this->options['attachIds'] ) and count( $this->options['attachIds'] ) )
|
||||
{
|
||||
$where = array( array( 'location_key=?', "{$this->options['app']}_{$this->options['key']}" ), array( 'attachment_id=?', $attachment['attach_id'] ) );
|
||||
$i = 1;
|
||||
|
||||
foreach ( $this->options['attachIds'] as $id )
|
||||
{
|
||||
$where[] = array( "id{$i}=?", $id );
|
||||
$i++;
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'core_attachments_map', $where );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If the attachment hasn't been claimed yet, it should only be deletable by the person who uploaded it */
|
||||
if( $attachment['attach_member_id'] != \IPS\Member::loggedIn()->member_id )
|
||||
{
|
||||
\IPS\Output::i()->json( 'NO_ATTACHMENT' );
|
||||
}
|
||||
}
|
||||
|
||||
/* If there's no other maps, we can delete the attachment itself */
|
||||
$otherMaps = \IPS\Db::i()->select( 'COUNT(*)', 'core_attachments_map', array( 'attachment_id=?', $attachment['attach_id'] ) )->first();
|
||||
if ( !$otherMaps )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_attachments', array( 'attach_id=?', $attachment['attach_id'] ) );
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_attachments', array( 'attach_id=?', $attachment['attach_id'] ) );
|
||||
\IPS\File::get( 'core_Attachment', $attachment['attach_location'] )->delete();
|
||||
if ( $attachment['attach_thumb_location'] )
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
if ( $attachment['attach_thumb_location'] )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\File::get( 'core_Attachment', $attachment['attach_thumb_location'] )->delete();
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
|
||||
/* Output */
|
||||
\IPS\Output::i()->json( 'OK' );
|
||||
}
|
||||
}
|
||||
@@ -546,12 +628,19 @@ class _Editor extends FormAbstract
|
||||
$emoticons = iterator_to_array( \IPS\Db::i()->select( '*', 'core_emoticons', array( 'typed<>?', '' ) )->setKeyField('typed') );
|
||||
foreach( $emoticons as $key => $emoticon )
|
||||
{
|
||||
$emoticons[ $key ] = array(
|
||||
'image' => (string) \IPS\File::get( "core_Emoticons", $emoticon['image'] )->url,
|
||||
'image_2x' => $emoticon['image_2x'] ? (string) \IPS\File::get( "core_Emoticons", $emoticon['image_2x'] )->url . ' 2x' : FALSE,
|
||||
'height' => $emoticon['height'] ?: FALSE,
|
||||
'width' => $emoticon['width'] ?: FALSE,
|
||||
);
|
||||
try
|
||||
{
|
||||
$emoticons[ $key ] = array(
|
||||
'image' => (string) \IPS\File::get( "core_Emoticons", $emoticon['image'] )->url,
|
||||
'image_2x' => ( isset( $emoticon['image_2x'] ) and $emoticon['image_2x'] ) ? (string) \IPS\File::get( "core_Emoticons", $emoticon['image_2x'] )->url . ' 2x' : FALSE,
|
||||
'height' => $emoticon['height'] ?: FALSE,
|
||||
'width' => $emoticon['width'] ?: FALSE,
|
||||
);
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\Log::log( $e, 'bad_emoticon' );
|
||||
}
|
||||
}
|
||||
|
||||
\IPS\Data\Store::i()->emoticons = $emoticons;
|
||||
@@ -605,7 +694,40 @@ class _Editor extends FormAbstract
|
||||
*/
|
||||
public static function ckeditorVersion()
|
||||
{
|
||||
preg_match( '/CKEditor\s+Included version: (.+?)\s/', file_get_contents( \IPS\ROOT_PATH . '/Credits.txt' ), $matches );
|
||||
return $matches[1];
|
||||
if ( file_exists( \IPS\ROOT_PATH . '/Credits.txt' ) )
|
||||
{
|
||||
preg_match( '#\s+Included version: (.+?)\s+?Website: http://ckeditor.com#', file_get_contents( \IPS\ROOT_PATH . '/Credits.txt' ), $matches );
|
||||
return $matches[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
return "[Could not determine the CKEditor version. Please restore Credits.txt to your suite's root directory.]";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Bypass the Profanity Check
|
||||
*/
|
||||
protected function bypassFilterProfanity()
|
||||
{
|
||||
return (bool) \IPS\Member::loggedIn()->group['g_bypass_badwords'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @return TRUE
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
parent::validate();
|
||||
|
||||
if ( $this->options['maxLength'] and \strlen( $this->value ) > $this->options['maxLength'] )
|
||||
{
|
||||
throw new \DomainException('form_maxlength_unspecific');
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Email input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 11 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -109,6 +109,16 @@ class _Form
|
||||
*/
|
||||
public $copyButton = NULL;
|
||||
|
||||
/**
|
||||
* @brief Language keys to preload for efficiency
|
||||
*/
|
||||
protected $languageKeys = array();
|
||||
|
||||
/**
|
||||
* @brief This form can be reloaded after saving
|
||||
*/
|
||||
public $canSaveAndReload = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -127,7 +137,7 @@ class _Form
|
||||
|
||||
if( $submitLang )
|
||||
{
|
||||
$this->actionButtons[] = \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->button( $submitLang, 'submit', null, 'ipsButton ipsButton_primary', array( 'accesskey' => 's' ) );
|
||||
$this->actionButtons[] = \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->button( $submitLang, 'submit', null, 'ipsButton ipsButton_primary', array( 'tabindex' => '2', 'accesskey' => 's' ) );
|
||||
}
|
||||
|
||||
$this->hiddenValues['csrfKey'] = \IPS\Session::i()->csrfKey;
|
||||
@@ -147,6 +157,12 @@ class _Form
|
||||
$potentialMaxUploadValues[] = \IPS\File::returnBytes( ini_get('memory_limit') );
|
||||
}
|
||||
$this->uploadField = min( $potentialMaxUploadValues );
|
||||
|
||||
/* This can be overridden in userland code, but by default takes the value sent by \IPS\Node\Controller::_afterSave() */
|
||||
if ( isset( \IPS\Request::i()->activeTab ) )
|
||||
{
|
||||
$this->activeTab = \IPS\Request::i()->activeTab;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,8 +272,7 @@ class _Form
|
||||
*/
|
||||
public function addMatrix( $name, $matrix )
|
||||
{
|
||||
//$matrix->manageable = FALSE;
|
||||
$matrix->id = $this->id;
|
||||
$matrix->formId = $this->id;
|
||||
$this->tabClasses[ $this->currentTab ] = 'ipsMatrix';
|
||||
$this->elements[ $this->currentTab ][ $name ] = $matrix;
|
||||
}
|
||||
@@ -327,6 +342,40 @@ class _Form
|
||||
{
|
||||
$this->hiddenValues[ $input->name ] = TRUE;
|
||||
}
|
||||
|
||||
$preloadTypes = array( 'CheckboxSet', 'Radio' );
|
||||
|
||||
/* Some form fields check for _desc and _warning so preload these */
|
||||
foreach( $preloadTypes as $type )
|
||||
{
|
||||
$class = 'IPS\Helpers\Form\\' . $type;
|
||||
|
||||
if ( is_a( $input, $class ) )
|
||||
{
|
||||
$this->languageKeys[] = $input->name . '_desc';
|
||||
$this->languageKeys[] = $input->name . '_warning';
|
||||
|
||||
if ( isset( $input->options['options'] ) and count( $input->options['options'] ) )
|
||||
{
|
||||
$this->languageKeys = array_merge( $this->languageKeys, array_map(
|
||||
function ($v )
|
||||
{
|
||||
return $v . '_desc';
|
||||
},
|
||||
array_values( $input->options['options'] )
|
||||
)
|
||||
);
|
||||
$this->languageKeys = array_merge( $this->languageKeys, array_map(
|
||||
function ($v )
|
||||
{
|
||||
return $v . '_warning';
|
||||
},
|
||||
array_values( $input->options['options'] )
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,6 +385,16 @@ class _Form
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
/* Preload languages */
|
||||
if ( count( $this->languageKeys ) and !( \IPS\Member::loggedIn()->language() instanceof \IPS\Lang\Setup\Lang ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->get( $this->languageKeys );
|
||||
}
|
||||
catch( \UnderflowException $e ) { }
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$html = array();
|
||||
@@ -357,13 +416,22 @@ class _Form
|
||||
$html[ $tab ] .= ( $element instanceof \IPS\Helpers\Form\FormAbstract ) ? $element->rowHtml( $this ) : (string) $element;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( $this->canSaveAndReload )
|
||||
{
|
||||
$this->addButton( 'save_and_reload', 'submit', null, 'ipsButton ipsButton_primary', array( 'name' => 'save_and_reload', 'value' => 1 ) );
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core' )->template( $this->id, $this->action, $html, $this->activeTab, $this->error, $errorTabs, $this->hiddenValues, $this->actionButtons, $this->uploadField, $this->sidebar, $this->tabClasses, $this->class, $this->attributes, $this->tabs, $this->iconTabs );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\IPS::exceptionHandler( $e );
|
||||
}
|
||||
catch ( \Throwable $e )
|
||||
{
|
||||
\IPS\IPS::exceptionHandler( $e );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -385,6 +453,16 @@ class _Form
|
||||
$args = array();
|
||||
}
|
||||
|
||||
/* Preload languages */
|
||||
if ( count( $this->languageKeys ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->get( $this->languageKeys );
|
||||
}
|
||||
catch( \UnderflowException $e ) { }
|
||||
}
|
||||
|
||||
$errorTabs = array();
|
||||
foreach ( $this->elements as $tab => $elements )
|
||||
{
|
||||
@@ -407,6 +485,22 @@ class _Form
|
||||
return call_user_func_array( $template, array_merge( $args, array( $this->id, $this->action, $this->elements, $this->hiddenValues, $this->actionButtons, $this->uploadField, $this->class, $this->attributes, $this->sidebar, $this, $errorTabs ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last used tab in the current form
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function getLastUsedTab()
|
||||
{
|
||||
$name = "{$this->id}_activeTab";
|
||||
if ( isset( \IPS\Request::i()->$name ) )
|
||||
{
|
||||
return \IPS\Request::i()->$name;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get submitted values
|
||||
*
|
||||
@@ -422,6 +516,66 @@ class _Form
|
||||
/* Did we submit the form? */
|
||||
if( isset( \IPS\Request::i()->$name ) and \IPS\Request::i()->csrfKey === \IPS\Session::i()->csrfKey )
|
||||
{
|
||||
/* Work out which fields are being toggled by other fields */
|
||||
$htmlIdsToIgnoreBecauseTheyAreHiddenByToggles = array();
|
||||
$htmlIdsWeWantBecauseTheyAreActivatedByToggles = array();
|
||||
foreach ( $this->elements as $elements )
|
||||
{
|
||||
foreach ( $elements as $_name => $element )
|
||||
{
|
||||
if ( isset( $element->options['togglesOn'] ) )
|
||||
{
|
||||
if ( !$element->value )
|
||||
{
|
||||
$htmlIdsToIgnoreBecauseTheyAreHiddenByToggles = array_merge( $htmlIdsToIgnoreBecauseTheyAreHiddenByToggles, $element->options['togglesOn'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$htmlIdsWeWantBecauseTheyAreActivatedByToggles = array_merge( $htmlIdsWeWantBecauseTheyAreActivatedByToggles, $element->options['togglesOn'] );
|
||||
}
|
||||
}
|
||||
if ( isset( $element->options['togglesOff'] ) )
|
||||
{
|
||||
if ( $element->value )
|
||||
{
|
||||
$htmlIdsToIgnoreBecauseTheyAreHiddenByToggles = array_merge( $htmlIdsToIgnoreBecauseTheyAreHiddenByToggles, $element->options['togglesOff'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$htmlIdsWeWantBecauseTheyAreActivatedByToggles = array_merge( $htmlIdsWeWantBecauseTheyAreActivatedByToggles, $element->options['togglesOff'] );
|
||||
}
|
||||
}
|
||||
if ( isset( $element->options['zeroValTogglesOff'] ) )
|
||||
{
|
||||
if ( $element->value === 0 )
|
||||
{
|
||||
$htmlIdsToIgnoreBecauseTheyAreHiddenByToggles = array_merge( $htmlIdsToIgnoreBecauseTheyAreHiddenByToggles, $element->options['zeroValTogglesOff'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$htmlIdsWeWantBecauseTheyAreActivatedByToggles = array_merge( $htmlIdsWeWantBecauseTheyAreActivatedByToggles, $element->options['zeroValTogglesOff'] );
|
||||
}
|
||||
}
|
||||
if ( isset( $element->options['toggles'] ) )
|
||||
{
|
||||
foreach ( $element->options['toggles'] as $toggleValue => $toggleHtmlIds )
|
||||
{
|
||||
$match = is_array( $element->value ) ? in_array( $toggleValue, $element->value ) : $toggleValue == $element->value;
|
||||
if ( !$match )
|
||||
{
|
||||
$htmlIdsToIgnoreBecauseTheyAreHiddenByToggles = array_merge( $htmlIdsToIgnoreBecauseTheyAreHiddenByToggles, $toggleHtmlIds );
|
||||
}
|
||||
else
|
||||
{
|
||||
$htmlIdsWeWantBecauseTheyAreActivatedByToggles = array_merge( $htmlIdsWeWantBecauseTheyAreActivatedByToggles, $toggleHtmlIds );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$htmlIdsToIgnore = array_diff( array_unique( $htmlIdsToIgnoreBecauseTheyAreHiddenByToggles ), array_unique( $htmlIdsWeWantBecauseTheyAreActivatedByToggles ) );
|
||||
|
||||
/* Loop elements */
|
||||
foreach ( $this->elements as $elements )
|
||||
{
|
||||
@@ -440,6 +594,14 @@ class _Form
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If this is dependant on a toggle which isn't set, don't return a value so that it doesn't
|
||||
trigger an error we cannot see */
|
||||
if ( $element->htmlId and in_array( $element->htmlId, $htmlIdsToIgnore ) )
|
||||
{
|
||||
$values[ $_name ] = $element->defaultValue;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Make sure we have a value (someone might try to be sneaky and remove the HTML from the form before submitting) */
|
||||
if ( !$element->valueSet )
|
||||
{
|
||||
@@ -519,11 +681,12 @@ class _Form
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save values to settings table
|
||||
*
|
||||
* @return bool
|
||||
* @param array|NULL $values Form Values
|
||||
* @return bool
|
||||
*/
|
||||
public function saveAsSettings( $values=NULL )
|
||||
{
|
||||
@@ -559,7 +722,7 @@ class _Form
|
||||
{
|
||||
if ( time() - \IPS\Member::loggedIn()->member_last_post < \IPS\Settings::i()->flood_control )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack('error_flood_control', FALSE, array( 'sprintf' => array( time() - \IPS\Member::loggedIn()->member_last_post ) ) ) );
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack('error_flood_control', FALSE, array( 'sprintf' => array( \IPS\Settings::i()->flood_control - ( time() - \IPS\Member::loggedIn()->member_last_post ) ) ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Abstract Class for input types for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -33,6 +33,11 @@ abstract class _FormAbstract
|
||||
*/
|
||||
public $label = NULL;
|
||||
|
||||
/**
|
||||
* @brief Description
|
||||
*/
|
||||
public $description = NULL;
|
||||
|
||||
/**
|
||||
* @brief Default Value
|
||||
*/
|
||||
@@ -163,6 +168,7 @@ abstract class _FormAbstract
|
||||
}
|
||||
catch ( \LogicException $e )
|
||||
{
|
||||
$this->valueSet = TRUE;
|
||||
$this->error = $e->getMessage();
|
||||
}
|
||||
}
|
||||
@@ -255,10 +261,18 @@ abstract class _FormAbstract
|
||||
$label = \IPS\Member::loggedIn()->language()->addToStack( $label );
|
||||
}
|
||||
}
|
||||
|
||||
$desc = $this->name . '_desc';
|
||||
$template = \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->rowDesc( $label, $this->html(), $this->appearRequired, $this->error, $this->prefix, $this->suffix, $this->htmlId ?: ( $form ? "{$form->id}_{$this->name}" : NULL ), $this, $form );
|
||||
$desc = \IPS\Member::loggedIn()->language()->addToStack( $desc, FALSE, array( 'returnBlank' => TRUE, 'htmlsprintf' => (string) $template, 'flipsprintf' => true ) );
|
||||
|
||||
$html = $this->html();
|
||||
|
||||
if ( $this->description )
|
||||
{
|
||||
$desc = $this->description;
|
||||
}
|
||||
else
|
||||
{
|
||||
$desc = $this->name . '_desc';
|
||||
$desc = \IPS\Member::loggedIn()->language()->addToStack( $desc, FALSE, array( 'returnBlank' => TRUE, 'returnInto' => \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->rowDesc( $label, $html, $this->appearRequired, $this->error, $this->prefix, $this->suffix, $this->htmlId ?: ( $form ? "{$form->id}_{$this->name}" : NULL ), $this, $form ) ) );
|
||||
}
|
||||
|
||||
if ( $this->warningBox )
|
||||
{
|
||||
@@ -267,15 +281,11 @@ abstract class _FormAbstract
|
||||
else
|
||||
{
|
||||
$warning = $this->name . '_warning';
|
||||
$template = \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->rowWarning( $label, $this->html(), $this->appearRequired, $this->error, $this->prefix, $this->suffix, $this->htmlId ?: ( $form ? "{$form->id}_{$this->name}" : NULL ), $this, $form );
|
||||
$warning = \IPS\Member::loggedIn()->language()->addToStack( $warning, FALSE, array( 'returnBlank' => TRUE, 'htmlsprintf' => (string) $template, 'flipsprintf' => true ) );
|
||||
$warning = \IPS\Member::loggedIn()->language()->addToStack( $warning, FALSE, array( 'returnBlank' => TRUE, 'returnInto' => \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->rowWarning( $label, $html, $this->appearRequired, $this->error, $this->prefix, $this->suffix, $this->htmlId ?: ( $form ? "{$form->id}_{$this->name}" : NULL ), $this, $form ) ) );
|
||||
}
|
||||
|
||||
/* Some form helpers might want to allow nested and outer suffixes */
|
||||
$html = $this->html();
|
||||
|
||||
if( array_key_exists( 'endSuffix', $this->options ) and ! empty( $this->options['endSuffix'] ) )
|
||||
{
|
||||
if( array_key_exists( 'endSuffix', $this->options ) )
|
||||
{
|
||||
$this->suffix = $this->options['endSuffix'];
|
||||
}
|
||||
|
||||
@@ -347,7 +357,7 @@ abstract class _FormAbstract
|
||||
{
|
||||
if ( !static::utf8mb4Check( $this->value ) )
|
||||
{
|
||||
throw new \DomainException( 'form_multibyte_unicode' );
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->isAdmin() ? 'form_multibyte_unicode_admin' : 'form_multibyte_unicode' );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+57
-21
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief FTP Details input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @subpackage Nexus
|
||||
* @since 17 Apr 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
@@ -27,12 +27,16 @@ class _Ftp extends \IPS\Helpers\Form\FormAbstract
|
||||
/**
|
||||
* @brief Default Options
|
||||
* @code
|
||||
'validate' => TRUE // Should details be validated?
|
||||
'validate' => TRUE, // Should details be validated?
|
||||
'allowBypassValidation' => TRUE, // If TRUE, the user will be allowed to use value even if the validation fails
|
||||
'rejectUnsupportedSftp' => FALSE, // If SFTP deatils are provided, but the server doesn't support it, should validation fail?
|
||||
);
|
||||
* @endcode
|
||||
*/
|
||||
protected $defaultOptions = array(
|
||||
'validate' => TRUE,
|
||||
'validate' => TRUE,
|
||||
'allowBypassValidation' => FALSE,
|
||||
'rejectUnsupportedSftp' => FALSE,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -44,7 +48,29 @@ class _Ftp extends \IPS\Helpers\Form\FormAbstract
|
||||
{
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'global_forms.js', 'nexus', 'global' ) );
|
||||
$value = is_array( $this->value ) ? $this->value : json_decode( \IPS\Text\Encrypt::fromTag( $this->value )->decrypt(), TRUE );
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->ftp( $this->name, $value );
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->ftp( $this->name, $value, $this->options['allowBypassValidation'] and $this->error );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate
|
||||
*
|
||||
* @param array $value The value
|
||||
* @return \IPS\Ftp
|
||||
*/
|
||||
public static function connectFromValue( $value )
|
||||
{
|
||||
if ( $value['protocol'] == 'sftp' )
|
||||
{
|
||||
$ftp = new \IPS\Ftp\Sftp( $value['server'], $value['un'], $value['pw'], $value['port'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$ftp = new \IPS\Ftp( $value['server'], $value['un'], $value['pw'], $value['port'], ( $value['protocol'] == 'ssl_ftp' ), 3 );
|
||||
}
|
||||
|
||||
$ftp->chdir( $value['path'] );
|
||||
|
||||
return $ftp;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,33 +80,43 @@ class _Ftp extends \IPS\Helpers\Form\FormAbstract
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
/* Do we have a value? */
|
||||
if ( $this->value['server'] or $this->value['un'] or $this->value['pw'] )
|
||||
{
|
||||
if ( $this->options['validate'] )
|
||||
/* And is it different to what it was originally, or do we need to establish the connection for custom validation? */
|
||||
$defaultValue = is_array( $this->defaultValue ) ? $this->defaultValue : json_decode( \IPS\Text\Encrypt::fromTag( $this->defaultValue )->decrypt(), TRUE );
|
||||
if ( $defaultValue['protocol'] != $this->value['protocol'] or $defaultValue['server'] != $this->value['server'] or $defaultValue['port'] != $this->value['port'] or $defaultValue['un'] != $this->value['un'] or $defaultValue['pw'] != $this->value['pw'] or $defaultValue['path'] != $this->value['path'] or $this->customValidationCode !== NULL )
|
||||
{
|
||||
try
|
||||
/* And are we supposed to be validating? */
|
||||
if ( $this->options['validate'] and ( !$this->options['allowBypassValidation'] or !isset( $this->value['bypassValidation'] ) ) )
|
||||
{
|
||||
if ( $this->value['protocol'] == 'sftp' )
|
||||
/* Do normal validation */
|
||||
try
|
||||
{
|
||||
$ftp = new \IPS\Ftp\Sftp( $this->value['server'], $this->value['un'], $this->value['pw'], $this->value['port'] );
|
||||
$ftp = static::connectFromValue( $this->value );
|
||||
}
|
||||
else
|
||||
catch ( \IPS\Ftp\Exception $e )
|
||||
{
|
||||
$ftp = new \IPS\Ftp( $this->value['server'], $this->value['un'], $this->value['pw'], $this->value['port'], ( $this->value['protocol'] == 'ssl_ftp' ) );
|
||||
throw new \DomainException( 'ftp_err-' . $e->getMessage() );
|
||||
}
|
||||
catch ( \BadMethodCallException $e )
|
||||
{
|
||||
// This means we tried an SFTP connection, but the server doesn't support it. We'll have to assume it's correct unless we've specifically set not to
|
||||
if ( $this->options['rejectUnsupportedSftp'] )
|
||||
{
|
||||
throw new \DomainException( 'ftp_err_no_sftp' );
|
||||
}
|
||||
}
|
||||
|
||||
$ftp->chdir( $this->value['path'] );
|
||||
}
|
||||
catch ( \IPS\Ftp\Exception $e )
|
||||
{
|
||||
throw new \DomainException( 'ftp_err-' . $e->getMessage() );
|
||||
}
|
||||
catch ( \BadMethodCallException $e )
|
||||
{
|
||||
// This means we tried an SFTP connection, but the server doesn't support it. We'll have to assume it's correct
|
||||
}
|
||||
}
|
||||
|
||||
/* Do any custom validation */
|
||||
if( $this->customValidationCode !== NULL )
|
||||
{
|
||||
call_user_func( $this->customValidationCode, $ftp );
|
||||
}
|
||||
}
|
||||
/* If not, should we? */
|
||||
elseif ( $this->required )
|
||||
{
|
||||
throw new \DomainException( 'form_required' );
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Item selector for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 12 Apr 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -82,12 +82,12 @@ class _Item extends FormAbstract
|
||||
{
|
||||
$results = array();
|
||||
$class = $this->options['class'];
|
||||
$field = $class::$databasePrefix . $class::$databaseColumnMap['title'];
|
||||
$field = $class::$databaseTable . '.' . $class::$databasePrefix . $class::$databaseColumnMap['title'];
|
||||
$where = array( array( $field . " LIKE CONCAT('%', ?, '%')", \IPS\Request::i()->q ) );
|
||||
$idField = $class::$databaseColumnId;
|
||||
if ( isset( $class::$databaseColumnMap['container'] ) and is_array( $this->options['containerIds'] ) and count( $this->options['containerIds'] ) )
|
||||
{
|
||||
$where[] = array( \IPS\Db::i()->in( $class::$databasePrefix . $class::$databaseColumnMap['container'], $this->options['containerIds'] ) );
|
||||
$where[] = array( \IPS\Db::i()->in( $class::$databaseTable . '.' . $class::$databasePrefix . $class::$databaseColumnMap['container'], $this->options['containerIds'] ) );
|
||||
}
|
||||
|
||||
if ( isset( $this->options['where'] ) and count( $this->options['where'] ) )
|
||||
@@ -130,14 +130,14 @@ class _Item extends FormAbstract
|
||||
/**
|
||||
* Format Value
|
||||
*
|
||||
* @return \IPS\Node\Model|array|NULL
|
||||
* @return array|NULL
|
||||
*/
|
||||
public function formatValue()
|
||||
{
|
||||
$itemClass = $this->options['class'];
|
||||
$order = NULL;
|
||||
$items = array();
|
||||
|
||||
$idField = $itemClass::$databaseColumnId;
|
||||
if ( ! $this->value )
|
||||
{
|
||||
$this->value = array();
|
||||
@@ -157,10 +157,10 @@ class _Item extends FormAbstract
|
||||
}
|
||||
}
|
||||
|
||||
$where = array( \IPS\Db::i()->in( $itemClass::$databaseColumnId, $this->value ) );
|
||||
$where = array( \IPS\Db::i()->in( $itemClass::$databaseTable . '.' . $itemClass::$databasePrefix . $itemClass::$databaseColumnId, $this->value ) );
|
||||
foreach( $itemClass::getItemsWithPermission( array( $where ), $order, NULL, $this->options['permissionCheck'] ) as $item )
|
||||
{
|
||||
$items[ $item->_id ] = $item;
|
||||
$items[ $item->$idField ] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,4 +187,19 @@ class _Item extends FormAbstract
|
||||
}
|
||||
return (string) $value;
|
||||
}
|
||||
/**
|
||||
* Validate
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @return TRUE
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
if( empty( $this->value ) and $this->required )
|
||||
{
|
||||
throw new \InvalidArgumentException('form_required');
|
||||
}
|
||||
|
||||
parent::validate();
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Key/Value input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Matrix Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 26 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -83,6 +83,11 @@ class _Matrix extends \IPS\Helpers\Form
|
||||
* @brief Manageable? (Rows can be added and deleted)
|
||||
*/
|
||||
public $manageable = TRUE;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* @brief Added rows
|
||||
@@ -116,6 +121,11 @@ class _Matrix extends \IPS\Helpers\Form
|
||||
* @brief Show tooltips in each cell?
|
||||
*/
|
||||
public $showTooltips = FALSE;
|
||||
|
||||
/**
|
||||
* @brief Form Id, Set it Matrix is part of a form
|
||||
*/
|
||||
public $formId = NULL;
|
||||
|
||||
/**
|
||||
* Get HTML
|
||||
@@ -126,12 +136,16 @@ 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 );
|
||||
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 );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\IPS::exceptionHandler( $e );
|
||||
}
|
||||
catch ( \Throwable $e )
|
||||
{
|
||||
\IPS\IPS::exceptionHandler( $e );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,7 +155,7 @@ class _Matrix extends \IPS\Helpers\Form
|
||||
*/
|
||||
public function nested()
|
||||
{
|
||||
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 );
|
||||
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 );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -171,21 +185,22 @@ class _Matrix extends \IPS\Helpers\Form
|
||||
* @return array
|
||||
*/
|
||||
public function elements( $getValues=TRUE )
|
||||
{
|
||||
{
|
||||
if ( $this->elements === NULL )
|
||||
{
|
||||
/* Stuff about our form */
|
||||
$name = "{$this->id}_submitted";
|
||||
$formName = $this->formId ? "{$this->formId}_submitted" : NULL;
|
||||
$matrixName = "{$this->id}_matrixRows";
|
||||
$matrixValues = \IPS\Request::i()->$matrixName;
|
||||
|
||||
|
||||
/* Loop our defined rows */
|
||||
$this->elements = array();
|
||||
$this->elements = array();
|
||||
foreach ( $this->rows as $rowId => $data )
|
||||
{
|
||||
/* Have we deleted this row? */
|
||||
$deleteKey = "{$rowId}_delete";
|
||||
if ( $this->manageable and isset( \IPS\Request::i()->$name ) and ( isset( \IPS\Request::i()->$deleteKey ) or !isset( $matrixValues[ $rowId ] ) or !$matrixValues[ $rowId ] ) )
|
||||
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 ] ) )
|
||||
{
|
||||
$this->removedRows[] = $rowId;
|
||||
continue;
|
||||
@@ -300,6 +315,25 @@ class _Matrix extends \IPS\Helpers\Form
|
||||
$name = "{$this->id}_submitted";
|
||||
if( $force or ( isset( \IPS\Request::i()->$name ) and \IPS\Request::i()->csrfKey === \IPS\Session::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 ( isset( \IPS\Request::i()->$squashedField ) )
|
||||
{
|
||||
$unsquashed = json_decode( \IPS\Request::i()->$squashedField, TRUE );
|
||||
|
||||
foreach( $unsquashed as $key => $value )
|
||||
{
|
||||
\IPS\Request::i()->$key = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $this->elements( FALSE ) as $rowId => $columns )
|
||||
{
|
||||
if ( is_array( $columns ) )
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Member input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 11 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -50,6 +50,7 @@ class _Member extends Text
|
||||
$this->defaultOptions['autocomplete'] = array(
|
||||
'source' => 'app=core&module=system&controller=ajax&do=findMember',
|
||||
'resultItemTemplate' => 'core.autocomplete.memberItem',
|
||||
'commaTrigger' => false,
|
||||
'unique' => true,
|
||||
'minAjaxLength' => 3,
|
||||
'disallowedCharacters' => array()
|
||||
@@ -81,7 +82,7 @@ class _Member extends Text
|
||||
{
|
||||
$value[] = ( $v instanceof \IPS\Member ) ? $v->name : $v;
|
||||
}
|
||||
$value = implode( ',', $value );
|
||||
$value = implode( "\n", $value );
|
||||
}
|
||||
elseif ( $value instanceof \IPS\Member )
|
||||
{
|
||||
@@ -90,7 +91,7 @@ class _Member extends Text
|
||||
|
||||
/* 10/19/15 - adding htmlspecialchars around value if autocomplete is enabled so that html tag characters can be used (e.g. for members) */
|
||||
/* This value is decoded by the JS widget before use. See https://community.invisionpower.com/4bugtrack/active-reports/cannot-pm-certain-members-r6181/ */
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->text( $this->name, 'text', ( $this->options['autocomplete'] ? htmlspecialchars( $value, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ) : $value ), $this->required, $this->options['maxLength'], $this->options['size'], $this->options['disabled'], $this->options['autocomplete'], $this->options['placeholder'], NULL, NULL );
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->text( $this->name, 'text', ( $this->options['autocomplete'] AND !is_null( $value ) ) ? htmlspecialchars( $value, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE ) : $value, $this->required, $this->options['maxLength'], $this->options['size'], $this->options['disabled'], $this->options['autocomplete'], $this->options['placeholder'], NULL, $this->options['nullLang'] );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,18 +101,20 @@ class _Member extends Text
|
||||
*/
|
||||
public function formatValue()
|
||||
{
|
||||
if ( $this->value and !( $this->value instanceof \IPS\Member ) )
|
||||
if ( $this->value !== '' and !( $this->value instanceof \IPS\Member ) )
|
||||
{
|
||||
$return = array();
|
||||
|
||||
foreach ( is_array( $this->value ) ? $this->value : explode( ',', $this->value ) as $v )
|
||||
foreach ( is_array( $this->value ) ? $this->value : explode( "\n", $this->value ) as $v )
|
||||
{
|
||||
if ( $v instanceof \IPS\Member )
|
||||
{
|
||||
$return[ $v->member_id ] = $v;
|
||||
}
|
||||
elseif( $v )
|
||||
elseif( $v !== '' )
|
||||
{
|
||||
$v = html_entity_decode( $v, ENT_QUOTES, 'UTF-8' );
|
||||
|
||||
$member = \IPS\Member::load( $v, 'name' );
|
||||
if ( $member->member_id )
|
||||
{
|
||||
@@ -160,7 +163,7 @@ class _Member extends Text
|
||||
{
|
||||
if ( is_array( $value ) )
|
||||
{
|
||||
return implode( ',', array_map( function( $v )
|
||||
return implode( "\n", array_map( function( $v )
|
||||
{
|
||||
return $v->member_id;
|
||||
}, $value ) );
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Number input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 12 Apr 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -41,6 +41,7 @@ class _Node extends FormAbstract
|
||||
'where' => array(), // where clause to control which results to display
|
||||
'disabledIds' => array(), // Array of disabled IDs
|
||||
'noParentNodes' => 'Custom' // If a value is provided, subnodes of this class which have no parent node will be added into a pseudo-group with the title provided. e.g. custom packages in Nexus do not belong to any package group
|
||||
'autoPopulate' => FALSE // Whether or not to autopopulate children of root nodes (defaults to TRUE which means the children are loaded, use FALSE to only show the parent nodes by default until they are clicked on)
|
||||
);
|
||||
* @endcode
|
||||
*/
|
||||
@@ -58,7 +59,8 @@ class _Node extends FormAbstract
|
||||
'forceOwner' => NULL,
|
||||
'where' => array(),
|
||||
'disabledIds' => array(),
|
||||
'noParentNodes' => NULL
|
||||
'noParentNodes' => NULL,
|
||||
'autoPopulate' => TRUE
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -88,6 +90,11 @@ class _Node extends FormAbstract
|
||||
$permCheck = is_string( $this->options['permissionCheck'] ) ? $this->options['permissionCheck'] : NULL;
|
||||
$disabledCallback = is_callable( $this->options['permissionCheck'] ) ? $this->options['permissionCheck'] : NULL;
|
||||
|
||||
if ( !$permCheck and \IPS\Dispatcher::hasInstance() and \IPS\Dispatcher::i()->controllerLocation === 'front' )
|
||||
{
|
||||
$permCheck = 'view';
|
||||
}
|
||||
|
||||
/* Are we getting some AJAX stuff? */
|
||||
if ( isset( \IPS\Request::i()->_nodeSelectName ) and \IPS\Request::i()->_nodeSelectName === $this->name )
|
||||
{
|
||||
@@ -104,25 +111,24 @@ class _Node extends FormAbstract
|
||||
case 'children':
|
||||
try
|
||||
{
|
||||
$node = $nodeClass::load( \IPS\Request::i()->_nodeId );
|
||||
|
||||
$children = $node->children( NULL, NULL, $this->options['subnodes'], $disabled, $this->options['where'] );
|
||||
$node = $permCheck ? $nodeClass::loadAndCheckPerms( \IPS\Request::i()->_nodeId, 'view' ) : $nodeClass::load( \IPS\Request::i()->_nodeId );
|
||||
$children = $node->children( $permCheck, NULL, $this->options['subnodes'], $disabled, $this->options['where'] );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
\IPS\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, $permCheck, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, FALSE, NULL, $this->options['class'], $this->options['where'], $this->options['disabledIds'] ) ) );
|
||||
break;
|
||||
|
||||
case 'parent':
|
||||
try
|
||||
{
|
||||
$node = $nodeClass::load( \IPS\Request::i()->_nodeId );
|
||||
$node = $permCheck ? $nodeClass::loadAndCheckPerms( \IPS\Request::i()->_nodeId, 'view' ) : $nodeClass::load( \IPS\Request::i()->_nodeId );
|
||||
$parent = $node->parent();
|
||||
|
||||
$children = $parent ? $parent->children( NULL, NULL, $this->options['subnodes'], $disabled, $this->options['where'] ) : $nodeClass::roots( NULL, NULL, $this->options['where'] );
|
||||
$children = $parent ? $parent->children( $permCheck, NULL, $this->options['subnodes'], $disabled, $this->options['where'] ) : $nodeClass::roots( NULL, NULL, $this->options['where'] );
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
{
|
||||
@@ -161,7 +167,7 @@ class _Node extends FormAbstract
|
||||
else
|
||||
{
|
||||
/* Recurse three levels in to allow for discoverability */
|
||||
foreach( $nodeClass::roots( NULL, NULL, $this->options['where'] ) AS $node )
|
||||
foreach( $nodeClass::roots( $permCheck, NULL, $this->options['where'] ) AS $node )
|
||||
{
|
||||
$this->_populate( $nodes, $disabled, 0, $node, $children, 3 );
|
||||
}
|
||||
@@ -198,18 +204,18 @@ class _Node extends FormAbstract
|
||||
{
|
||||
foreach ( $this->value as $node )
|
||||
{
|
||||
$title = isset( $node::$titleLangPrefix ) ? \IPS\Member::loggedIn()->language()->addToStack( $node::$titleLangPrefix . $node->_id, FALSE, array( 'json' => TRUE, 'escape' => TRUE ) ) : $node->_title;
|
||||
$title = isset( $node::$titleLangPrefix ) ? \IPS\Member::loggedIn()->language()->addToStack( $node::$titleLangPrefix . $node->_id, FALSE, array( 'json' => TRUE, 'escape' => TRUE, 'striptags'=> TRUE ) ) : ( $node->_stripTagsTitle ? $node->_stripTagsTitle : $node->_title );
|
||||
$selected[ !( $node instanceof $nodeClass ) ? "{$node->_id}.s" : $node->_id ] = array( 'title' => $title, 'parents' => array_values( array_map( function( $val ){
|
||||
return isset( $val::$titleLangPrefix ) ? \IPS\Member::loggedIn()->language()->addToStack( $val::$titleLangPrefix . $val->_id, FALSE, array( 'json' => TRUE, 'escape' => TRUE ) ) : $val->_title;
|
||||
return isset( $val::$titleLangPrefix ) ? \IPS\Member::loggedIn()->language()->addToStack( $val::$titleLangPrefix . $val->_id, FALSE, array( 'json' => TRUE, 'escape' => TRUE, 'striptags'=> TRUE ) ) : ( $val->_stripTagsTitle ? $val->_stripTagsTitle : $val->_title );
|
||||
}, iterator_to_array( $node->parents() ) ) ) );
|
||||
}
|
||||
}
|
||||
elseif ( $this->value instanceof \IPS\Node\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 ) ) : $this->value->_title;
|
||||
$title = isset( $nodeClass::$titleLangPrefix ) ? \IPS\Member::loggedIn()->language()->addToStack( $class::$titleLangPrefix . $this->value->_id, FALSE, array( 'json' => TRUE, 'escape' => TRUE, 'striptags'=> TRUE ) ) : ( $this->value->_stripTagsTitle ? $this->value->_stripTagsTitle : $this->value->_title );
|
||||
$selected[ !( $this->value instanceof $nodeClass ) ? "{$this->value->_id}.s" : $this->value->_id ] = array( 'title' => $title, 'parents' => array_values( array_map( function( $val ){
|
||||
return isset( $val::$titleLangPrefix ) ? \IPS\Member::loggedIn()->language()->addToStack( $val::$titleLangPrefix . $val->_id, FALSE, array( 'json' => TRUE, 'escape' => TRUE ) ) : $val->_title;
|
||||
return isset( $val::$titleLangPrefix ) ? \IPS\Member::loggedIn()->language()->addToStack( $val::$titleLangPrefix . $val->_id, FALSE, array( 'json' => TRUE, 'escape' => TRUE, 'striptags'=> TRUE ) ) : ( $val->_stripTagsTitle ? $val->_stripTagsTitle : $val->_title );
|
||||
}, iterator_to_array( $this->value->parents() ) ) ) );
|
||||
}
|
||||
|
||||
@@ -260,14 +266,14 @@ class _Node extends FormAbstract
|
||||
}
|
||||
|
||||
/* 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, $permCheck, $this->options['subnodes'], $this->options['togglePerm'], $this->options['toggleIds'], $disabledCallback, $this->options['zeroValTogglesOn'], $this->options['zeroValTogglesOff'], TRUE, $children, $this->options['class'], $this->options['where'], is_array( $this->options['disabledIds'] ) ? $this->options['disabledIds'] : array(), $this->options['noParentNodes'], $noParentNodes );
|
||||
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, $permCheck, $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 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate array options
|
||||
*
|
||||
* @param array $options The list of nodes
|
||||
* @param array $disabled Disabled options
|
||||
* @param array|boolean $disabled Disabled options
|
||||
* @param int $depth The current depth
|
||||
* @param \IPS\Node\Model $node The node
|
||||
* @param int|NULL $depthLimit How deep the recursion should go
|
||||
@@ -276,7 +282,7 @@ class _Node extends FormAbstract
|
||||
*/
|
||||
protected function _populate( &$nodes, &$disabled, $depth, $node, &$children, $depthLimit = NULL, $parent = NULL, $noJS = FALSE )
|
||||
{
|
||||
if ( !$this->options['permissionCheck'] OR $node->can('view') )
|
||||
if ( ( !$this->options['permissionCheck'] OR $node->can('view') ) and ( empty( $this->options['disabled'] ) or !in_array( $node->_id, $this->options['disabled'] ) ) and !$node->deleteOrMoveQueued() )
|
||||
{
|
||||
if ( $noJS )
|
||||
{
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Number input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -79,7 +79,7 @@ class _Number extends FormAbstract
|
||||
|
||||
/* Work out the step */
|
||||
$args = func_get_args();
|
||||
if ( !isset( $options['base'] ) and isset( $options['decimals'] ) )
|
||||
if ( !isset( $options['step'] ) and isset( $options['decimals'] ) )
|
||||
{
|
||||
if ( $options['decimals'] === TRUE )
|
||||
{
|
||||
@@ -95,6 +95,11 @@ class _Number extends FormAbstract
|
||||
call_user_func_array( 'parent::__construct', $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated HTML store
|
||||
*/
|
||||
protected static $generatedHtml = array();
|
||||
|
||||
/**
|
||||
* Get HTML
|
||||
*
|
||||
@@ -103,7 +108,13 @@ class _Number extends FormAbstract
|
||||
public function html()
|
||||
{
|
||||
/* Display */
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->number( $this->name, $this->value, $this->required, $this->options['unlimited'], $this->options['range'], $this->options['min'], $this->options['max'], $this->options['step'], $this->options['decimals'], $this->options['unlimitedLang'], $this->options['disabled'], $this->suffix, $this->options['unlimitedToggles'], $this->options['unlimitedToggleOn'], $this->options['valueToggles'] );
|
||||
if ( ! isset( static::$generatedHtml[ $this->_name ] ) )
|
||||
{
|
||||
static::$generatedHtml[ $this->_name ] = \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->number( $this->name, $this->value, $this->required, $this->options['unlimited'], $this->options['range'], $this->options['min'], $this->options['max'], $this->options['step'], $this->options['decimals'], $this->options['unlimitedLang'], $this->options['disabled'], $this->suffix, $this->options['unlimitedToggles'], $this->options['unlimitedToggleOn'], $this->options['valueToggles'] );
|
||||
}
|
||||
|
||||
/* Because we mess around with suffixes in the Number field, we store the HTML here otherwise when it is regenerated, the suffix is missing */
|
||||
return static::$generatedHtml[ $this->_name ];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,10 +178,13 @@ class _Number extends FormAbstract
|
||||
return $value;
|
||||
}
|
||||
|
||||
/* Convert decimal point and thousand separators to a way PHP understand */
|
||||
$value = str_replace( trim( \IPS\Member::loggedIn()->language()->locale['thousands_sep'] ), '', $value );
|
||||
/* Browsers *might* send in a normal "10.00" format, or because they like to keep us on our
|
||||
toes, they might send in a locale-specific "10,00" format. We convert the decimal point
|
||||
of the locale to . in an attempt to get us to the former from the latter, but we don't
|
||||
do the thousand seperator in case what we received was the former alredy, which would turn
|
||||
for example "10,00" into "1000" */
|
||||
$value = str_replace( trim( \IPS\Member::loggedIn()->language()->locale['decimal_point'] ), '.', $value );
|
||||
|
||||
|
||||
/* If it's not numeric, throw an exception */
|
||||
if ( ( !is_numeric( $value ) and $value !== '' and $this->required === FALSE ) or ( !is_numeric( $value ) and $this->required === TRUE ) )
|
||||
{
|
||||
@@ -204,7 +218,7 @@ class _Number extends FormAbstract
|
||||
public function validate()
|
||||
{
|
||||
parent::validate();
|
||||
|
||||
|
||||
if ( $this->options['unlimited'] === NULL or $this->value !== $this->options['unlimited'] )
|
||||
{
|
||||
if ( $this->options['min'] !== NULL and $this->value < $this->options['min'] )
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Number range input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @since 11 Jul 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\Helpers\Form;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number range input class for Form Builder
|
||||
*/
|
||||
class _NumberRange extends FormAbstract
|
||||
{
|
||||
/**
|
||||
* @brief Default Options
|
||||
* @see \IPS\Helpers\Form\Number::$defaultOptions
|
||||
* @code
|
||||
$defaultOptions = array(
|
||||
'start' => array( ... ),
|
||||
'end' => array( ... ),
|
||||
);
|
||||
* @endcode
|
||||
*/
|
||||
protected $defaultOptions = array(
|
||||
'start' => array(
|
||||
'min' => NULL,
|
||||
'max' => NULL,
|
||||
'disabled' => FALSE,
|
||||
'unlimited' => NULL,
|
||||
'unlimitedLang' => 'any',
|
||||
'unlimitedToggles' => array(),
|
||||
'unlimitedToggleOn' => TRUE,
|
||||
),
|
||||
'end' => array(
|
||||
'min' => NULL,
|
||||
'max' => NULL,
|
||||
'disabled' => FALSE,
|
||||
'unlimited' => NULL,
|
||||
'unlimitedLang' => 'any',
|
||||
'unlimitedToggles' => array(),
|
||||
'unlimitedToggleOn' => TRUE,
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Start Number Object
|
||||
*/
|
||||
public $start = NULL;
|
||||
|
||||
/**
|
||||
* @brief End Number Object
|
||||
*/
|
||||
public $end = NULL;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* Creates the two number objects
|
||||
*
|
||||
* @see \IPS\Helpers\Form\Abstract::__construct
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $name, $defaultValue=NULL, $required=FALSE, $options=array() )
|
||||
{
|
||||
$this->start = new \IPS\Helpers\Form\Number( "{$name}[start]", isset( $defaultValue['start'] ) ? $defaultValue['start'] : NULL, FALSE, isset( $options['start'] ) ? $options['start'] : array() );
|
||||
$this->end = new \IPS\Helpers\Form\Number( "{$name}[end]", isset( $defaultValue['end'] ) ? $defaultValue['end'] : NULL, FALSE, isset( $options['end'] ) ? $options['end'] : array() );
|
||||
|
||||
call_user_func_array( 'parent::__construct', func_get_args() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Format Value
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function formatValue()
|
||||
{
|
||||
/* Return */
|
||||
return array(
|
||||
'start' => $this->start->formatValue(),
|
||||
'end' => $this->end->formatValue(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function html()
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->numberRange( $this->start->html(), $this->end->html() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \LengthException
|
||||
* @return TRUE
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
$this->start->validate();
|
||||
$this->end->validate();
|
||||
|
||||
if ( $this->required and $this->value['start'] === NULL and $this->value['end'] === NULL )
|
||||
{
|
||||
throw new \InvalidArgumentException('form_required');
|
||||
}
|
||||
|
||||
if( $this->customValidationCode !== NULL )
|
||||
{
|
||||
call_user_func( $this->customValidationCode, $this->value );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Password input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 11 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -27,14 +27,19 @@ class _Password extends Text
|
||||
* @brief Default Options
|
||||
* @code
|
||||
$childDefaultOptions = array(
|
||||
'validateFor' => \IPS\Member::loggedIn(), // If an \IPS\Member object is provided, the password will be checked if it is valid for that account. Default is NULL.
|
||||
'confirm' => 'password1', // If the name of another element in the form is provided, will check is the values match. Default is NULL.
|
||||
'validateFor' => \IPS\Member::loggedIn(), // If an \IPS\Member object is provided, the password will be checked if it is valid for that account. Default is NULL.
|
||||
'confirm' => 'password1', // If the name of another element in the form is provided, will check is the values match. Default is NULL.
|
||||
'showMeter' => FALSE, // Show a "strength" meter
|
||||
'minimumStrength => 3 // If a strength is provided validation will fail for any lesser value.
|
||||
);
|
||||
* @endcode
|
||||
*/
|
||||
public $childDefaultOptions = array(
|
||||
'validateFor' => NULL,
|
||||
'confirm' => NULL
|
||||
'validateFor' => NULL,
|
||||
'confirm' => NULL,
|
||||
'showMeter' => FALSE,
|
||||
'minimumStrength' => NULL,
|
||||
'checkStrength' => FALSE
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -52,7 +57,21 @@ class _Password extends Text
|
||||
{
|
||||
throw new \InvalidArgumentException( 'err_password_length' );
|
||||
}
|
||||
|
||||
|
||||
/* Does the password meet the minimum required strength? */
|
||||
if ( $this->options['checkStrength'] === TRUE )
|
||||
{
|
||||
$this->options['minimumStrength'] = ( $this->options['minimumStrength'] ) ?: \IPS\Settings::i()->password_strength_option;
|
||||
|
||||
require_once \IPS\ROOT_PATH . "/system/3rd_party/phpass/phpass.php";
|
||||
$phpass = new \PasswordStrength();
|
||||
|
||||
if ( $this->options['showMeter'] and \IPS\Settings::i()->password_strength_meter_enforce and $phpass->classify( $this->value ) < $this->options['minimumStrength'] )
|
||||
{
|
||||
throw new \InvalidArgumentException( \IPS\Member::loggedIn()->language()->addToStack('err_password_strength', FALSE, array( 'sprintf' => \IPS\Member::loggedIn()->language()->addToStack( 'strength_' . \IPS\Settings::i()->password_strength_option ) ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Is valid for member? */
|
||||
if ( $this->options['validateFor'] !== NULL )
|
||||
{
|
||||
@@ -96,4 +115,27 @@ class _Password extends Text
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML
|
||||
*
|
||||
* @return string
|
||||
* @note We cannot pass the regex to the HTML5 'pattern' attribute for two reasons:
|
||||
* @li PCRE and ECMAScript regex are not 100% compatible (though the instances this present a problem are admittedly rare)
|
||||
* @li You cannot specify modifiers with the pattern attribute, which we need to support on the PHP side
|
||||
*/
|
||||
public function html()
|
||||
{
|
||||
/* 10/19/15 - adding htmlspecialchars around value if autocomplete is enabled so that html tag characters can be used (e.g. for members) */
|
||||
/* This value is decoded by the JS widget before use. See https://community.invisionpower.com/4bugtrack/active-reports/cannot-pm-certain-members-r6181/ */
|
||||
if( $this->options['autocomplete'] and !empty( $this->value ) and is_array( $this->value ) )
|
||||
{
|
||||
foreach( $this->value as $key => $value )
|
||||
{
|
||||
$this->value[ $key ] = htmlspecialchars( $value, ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE );
|
||||
}
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->text( $this->name, $this->formType, $this->value, $this->required, $this->options['maxLength'], $this->options['size'], $this->options['disabled'], $this->options['autocomplete'], $this->options['placeholder'], NULL, $this->options['nullLang'], $this->htmlId, $this->options['showMeter'] );
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Poll input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 10 Jan 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -48,33 +48,26 @@ class _Poll extends FormAbstract
|
||||
public function html()
|
||||
{
|
||||
$json = array();
|
||||
|
||||
for( $i = 1; $i <= \IPS\Settings::i()->max_poll_questions; $i++ )
|
||||
|
||||
if ( $this->value AND is_array( $this->value->choices ) AND count( $this->value->choices ) )
|
||||
{
|
||||
$thisQuestion = array();
|
||||
|
||||
if( $this->value AND isset( $this->value->choices[ $i ] ) )
|
||||
foreach ( $this->value->choices as $k => $choice )
|
||||
{
|
||||
$thisQuestion['title'] = $this->value->choices[ $i ]['question'];
|
||||
$thisQuestion['multiChoice'] = (bool) $this->value->choices[ $i ]['multi'];
|
||||
$thisQuestion['choices'] = array();
|
||||
$thisQuestion['title'] = $choice['question'];
|
||||
$thisQuestion['multiChoice'] = ( isset( $choice['multi'] ) and $choice['multi'] ) ? TRUE : FALSE;
|
||||
|
||||
for( $j = 1; $j <= \IPS\Settings::i()->max_poll_choices; $j++ )
|
||||
$thisQuestion['choices'] = array();
|
||||
foreach ( $choice['choice'] as $i => $question )
|
||||
{
|
||||
$thisChoice = array();
|
||||
|
||||
if( $this->value AND isset( $this->value->choices[ $i ]['choice'][ $j ] ) )
|
||||
{
|
||||
$thisChoice['title'] = $this->value->choices[ $i ]['choice'][ $j ];
|
||||
$thisChoice['count'] = $this->value->choices[ $i ]['votes'][ $j ];
|
||||
$thisQuestion['choices'][] = $thisChoice;
|
||||
}
|
||||
$thisChoice['title'] = $question;
|
||||
$thisChoice['count'] = isset( $choice['votes'][ $i ] ) ? $choice['votes'][ $i ] : 0;
|
||||
$thisQuestion['choices'][ $i ] = $thisChoice;
|
||||
}
|
||||
|
||||
$json[] = $thisQuestion;
|
||||
$json[ $k ] = $thisQuestion;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$json = json_encode( $json );
|
||||
|
||||
if( !$this->jsSent )
|
||||
@@ -113,11 +106,16 @@ EOF;
|
||||
$poll = new \IPS\Poll;
|
||||
$poll->starter_id = \IPS\Member::loggedIn()->member_id;
|
||||
}
|
||||
|
||||
|
||||
/* Set values */
|
||||
$data = parent::getValue();
|
||||
if ( !isset( $data['questions'] ) )
|
||||
{
|
||||
if ( isset( $data['fallback'] ) )
|
||||
{
|
||||
return $this->defaultValue;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
$poll->setDataFromForm( $data, $this->options['allowPollOnly'] );
|
||||
@@ -129,7 +127,7 @@ EOF;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Return */
|
||||
return $poll;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Radio Switch class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -35,6 +35,10 @@ class _Radio extends Select
|
||||
{
|
||||
$this->options['descriptions'] = array();
|
||||
}
|
||||
if ( !isset( $this->options['warnings'] ) )
|
||||
{
|
||||
$this->options['warnings'] = array();
|
||||
}
|
||||
|
||||
/* If you haven't selected any radio options, then there is no input and the required flag is never checked (validate() is never called) */
|
||||
$_key = "radio_" . $this->name . "__empty";
|
||||
@@ -62,7 +66,8 @@ class _Radio extends Select
|
||||
*/
|
||||
public function html()
|
||||
{
|
||||
$descriptions = $this->options['descriptions'];
|
||||
$descriptions = $this->options['descriptions'];
|
||||
$warnings = $this->options['warnings'];
|
||||
if ( $this->options['parse'] === 'lang' )
|
||||
{
|
||||
foreach ( $this->options['options'] as $k => $v )
|
||||
@@ -72,6 +77,12 @@ class _Radio extends Select
|
||||
{
|
||||
$descriptions[ $k ] = \IPS\Member::loggedIn()->language()->addToStack( $key );
|
||||
}
|
||||
|
||||
$key = "{$v}_warning";
|
||||
if ( \IPS\Member::loggedIn()->language()->checkKeyExists( $key ) )
|
||||
{
|
||||
$warnings[ $k ] = \IPS\Member::loggedIn()->language()->addToStack( $key );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,19 +90,23 @@ class _Radio extends Select
|
||||
if ( $this->options['returnLabels'] )
|
||||
{
|
||||
$value = array_search( $this->value, $this->options['options'] );
|
||||
if ( $value === FALSE )
|
||||
{
|
||||
$value = $this->defaultValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = $this->value;
|
||||
}
|
||||
|
||||
|
||||
if ( $this->options['parse'] === 'image' )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->radioImages( $this->name, $value, $this->required, $this->options['options'], $this->options['disabled'], $this->options['toggles'], $descriptions, $this->options['userSuppliedInput'], $this->options['unlimited'], $this->options['unlimitedLang'], $this->htmlId );
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->radioImages( $this->name, $value, $this->required, $this->options['options'], $this->options['disabled'], $this->options['toggles'], $descriptions, $warnings, $this->options['userSuppliedInput'], $this->options['unlimited'], $this->options['unlimitedLang'], $this->htmlId );
|
||||
}
|
||||
else
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->radio( $this->name, $value, $this->required, $this->parseOptions(), $this->options['disabled'], $this->options['toggles'], $descriptions, $this->options['userSuppliedInput'], $this->options['unlimited'], $this->options['unlimitedLang'], $this->htmlId );
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->radio( $this->name, $value, $this->required, $this->parseOptions(), $this->options['disabled'], $this->options['toggles'], $descriptions, $warnings, $this->options['userSuppliedInput'], $this->options['unlimited'], $this->options['unlimitedLang'], $this->htmlId );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Rating input Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 3 Oct 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -28,11 +28,15 @@ class _Rating extends FormAbstract
|
||||
* @code
|
||||
$defaultOptions = array(
|
||||
'max' => 5, // Maximum number of stars
|
||||
'display' => 2.5, // If provided, this number of stars will be highlighted initially rather than the value. Can be used for half-values
|
||||
'userRated' => 3, // If provided, will indicate to the user a previous rating
|
||||
);
|
||||
* @endcode
|
||||
*/
|
||||
protected $defaultOptions = array(
|
||||
'max' => 5,
|
||||
'display' => NULL,
|
||||
'userRated' => NULL,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -42,7 +46,7 @@ class _Rating extends FormAbstract
|
||||
*/
|
||||
public function html()
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->rating( $this->name, $this->value, $this->required, $this->options['max'] );
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->rating( $this->name, $this->value, $this->required, $this->options['max'], $this->options['display'], $this->options['userRated'] );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Search input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 11 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Select-box class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -223,12 +223,12 @@ class _Select extends FormAbstract
|
||||
$value = mb_strpos( $name, '[' ) ? \IPS\Request::i()->valueFromArray( $name ) : \IPS\Request::i()->$name;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $value ) AND is_array( $value ) AND $this->options['multiple'] )
|
||||
|
||||
if ( isset( $value ) AND is_array( $value ) AND $this->options['multiple'] AND array_search( '__EMPTY', $value ) !== FALSE )
|
||||
{
|
||||
unset( $value[ array_search( '__EMPTY', $value ) ] );
|
||||
}
|
||||
|
||||
|
||||
if ( $this->options['returnLabels'] )
|
||||
{
|
||||
if ( is_array( $value ) )
|
||||
@@ -286,10 +286,19 @@ class _Select extends FormAbstract
|
||||
$acceptableValues[] = $this->options['returnLabels'] ? $v : $k;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$disabledValues = ( is_array( $this->options['disabled'] ) ) ? $this->options['disabled'] : array( $this->options['disabled'] );
|
||||
$acceptableValues = array_diff( $acceptableValues, $disabledValues );
|
||||
|
||||
$diff = array_diff( ( is_array( $this->value ) ? $this->value : array( $this->value ) ), $acceptableValues );
|
||||
if ( !empty( $diff ) )
|
||||
{
|
||||
/* Is the entire thing disabled? If so, just return any default value set (if one has been set)*/
|
||||
if ( $this->options['disabled'] === TRUE and $this->defaultValue )
|
||||
{
|
||||
return $this->defaultValue;
|
||||
}
|
||||
|
||||
throw new \OutOfRangeException( 'form_bad_value' );
|
||||
}
|
||||
|
||||
@@ -300,15 +309,4 @@ class _Select extends FormAbstract
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* String Value
|
||||
*
|
||||
* @param mixed $value The value
|
||||
* @return string
|
||||
*/
|
||||
public static function stringValue( $value )
|
||||
{
|
||||
return parent::stringValue( $value );
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Form builder helper to allow user-created "groups" of other users
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 10 Mar 2014
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Sort items input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Community Suite
|
||||
* @since 14 Oct 2016
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
namespace IPS\Helpers\Form;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort items input class for Form Builder
|
||||
*/
|
||||
class _Sort extends FormAbstract
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @see \IPS\Helpers\Form\Abstract::__construct
|
||||
* @param string $name Name
|
||||
* @param mixed $defaultValue Default value
|
||||
* @param bool $required Required?
|
||||
* @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
|
||||
*/
|
||||
public function __construct( $name, $defaultValue=NULL, $required=FALSE, $options=array(), $customValidationCode=NULL, $prefix=NULL, $suffix=NULL, $id=NULL )
|
||||
{
|
||||
call_user_func_array( 'parent::__construct', func_get_args() );
|
||||
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'jquery/jquery-ui.js', 'core', 'interface' ) );
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'jquery/jquery-touchpunch.js', 'core', 'interface' ) );
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'jquery/jquery.menuaim.js', 'core', 'interface' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function html()
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->sort( $this->name, $this->value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @return TRUE
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
if ( array_diff( array_keys( $this->value ), array_keys( $this->defaultValue ) ) or array_diff( array_keys( $this->defaultValue ), array_keys( $this->value ) ) )
|
||||
{
|
||||
throw new \DomainException('form_bad_value');
|
||||
}
|
||||
|
||||
parent::validate();
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Stack input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 11 Apr 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -29,6 +29,8 @@ class _Stack extends FormAbstract
|
||||
protected $defaultOptions = array(
|
||||
'stackFieldType' => 'Text',
|
||||
'removeEmptyValues' => TRUE,
|
||||
'maxItems' => NULL,
|
||||
'minItems' => NULL
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -84,7 +86,7 @@ class _Stack extends FormAbstract
|
||||
$class = ( new $classType( $this->name . '[' . count($fields) . ']', $v, FALSE, $this->options, $this->customValidationCode, $this->prefix, $this->suffix, $this->htmlId . '_' . count($fields) ) );
|
||||
$html = $class->html();
|
||||
|
||||
if ( $remove !== md5( $html ) )
|
||||
if( !\IPS\Login::compareHashes( $remove, md5( $html ) ) )
|
||||
{
|
||||
$fields[] = $html;
|
||||
}
|
||||
@@ -95,7 +97,7 @@ class _Stack extends FormAbstract
|
||||
$class = ( new $classType( $this->name . '[0]', NULL, FALSE, $this->options, $this->customValidationCode, $this->prefix, $this->suffix, $this->htmlId . '_' . count($fields) ) );
|
||||
$html = $class->html();
|
||||
|
||||
if ( $remove !== md5( $html ) )
|
||||
if( !\IPS\Login::compareHashes( $remove, md5( $html ) ) )
|
||||
{
|
||||
$fields[] = $html;
|
||||
}
|
||||
@@ -109,7 +111,7 @@ class _Stack extends FormAbstract
|
||||
$fields[] = $html;
|
||||
}
|
||||
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->stack( $this->name, $fields );
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->stack( $this->name, $fields, $this->options );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,13 +153,29 @@ class _Stack extends FormAbstract
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @return TRUE
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
if ( empty( $this->value ) and $this->required )
|
||||
{
|
||||
throw new \InvalidArgumentException('form_required');
|
||||
}
|
||||
|
||||
if ( $this->options['maxItems'] !== NULL and count( $this->value ) > $this->options['maxItems'] )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_tags_max', FALSE, array( 'pluralize' => array( $this->options['maxItems'] ) ) ) );
|
||||
}
|
||||
|
||||
if ( $this->options['minItems'] !== NULL and count( $this->value ) < $this->options['minItems'] )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_tags_min', FALSE, array( 'pluralize' => array( $this->options['minItems'] ) ) ) );
|
||||
}
|
||||
|
||||
parent::validate();
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Telephone input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 11 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
+121
-35
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Text input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -39,7 +39,7 @@ class _Text extends TextArea
|
||||
'unique' => TRUE, // Specifies if the values must be unique
|
||||
'forceLower' => TRUE, // If TRUE, all values will be converted to lowercase
|
||||
'minLength' => 5, // The minimum length of each tag (characters) - if not specified, will be unlimited
|
||||
'maxLength' => 10, // The minimum length of each tag (characters) - if not specified, will be unlimited
|
||||
'maxLength' => 10, // The maximum length of each tag (characters) - if not specified, will be unlimited
|
||||
'prefix' => TRUE, // If TRUE, user will have option to specify one tag as a prefix
|
||||
'resultItemTemplate'=> 'core.foo.bar', // Can be used to specify a custom JavaScript template to use for the result
|
||||
'minAjaxLength' => 3, // Minimum length of value before sending AJAX lookup call
|
||||
@@ -50,6 +50,7 @@ class _Text extends TextArea
|
||||
'nullLang' => 'no_value', // If provided, an "or X" checkbox will appear with X being the value of this language key. When checked, NULL will be returned as the value.
|
||||
'accountUsername' => TRUE, // If TRUE or an \IPS\Member, additional checks will be performed to ensure provided value is acceptable for use as a username. Pass an \IPS\Member object to exclude that member from the duplicate checks
|
||||
'trim' => TRUE, // If TRUE (which is the default), whitespace will be stripped from the start and end of the value
|
||||
'bypassProfanity' => FALSE, // If TRUE, profanity filter will be bypassed when it is not appropriate to do so (ex: on the login form). Defaults to FALSE.
|
||||
);
|
||||
* @endcode
|
||||
*/
|
||||
@@ -64,6 +65,7 @@ class _Text extends TextArea
|
||||
'nullLang' => NULL,
|
||||
'accountUsername' => FALSE,
|
||||
'trim' => TRUE,
|
||||
'bypassProfanity' => FALSE,
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -92,11 +94,12 @@ class _Text extends TextArea
|
||||
$args = func_get_args();
|
||||
if ( isset( $args[3]['accountUsername'] ) and $args[3]['accountUsername'] !== FALSE )
|
||||
{
|
||||
$args[3]['minLength'] = \IPS\Settings::i()->min_user_name_length;
|
||||
$args[3]['maxLength'] = \IPS\Settings::i()->max_user_name_length;
|
||||
|
||||
if ( \IPS\Settings::i()->username_characters )
|
||||
{
|
||||
$args[3]['regex'] = '/^[' . str_replace( '\-', '-', preg_quote( \IPS\Settings::i()->username_characters, '/' ) ) . ']*$/i';
|
||||
$args[3]['regex'] = '/^[' . str_replace( '\-', '-', preg_quote( \IPS\Settings::i()->username_characters, '/' ) ) . ']*$/iu';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +128,7 @@ class _Text extends TextArea
|
||||
{
|
||||
/* 10/19/15 - adding htmlspecialchars around value if autocomplete is enabled so that html tag characters can be used (e.g. for members) */
|
||||
/* This value is decoded by the JS widget before use. See https://community.invisionpower.com/4bugtrack/active-reports/cannot-pm-certain-members-r6181/ */
|
||||
if( $this->options['autocomplete'] and !empty( $this->value ) )
|
||||
if( $this->options['autocomplete'] and !empty( $this->value ) and is_array( $this->value ) )
|
||||
{
|
||||
foreach( $this->value as $key => $value )
|
||||
{
|
||||
@@ -168,18 +171,28 @@ class _Text extends TextArea
|
||||
if ( isset( $this->options['autocomplete'] ) )
|
||||
{
|
||||
$return = htmlspecialchars_decode( $return, ENT_QUOTES );
|
||||
|
||||
if ( !is_array( $return ) )
|
||||
{
|
||||
$return = array_filter( explode( "\n", $return ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove all invisible characters */
|
||||
$return = preg_replace( '/\p{C}+/u', '', $return );
|
||||
if ( !is_array( $return ) )
|
||||
{
|
||||
$return = preg_replace( '/\p{C}+/u', '', $return );
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach( $return as $k => $v )
|
||||
{
|
||||
$return = preg_replace( '/\p{C}+/u', '', $return );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $this->options['autocomplete']['prefix'] ) and $this->options['autocomplete']['prefix'] )
|
||||
{
|
||||
if ( !is_array( $return ) )
|
||||
{
|
||||
$return = array_filter( explode( ',', $return ) );
|
||||
}
|
||||
|
||||
$firstAsPrefix = $this->name . '_first_as_prefix';
|
||||
$freechoicePrefixCheckbox = $this->name . '_freechoice_prefix';
|
||||
$freechoicePrefix = $this->name . '_prefix';
|
||||
@@ -220,7 +233,7 @@ class _Text extends TextArea
|
||||
{
|
||||
if ( $this->options['autocomplete'] !== NULL and ( !isset( $this->options['autocomplete']['maxItems'] ) or $this->options['autocomplete']['maxItems'] != 1 ) and !is_array( $this->value ) and $this->value !== NULL )
|
||||
{
|
||||
return array_filter( array_map( 'trim', explode( ',', $this->value ) ) );
|
||||
return array_filter( array_map( 'trim', explode( "\n", $this->value ) ) );
|
||||
}
|
||||
|
||||
return $this->value;
|
||||
@@ -237,19 +250,37 @@ class _Text extends TextArea
|
||||
{
|
||||
parent::validate();
|
||||
|
||||
/* skip validation if it's an username field and if the name wasn't changed */
|
||||
if ( $this->options['accountUsername'] AND $this->options['accountUsername'] instanceOf \IPS\Member AND $this->options['accountUsername']->name == $this->value )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if( \IPS\Dispatcher::i() instanceof \IPS\Dispatcher\Front and !\IPS\Member::loggedIn()->group['g_bypass_badwords'] )
|
||||
{
|
||||
$looseProfanity = array();
|
||||
$exactProfanity = array();
|
||||
|
||||
/* Set up profanity filters */
|
||||
$exactProfanity = iterator_to_array( \IPS\Db::i()->select( '*', 'core_profanity_filters', array('m_exact=?', TRUE) )->setKeyField( 'type' )->setValueField( 'swop' ) );
|
||||
$looseProfanity = iterator_to_array( \IPS\Db::i()->select( '*', 'core_profanity_filters', array('m_exact=?', FALSE) )->setKeyField( 'type' )->setValueField( 'swop' ) );
|
||||
foreach( \IPS\core\Profanity::getProfanity() AS $profanity )
|
||||
{
|
||||
if ( $profanity->m_exact )
|
||||
{
|
||||
$exactProfanity[ $profanity->type ] = $profanity;
|
||||
}
|
||||
else
|
||||
{
|
||||
$looseProfanity[ $profanity->type ] = $profanity;
|
||||
}
|
||||
}
|
||||
|
||||
foreach( $exactProfanity as $key => $value )
|
||||
{
|
||||
$exactProfanity[mb_strtolower( $key )] = $value;
|
||||
$exactProfanity[ mb_strtolower( $key ) ] = $value;
|
||||
}
|
||||
|
||||
/* Construct break points */
|
||||
$breakPoints = array();
|
||||
$exactProfanityBreakpoints = array();
|
||||
if( count( $exactProfanity ) )
|
||||
{
|
||||
$array = array();
|
||||
@@ -259,7 +290,7 @@ class _Text extends TextArea
|
||||
}
|
||||
|
||||
/* @note: We use \b because of http://community.invisionpower.com/resources/bugs.html/_/4-0-0/anacronym-doesnt-work-in-middle-of-a-phrase-r47612 */
|
||||
$breakPoints[] = '((?=<^|\b)(?:' . implode( '|', $array ) . ')(?=\b|$))';
|
||||
$exactProfanityBreakpoints[] = '((?=<^|\b)(?:' . implode( '|', $array ) . ')(?=\b|$))';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,11 +346,11 @@ class _Text extends TextArea
|
||||
|
||||
if ( isset( $this->options['autocomplete']['maxItems'] ) and count( $values ) > $this->options['autocomplete']['maxItems'] )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_tags_max', FALSE, array( 'pluralize' => $this->options['autocomplete']['maxItems'] ) ) );
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_tags_max', FALSE, array( 'pluralize' => array( $this->options['autocomplete']['maxItems'] ) ) ) );
|
||||
}
|
||||
if ( isset( $this->options['autocomplete']['minItems'] ) and ( $this->required or count( $values ) > 0 ) and count( $values ) < $this->options['autocomplete']['minItems'] )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_tags_min', FALSE, array( 'pluralize' => $this->options['autocomplete']['minItems'] ) ) );
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_tags_min', FALSE, array( 'pluralize' => array( $this->options['autocomplete']['minItems'] ) ) ) );
|
||||
}
|
||||
|
||||
if ( isset( $this->options['autocomplete']['minLength'] ) )
|
||||
@@ -338,7 +369,7 @@ class _Text extends TextArea
|
||||
{
|
||||
if ( mb_strlen( $v ) > $this->options['autocomplete']['maxLength'] )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_tags_length_max', FALSE, array( 'pluralize' => $this->options['autocomplete']['maxLength'] ) ) );
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_tags_length_max', FALSE, array( 'pluralize' => array( $this->options['autocomplete']['maxLength'] ) ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,11 +379,35 @@ class _Text extends TextArea
|
||||
{
|
||||
if ( array_key_exists( $v, $exactProfanity ) )
|
||||
{
|
||||
$this->value[ $k ] = $exactProfanity[ $v ];
|
||||
if ( $exactProfanity[ $v ]->action == 'swap' )
|
||||
{
|
||||
$this->value[ $k ] = $exactProfanity[ $v ]->swop;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \DomainException( 'Profanity Filter' ); // @todo proper lang string
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->value[ $k ] = str_replace( array_keys( $looseProfanity ), array_values( $looseProfanity ), $v );
|
||||
$swaps = array();
|
||||
foreach( $looseProfanity AS $type => $row )
|
||||
{
|
||||
if ( $row->action == 'swap' )
|
||||
{
|
||||
$swaps[ $row->type ] = $row->swop;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mb_stristr( $value, $type ) )
|
||||
{
|
||||
throw new \DomainException( 'Profanity Filter' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Still here? Normal swaps. */
|
||||
$this->value[ $k ] = str_ireplace( array_keys( $swaps ), array_values( $swaps ), $this->value[ $k ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -369,34 +424,42 @@ class _Text extends TextArea
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_array ( $this->value ) AND isset( $this->options['autocomplete']['source'] ) AND is_array( $this->options['autocomplete']['source'] ) AND !$this->options['autocomplete']['freeChoice'] )
|
||||
if ( is_array ( $this->value ) AND isset( $this->options['autocomplete']['source'] ) AND is_array( $this->options['autocomplete']['source'] ) AND ( !isset( $this->options['autocomplete']['freeChoice'] ) OR !$this->options['autocomplete']['freeChoice'] ) )
|
||||
{
|
||||
$this->value = array_uintersect( $this->value, $this->options['autocomplete']['source'], function( $a, $b ){
|
||||
return ( mb_strtolower( $a ) === mb_strtolower( $b ) );
|
||||
} );
|
||||
if( isset( $this->options['autocomplete']['forceLower'] ) AND $this->options['autocomplete']['forceLower'] )
|
||||
{
|
||||
$this->value = array_uintersect( array_map( 'mb_strtolower', $this->value ), array_map( 'mb_strtolower', $this->options['autocomplete']['source'] ), 'strcasecmp' );
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->value = array_uintersect( $this->value, $this->options['autocomplete']['source'], 'strcasecmp' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Split on profanity */
|
||||
if( is_string( $this->value ) and \IPS\Dispatcher::i() instanceof \IPS\Dispatcher\Front and !\IPS\Member::loggedIn()->group['g_bypass_badwords'] )
|
||||
if( $this->options['bypassProfanity'] === FALSE and is_string( $this->value ) and \IPS\Dispatcher::i() instanceof \IPS\Dispatcher\Front and !\IPS\Member::loggedIn()->group['g_bypass_badwords'] )
|
||||
{
|
||||
$newVal = NULL;
|
||||
if ( count( $breakPoints ) )
|
||||
if ( count( $exactProfanityBreakpoints ) )
|
||||
{
|
||||
/* preg_split can return boolean false*/
|
||||
$split = preg_split( '/' . implode( '|', $breakPoints ) . '/iu', $this->value, null, PREG_SPLIT_DELIM_CAPTURE );
|
||||
$split = preg_split( '/' . implode( '|', $exactProfanityBreakpoints ) . '/iu', $this->value, null, PREG_SPLIT_DELIM_CAPTURE );
|
||||
|
||||
if( is_array( $split ) )
|
||||
{
|
||||
foreach ( $split as $section )
|
||||
{
|
||||
/* Replace loose profanity */
|
||||
$section = str_ireplace( array_keys( $looseProfanity ), array_values( $looseProfanity ), $section );
|
||||
|
||||
if ( isset( $exactProfanity[ mb_strtolower( $section ) ] ) )
|
||||
{
|
||||
$newVal .= $exactProfanity[ mb_strtolower( $section ) ];
|
||||
|
||||
if ( $exactProfanity[ mb_strtolower( $section ) ]->action == 'swap' )
|
||||
{
|
||||
$newVal .= $exactProfanity[ mb_strtolower( $section ) ]->swop;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new \DomainException( 'Profanity Filter' );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -405,8 +468,31 @@ class _Text extends TextArea
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$value = $newVal ?: $this->value;
|
||||
|
||||
if ( count( $looseProfanity ) )
|
||||
{
|
||||
$swaps = array();
|
||||
foreach( $looseProfanity AS $type => $row )
|
||||
{
|
||||
if ( $row->action == 'swap' )
|
||||
{
|
||||
$swaps[ $row->type ] = $row->swop;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( mb_stristr( $value, $type ) )
|
||||
{
|
||||
throw new \DomainException( 'Profanity Filter' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$value = str_ireplace( array_keys( $swaps ), array_values( $swaps ), $value );
|
||||
}
|
||||
|
||||
$this->value = $newVal ?: $this->value;
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Text input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Translatable text input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 25 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -31,6 +31,7 @@ class _Translatable extends FormAbstract
|
||||
'editor' => array(...), // If this needs to be an editor rather than a textbox, all the options of \IPS\Helpers\Form\Editor are available here
|
||||
'textArea' => FALSE, // Makes a textarea rather than a textbox
|
||||
'placeholder' => 'Example', // Placeholder
|
||||
'sprintf' => array(), // sprintf options - useful when doing dynamic replacements (such as {var} which should be converted to %1$s or %s on save).
|
||||
);
|
||||
* @endcode
|
||||
*/
|
||||
@@ -38,13 +39,14 @@ class _Translatable extends FormAbstract
|
||||
'key' => NULL,
|
||||
'editor' => NULL,
|
||||
'textArea' => FALSE,
|
||||
'placeholder' => NULL
|
||||
'placeholder' => NULL,
|
||||
'sprintf' => NULL
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Editors
|
||||
*/
|
||||
protected $editors = array();
|
||||
protected $editors = NULL;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -69,7 +71,14 @@ class _Translatable extends FormAbstract
|
||||
$v = $v['word_custom'] ?: $v['word_default'];
|
||||
if ( $v or !isset( $values[ $k ] ) )
|
||||
{
|
||||
$values[ $k ] = $v;
|
||||
if ( is_array( $this->options['sprintf'] ) )
|
||||
{
|
||||
$values[ $k ] = vsprintf( $v, $this->options['sprintf'] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$values[ $k ] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,20 +95,35 @@ class _Translatable extends FormAbstract
|
||||
$this->value = $values;
|
||||
}
|
||||
|
||||
/* Init editors */
|
||||
if ( isset( $this->options['editor'] ) )
|
||||
{
|
||||
foreach ( \IPS\Lang::getEnabledLanguages() as $lang )
|
||||
{
|
||||
$options = $this->options['editor'];
|
||||
$options['autoSaveKey'] .= $lang->id;
|
||||
$this->editors[ $lang->id ] = new Editor( "{$this->name}[{$lang->id}]", isset( $this->value[ $lang->id ] ) ? $this->value[ $lang->id ] : NULL, $this->required, $options );
|
||||
}
|
||||
}
|
||||
|
||||
/* Add flags.css */
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'flags.css', 'core', 'global' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get editors
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function _getEditors()
|
||||
{
|
||||
if ( isset( $this->options['editor'] ) )
|
||||
{
|
||||
if ( $this->editors === NULL )
|
||||
{
|
||||
foreach ( \IPS\Lang::getEnabledLanguages() as $lang )
|
||||
{
|
||||
$options = $this->options['editor'];
|
||||
$options['autoSaveKey'] .= $lang->id;
|
||||
$this->editors[ $lang->id ] = new Editor( "{$this->name}[{$lang->id}]", isset( $this->value[ $lang->id ] ) ? $this->value[ $lang->id ] : NULL, $this->required, $options );
|
||||
}
|
||||
}
|
||||
return $this->editors;
|
||||
}
|
||||
else
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get HTML
|
||||
@@ -108,7 +132,30 @@ class _Translatable extends FormAbstract
|
||||
*/
|
||||
public function html()
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->translatable( $this->name, \IPS\Lang::getEnabledLanguages(), $this->value, $this->editors, $this->options['placeholder'], $this->options['textArea'], $this->required );
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->translatable( $this->name, \IPS\Lang::getEnabledLanguages(), $this->value, $this->_getEditors(), $this->options['placeholder'], $this->options['textArea'], $this->required );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get Value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
if ( isset( $this->options['editor'] ) )
|
||||
{
|
||||
$return = array();
|
||||
foreach ( $this->_getEditors() as $languageId => $editor )
|
||||
{
|
||||
$return[ $languageId ] = $editor->getValue();
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
else
|
||||
{
|
||||
return parent::getValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Upload class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -34,6 +34,7 @@ class _Upload extends FormAbstract
|
||||
'allowedFileTypes' => array( 'pdf', 'txt' ), // Allowed file extensions. NULL allows any. Default is NULL.
|
||||
'maxFileSize' => 100, // Maximum file size in megabytes. NULL is no limit. Default is NULL. Note that there *may* be server limitations regardless of this value which are calculated automatically.
|
||||
'totalMaxSize' => 100, // If this is a "multiple" upload field, the maximum storage space allowed in total in megabytes.
|
||||
'maxFiles' => NULL, // Maximum number of files that can be uploaded
|
||||
'postKey' => 'abc', // If provided, uploads will be treated as post attachments using the given post key
|
||||
'temporary' => TRUE, // If TRUE, the image will not be moved and the filename returned, rather than an \IPS\File object. This should ONLY be used for files which are genuinely
|
||||
temporary (e.g. importing skins, languages) as the file will be deleted after the script finished executing. Default is FALSE.
|
||||
@@ -51,6 +52,7 @@ class _Upload extends FormAbstract
|
||||
'allowedFileTypes' => NULL,
|
||||
'maxFileSize' => NULL,
|
||||
'totalMaxSize' => NULL,
|
||||
'maxFiles' => NULL,
|
||||
'postKey' => NULL,
|
||||
'storageExtension' => NULL,
|
||||
'storageContainer' => NULL,
|
||||
@@ -79,65 +81,72 @@ class _Upload extends FormAbstract
|
||||
*
|
||||
* @see \IPS\Helpers\Form\Abstract::__construct
|
||||
* @param string $name Name
|
||||
* @param mixed $defaultValue Default value
|
||||
* @param bool $required Required?
|
||||
* @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
|
||||
*/
|
||||
public function __construct( $name )
|
||||
public function __construct( $name, $defaultValue=NULL, $required=FALSE, $options=array(), $customValidationCode=NULL, $prefix=NULL, $suffix=NULL, $id=NULL )
|
||||
{
|
||||
/* What's PHP's upload limit */
|
||||
$potentialValues = array();
|
||||
|
||||
if( (float) ini_get('upload_max_filesize') > 0 )
|
||||
{
|
||||
$potentialValues[] = \IPS\File::returnBytes( ini_get('upload_max_filesize') );
|
||||
}
|
||||
|
||||
if( (float) ini_get('post_max_size') > 0 )
|
||||
{
|
||||
$potentialValues[] = \IPS\File::returnBytes( ini_get('post_max_size') ) - 1048576;
|
||||
}
|
||||
|
||||
if( (float) ini_get('memory_limit') > 0 )
|
||||
{
|
||||
$potentialValues[] = \IPS\File::returnBytes( ini_get('memory_limit') );
|
||||
}
|
||||
|
||||
/* We want the value in MB */
|
||||
$this->maxChunkSize = min( $potentialValues ) / 1048576;
|
||||
|
||||
/* Call parent constructor */
|
||||
call_user_func_array( 'parent::__construct', func_get_args() );
|
||||
|
||||
/* Work out storage extension */
|
||||
if ( $this->options['postKey'] and !$this->options['storageExtension'] )
|
||||
if ( isset( $options['postKey'] ) and $options['postKey'] and ( !isset( $options['storageExtension'] ) or !$options['storageExtension'] ) )
|
||||
{
|
||||
$this->options['storageExtension'] = 'core_Attachment';
|
||||
$options['storageExtension'] = 'core_Attachment';
|
||||
}
|
||||
if ( !$this->options['storageExtension'] and !$this->options['temporary'] )
|
||||
if ( ( !isset( $options['storageExtension'] ) or !$options['storageExtension'] ) and ( !isset( $options['temporary'] ) or !$options['temporary'] ) )
|
||||
{
|
||||
throw new \InvalidArgumentException;
|
||||
}
|
||||
|
||||
/* Does the storage extension support chunking? */
|
||||
if ( $this->options['storageExtension'] )
|
||||
if ( isset( $options['storageExtension'] ) and $options['storageExtension'] )
|
||||
{
|
||||
$storageClass = \IPS\File::getClass( $this->options['storageExtension'] );
|
||||
if( !$storageClass::$supportsChunking and ( $this->options['maxFileSize'] === NULL or $this->maxChunkSize < $this->options['maxFileSize'] ) )
|
||||
$storageClass = \IPS\File::getClass( $options['storageExtension'] );
|
||||
if( !$storageClass::$supportsChunking and ( !isset( $options['maxFileSize'] ) or $this->maxChunkSize < $options['maxFileSize'] ) )
|
||||
{
|
||||
$this->options['maxFileSize'] = $this->maxChunkSize;
|
||||
$options['maxFileSize'] = $this->maxChunkSize;
|
||||
}
|
||||
}
|
||||
|
||||
if( $this->options['maxFileSize'] !== NULL AND $this->options['maxFileSize'] <= 0 )
|
||||
if( isset( $options['maxFileSize'] ) AND $options['maxFileSize'] <= 0 )
|
||||
{
|
||||
throw new \InvalidArgumentException;
|
||||
}
|
||||
|
||||
if( isset( $options['maxFiles'] ) AND $options['maxFiles'] <= 0 )
|
||||
{
|
||||
throw new \InvalidArgumentException;
|
||||
}
|
||||
|
||||
/* If this has to be an image, set the allowed file types */
|
||||
if ( $this->options['image'] !== NULL and !isset( $this->options['image']['optional'] ) and $this->options['allowedFileTypes'] === NULL )
|
||||
if ( isset( $options['image'] ) and !isset( $options['image']['optional'] ) and !isset( $options['allowedFileTypes'] ) )
|
||||
{
|
||||
$this->options['allowedFileTypes'] = \IPS\Image::$imageExtensions;
|
||||
$options['allowedFileTypes'] = \IPS\Image::$imageExtensions;
|
||||
}
|
||||
|
||||
|
||||
/* Call parent constructor */
|
||||
parent::__construct( $name, $defaultValue, $required, $options, $customValidationCode, $prefix, $suffix, $id );
|
||||
|
||||
/* Add JS */
|
||||
if ( \IPS\IN_DEV )
|
||||
{
|
||||
@@ -171,7 +180,7 @@ class _Upload extends FormAbstract
|
||||
}
|
||||
|
||||
/* Are we processing an AJAX upload? */
|
||||
if( isset( $_SERVER['HTTP_X_PLUPLOAD'] ) AND ( $_SERVER['HTTP_X_PLUPLOAD'] == md5( $this->name . session_id() ) ) )
|
||||
if( isset( $_SERVER['HTTP_X_PLUPLOAD'] ) AND \IPS\Login::compareHashes( $_SERVER['HTTP_X_PLUPLOAD'], md5( $this->name . session_id() ) ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -211,6 +220,12 @@ class _Upload extends FormAbstract
|
||||
try
|
||||
{
|
||||
$image = \IPS\Image::create( $fileObj->contents() );
|
||||
|
||||
if( $image::exifSupported() )
|
||||
{
|
||||
$image->setExifData( $fileObj->contents() );
|
||||
}
|
||||
|
||||
$image->resizeToMax( $options['image']['maxWidth'] ?: NULL, $options['image']['maxHeight'] ?: NULL );
|
||||
|
||||
$fileObj->replace( (string) $image );
|
||||
@@ -219,11 +234,12 @@ class _Upload extends FormAbstract
|
||||
}
|
||||
|
||||
$insertId = \IPS\Db::i()->insert( 'core_files_temp', array(
|
||||
'upload_key' => md5( $this->name . session_id() ),
|
||||
'filename' => $fileObj->originalFilename,
|
||||
'mime' => \IPS\File::getMimeType( $fileObj->originalFilename ),
|
||||
'contents' => (string) $fileObj,
|
||||
'time' => time()
|
||||
'upload_key' => md5( $this->name . session_id() ),
|
||||
'filename' => $fileObj->originalFilename,
|
||||
'mime' => \IPS\File::getMimeType( $fileObj->originalFilename ),
|
||||
'contents' => (string) $fileObj,
|
||||
'time' => time(),
|
||||
'storage_extension' => $this->options['storageExtension']
|
||||
) );
|
||||
|
||||
if ( $this->options['callback'] )
|
||||
@@ -271,7 +287,11 @@ class _Upload extends FormAbstract
|
||||
{
|
||||
$message = \IPS\Member::loggedIn()->language()->addToStack("uploaderr_{$e->getMessage()}");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
$message = \IPS\Member::loggedIn()->language()->addToStack("uploaderr_unspecified");
|
||||
}
|
||||
|
||||
\IPS\Output::i()->json( array(
|
||||
'error' => $message,
|
||||
'extra' => $e->getCode()
|
||||
@@ -373,7 +393,7 @@ class _Upload extends FormAbstract
|
||||
$maxFileSize = $this->options['maxFileSize'] ? number_format( $this->options['maxFileSize'], 4, '.', '' ) : $this->options['maxFileSize'];
|
||||
|
||||
/* The html() method is called more than once, however $this->value is wiped out so if it was an attachments array all of the array properties are lost */
|
||||
$this->builtHtml = call_user_func( $this->template, $this->name, $this->value, $this->options['minimize'], $maxFileSize, $this->maxChunkSize, $this->options['totalMaxSize'], $this->options['allowedFileTypes'], $uploadKey, $this->options['multiple'], $this->options['postKey'], $this->options['temporary'] or ( isset( \IPS\Request::i()->cookie['vle_editor'] ) and \IPS\Request::i()->cookie['vle_editor'] ), $this->options['template'], $existing, $this->options['default'] );
|
||||
$this->builtHtml = call_user_func( $this->template, $this->name, $this->value, $this->options['minimize'], $maxFileSize, $this->options['maxFiles'], $this->maxChunkSize, $this->options['totalMaxSize'], $this->options['allowedFileTypes'], $uploadKey, $this->options['multiple'], $this->options['postKey'], $this->options['temporary'] or ( isset( \IPS\Request::i()->cookie['vle_editor'] ) and \IPS\Request::i()->cookie['vle_editor'] ), $this->options['template'], $existing, $this->options['default'] );
|
||||
return $this->builtHtml;
|
||||
}
|
||||
|
||||
@@ -444,9 +464,9 @@ class _Upload extends FormAbstract
|
||||
{
|
||||
/* Don't delete file if new file upload has same name */
|
||||
$okToDelete = TRUE;
|
||||
foreach( $tempFiles as $tid => $path )
|
||||
foreach( $tempFiles as $tid => $tmpFile )
|
||||
{
|
||||
if ( (string) $this->defaultValue[ $id ] == $path )
|
||||
if ( (string) $this->defaultValue[ $id ] == $tmpFile['contents'] )
|
||||
{
|
||||
$okToDelete = FALSE;
|
||||
}
|
||||
@@ -471,12 +491,12 @@ class _Upload extends FormAbstract
|
||||
if ( is_array( $this->defaultValue ) )
|
||||
{
|
||||
foreach( $this->defaultValue as $file )
|
||||
{
|
||||
{
|
||||
/* Don't delete file if new file upload has same name */
|
||||
$okToDelete = TRUE;
|
||||
foreach( $tempFiles as $id => $path )
|
||||
foreach( $tempFiles as $id => $tmpFile )
|
||||
{
|
||||
if ( (string) $file == $path )
|
||||
if ( (string) $file == $tmpFile['contents'] )
|
||||
{
|
||||
$okToDelete = FALSE;
|
||||
}
|
||||
@@ -492,9 +512,9 @@ class _Upload extends FormAbstract
|
||||
{
|
||||
/* Don't delete file if new file upload has same name */
|
||||
$okToDelete = TRUE;
|
||||
foreach( $tempFiles as $id => $path )
|
||||
foreach( $tempFiles as $id => $tmpFile )
|
||||
{
|
||||
if ( (string) $this->defaultValue == $path )
|
||||
if ( (string) $this->defaultValue == $tmpFile['contents'] )
|
||||
{
|
||||
$okToDelete = FALSE;
|
||||
}
|
||||
@@ -594,7 +614,7 @@ class _Upload extends FormAbstract
|
||||
{
|
||||
\IPS\File::validateUpload( $file, $this->options['allowedFileTypes'], $this->options['maxFileSize'] );
|
||||
|
||||
$ext = mb_substr( $file['name'], ( mb_strrpos( $file['name'], '.' ) + 1 ) );
|
||||
$ext = mb_strtolower( mb_substr( $file['name'], ( mb_strrpos( $file['name'], '.' ) + 1 ) ) );
|
||||
|
||||
/* Don't allow "XSS" in images */
|
||||
if( in_array( $ext, \IPS\File::$safeFileExtensions ) AND in_array( $ext, \IPS\Image::$imageExtensions ) )
|
||||
@@ -616,16 +636,22 @@ class _Upload extends FormAbstract
|
||||
if ( is_array( $this->options['image'] ) )
|
||||
{
|
||||
$options = $this->options;
|
||||
$fileObjects = \IPS\File::createFromUploads( $this->options['storageExtension'], $fieldName, $this->options['allowedFileTypes'], $this->options['maxFileSize'], $this->options['totalMaxSize'], 0, function( $contents ) use ( $options )
|
||||
{
|
||||
try
|
||||
$fileObjects = \IPS\File::createFromUploads( $this->options['storageExtension'], $fieldName, $this->options['allowedFileTypes'], $this->options['maxFileSize'], $this->options['totalMaxSize'], 0, function( $contents, $filename ) use ( $options )
|
||||
{
|
||||
$ext = mb_strtolower( mb_substr( $filename, mb_strrpos( $filename, '.' ) + 1 ) );
|
||||
|
||||
/* Resize images */
|
||||
if ( in_array( $ext, \IPS\Image::$imageExtensions ) )
|
||||
{
|
||||
$image = \IPS\Image::create( $contents );
|
||||
$image->resizeToMax( $options['image']['maxWidth'] ?: NULL, $options['image']['maxHeight'] ?: NULL );
|
||||
|
||||
return (string) $image;
|
||||
try
|
||||
{
|
||||
$image = \IPS\Image::create( $contents );
|
||||
$image->resizeToMax( $options['image']['maxWidth'] ?: NULL, $options['image']['maxHeight'] ?: NULL );
|
||||
|
||||
return (string) $image;
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
|
||||
return $contents;
|
||||
}, $this->options['storageContainer'], $this->options['obscure'] );
|
||||
@@ -634,15 +660,16 @@ class _Upload extends FormAbstract
|
||||
{
|
||||
$fileObjects = \IPS\File::createFromUploads( $this->options['storageExtension'], $fieldName, $this->options['allowedFileTypes'], $this->options['maxFileSize'], $this->options['totalMaxSize'], 0, NULL, $this->options['storageContainer'], $this->options['obscure'] );
|
||||
}
|
||||
|
||||
|
||||
foreach ( $fileObjects as $fileObj )
|
||||
{
|
||||
$insertId = \IPS\Db::i()->insert( 'core_files_temp', array(
|
||||
'upload_key' => md5( $this->name . session_id() ),
|
||||
'filename' => $fileObj->originalFilename,
|
||||
'mime' => \IPS\File::getMimeType( $fileObj->originalFilename ),
|
||||
'contents' => (string) $fileObj,
|
||||
'time' => time()
|
||||
'upload_key' => md5( $this->name . session_id() ),
|
||||
'filename' => $fileObj->originalFilename,
|
||||
'mime' => \IPS\File::getMimeType( $fileObj->originalFilename ),
|
||||
'contents' => (string) $fileObj,
|
||||
'time' => time(),
|
||||
'storage_extension' => $this->options['storageExtension']
|
||||
) );
|
||||
|
||||
if ( $this->options['callback'] )
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief URL input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 11 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -28,9 +28,11 @@ class _Url extends Text
|
||||
* @code
|
||||
$childDefaultOptions = array(
|
||||
'allowedProtocols' => array( 'http', 'https' ), // Allowed protocols. Default is http and https. Be careful changing this not to introduce security issues.
|
||||
'allowedMimes' => 'image/*', // Sets the allowed mimetype(s). Can be string or array. * is a wildcard. Default is NULL, which allows any mimetypes.
|
||||
'file' => 'Profile', // If provided, the contents of the URL will be fetched and written as a file, an \IPS\File object will then be returned rather than a string. Provide the extension name which specifies the storage location to use.
|
||||
'allowedMimes' => 'image/*', // Sets the allowed mimetype(s). Can be string or array. * is a wildcard. Default is NULL, which allows any mimetypes. Note, setting this will not allow localhost URLs.
|
||||
'file' => 'Profile', // If provided, the contents of the URL will be fetched and written as a file, an \IPS\File object will then be returned rather than a string. Provide the extension name which specifies the storage location to use. Note, setting this will not allow localhost URLs.
|
||||
'maxFileSize' => NULL, // If provided along with 'file', the resulting file that is written to disk cannot be greater than this size in megabytes. NULL for no limit (default is NULL).
|
||||
'maxDimensions' => NULL, // If supplied as an array with keys 'width' and 'height' and the resulting file is an image, the image will be scaled down to these maximum dimensions. NULL for no limits (default is NULL).
|
||||
'rateLimit' => 20, // Rate-limit requests to prevent the ability to DOS a remote server - time between allowed attempts in seconds (defaults to 20). NULL to disable rate limiting.
|
||||
);
|
||||
* @endcode
|
||||
*/
|
||||
@@ -39,6 +41,8 @@ class _Url extends Text
|
||||
'allowedMimes' => NULL,
|
||||
'file' => FALSE,
|
||||
'maxFileSize' => NULL,
|
||||
'maxDimensions' => NULL,
|
||||
'rateLimit' => 20
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -71,6 +75,32 @@ class _Url extends Text
|
||||
/* Try to fetch it, if necessary */
|
||||
if ( $this->options['file'] or $this->options['allowedMimes'] )
|
||||
{
|
||||
/* Localhost is not allowed as sending a HTTP request to the local server will cause scripts which are relying
|
||||
on only being accessible to the local machine to execute */
|
||||
if ( $value->isLocalhost() )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_url_localhost', FALSE, array( 'sprintf' => array( \IPS\Http\Url::internal('')->data['host'] ) ) ) );
|
||||
}
|
||||
|
||||
/* Is rate limiting enabled (the default)? */
|
||||
if( $this->options['rateLimit'] !== NULL AND intval( $this->options['rateLimit'] ) > 0 )
|
||||
{
|
||||
/* We need to rate limit URL fetch requests - have we tried to fetch this field yet? */
|
||||
$_key = 'url_fetch_' . $this->htmlId;
|
||||
|
||||
if( isset( $_SESSION[ $_key ] ) AND $_SESSION[ $_key ] )
|
||||
{
|
||||
/* Was it less than 20 seconds ago? If so, make the user wait */
|
||||
$timeLeft = $_SESSION[ $_key ] - ( time() - intval( $this->options['rateLimit'] ) );
|
||||
if( $timeLeft > 0 )
|
||||
{
|
||||
throw new \DomainException( \IPS\Member::loggedIn()->language()->addToStack( 'form_url_too_soon', FALSE, array( 'sprintf' => array( $this->options['rateLimit'], $timeLeft ) ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
$_SESSION[ $_key ] = time();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$response = $value->request()->get();
|
||||
@@ -118,6 +148,25 @@ class _Url extends Text
|
||||
try
|
||||
{
|
||||
$this->value = \IPS\File::create( $this->options['file'], $filename, $response );
|
||||
|
||||
/* Do we need to resize images down? */
|
||||
if( $this->value->isImage() AND $this->options['maxDimensions'] !== NULL )
|
||||
{
|
||||
try
|
||||
{
|
||||
$image = \IPS\Image::create( $this->value->contents() );
|
||||
|
||||
if( $image::exifSupported() )
|
||||
{
|
||||
$image->setExifData( $this->value->contents() );
|
||||
}
|
||||
|
||||
$image->resizeToMax( $this->options['maxDimensions']['width'] ?: NULL, $this->options['maxDimensions']['height'] ?: NULL );
|
||||
|
||||
$this->value->replace( (string) $image );
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
}
|
||||
}
|
||||
catch( \InvalidArgumentException $e )
|
||||
{
|
||||
@@ -160,7 +209,7 @@ class _Url extends Text
|
||||
{
|
||||
try
|
||||
{
|
||||
return new \IPS\Http\Url( $this->value );
|
||||
return \IPS\Http\Url::createFromString( $this->value, TRUE, TRUE );
|
||||
}
|
||||
catch ( \InvalidArgumentException $e )
|
||||
{
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Width/Height input class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 28 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Yes/No Radio Switches class for Form Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 8 Mar 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Multiple Redirector
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 3 Apr 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -54,14 +54,36 @@ class _MultipleRedirect
|
||||
{
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'global_core.js', 'core', 'global' ) );
|
||||
|
||||
$this->url = $url;
|
||||
|
||||
$this->url = $url;
|
||||
$key = 'mr-' . md5( $url );
|
||||
|
||||
if ( isset( \IPS\Request::i()->mr ) and ! isset( \IPS\Request::i()->mr_continue ) )
|
||||
{
|
||||
$data = json_decode( urldecode( base64_decode( \IPS\Request::i()->mr ) ), TRUE );
|
||||
|
||||
if ( isset( \IPS\Request::i()->_mrReset ) )
|
||||
{
|
||||
$data = NULL;
|
||||
$iteration = 1;
|
||||
}
|
||||
elseif ( isset( $_SESSION[ $key ] ) )
|
||||
{
|
||||
$data = json_decode( $_SESSION[ $key ], TRUE );
|
||||
$iteration = intval( \IPS\Request::i()->mr ) + 1;
|
||||
}
|
||||
elseif ( !is_numeric( \IPS\Request::i()->mr ) and $base64Decoded = @base64_decode( \IPS\Request::i()->mr ) )
|
||||
{
|
||||
$data = json_decode( urldecode( $base64Decoded ), TRUE );
|
||||
$iteration = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$data = NULL;
|
||||
$iteration = 1;
|
||||
}
|
||||
|
||||
if ( $data === '__done' )
|
||||
{
|
||||
unset( $_SESSION[ $key ] );
|
||||
|
||||
call_user_func( $finished );
|
||||
return;
|
||||
}
|
||||
@@ -72,6 +94,7 @@ class _MultipleRedirect
|
||||
|
||||
if ( $response === NULL )
|
||||
{
|
||||
unset( $_SESSION[ $key ] );
|
||||
if ( !\IPS\Request::i()->isAjax() )
|
||||
{
|
||||
call_user_func( $finished );
|
||||
@@ -79,7 +102,8 @@ class _MultipleRedirect
|
||||
}
|
||||
else
|
||||
{
|
||||
\IPS\Output::i()->json( array( base64_encode( urlencode( json_encode( $finalRedirect ? '__done' : '__done__' ) ) ) ) );
|
||||
$_SESSION['mr-' . md5( $url ) ] = json_encode( $finalRedirect ? '__done' : '__done__' );
|
||||
\IPS\Output::i()->json( $finalRedirect ? array( 'done' => true ) : array( 'close' => true ) );
|
||||
}
|
||||
}
|
||||
elseif ( is_string( $response[0] ) )
|
||||
@@ -92,13 +116,14 @@ class _MultipleRedirect
|
||||
}
|
||||
else
|
||||
{
|
||||
$_SESSION['mr-' . md5( $url ) ] = json_encode( $response[0] );
|
||||
|
||||
if ( !\IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $this->url->setQueryString( 'mr', base64_encode( urlencode( json_encode( $response[0] ) ) ) ), $response[1], 303, TRUE );
|
||||
\IPS\Output::i()->redirect( $this->url->setQueryString( 'mr', $iteration ), $response[1], 303, TRUE );
|
||||
}
|
||||
else
|
||||
{
|
||||
$response[0] = base64_encode( json_encode( $response[0] ) );
|
||||
\IPS\Output::i()->json( $response );
|
||||
}
|
||||
}
|
||||
@@ -110,8 +135,9 @@ class _MultipleRedirect
|
||||
\IPS\Output::i()->error( $e->getMessage() . ' ' . $e->getLine() . ' ' . str_replace( "\n", "<br>", $e->getTraceAsString() ), '1S111/1', 403, '' );
|
||||
}
|
||||
|
||||
\IPS\Log::log( $e, 'multiredirect' );
|
||||
\IPS\Output::i()->error( $e->getMessage(), '1S111/1', 403, '' );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +148,6 @@ class _MultipleRedirect
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->output ?: \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->multipleRedirect( $this->url, ( ( isset( \IPS\Request::i()->mr_continue ) and isset( \IPS\Request::i()->mr ) ) ? \IPS\Request::i()->mr : base64_encode( json_encode( 0 ) ) ) );
|
||||
return $this->output ?: \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->multipleRedirect( $this->url, ( ( isset( \IPS\Request::i()->mr_continue ) and isset( \IPS\Request::i()->mr ) ) ? \IPS\Request::i()->mr : 0 ) );
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Table Builder using an \IPS\Content\Item class datasource
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 16 Jul 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -57,7 +57,12 @@ class _Content extends Table
|
||||
* @brief Honor the pinned flag for sorting. Will be set to false in stream-like views
|
||||
*/
|
||||
protected $honorPinned = TRUE;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Show moved links in the result set. This is desirable in controller generated views but not streams or widgets, etc.
|
||||
*/
|
||||
protected $showMovedLinks = FALSE;
|
||||
|
||||
/**
|
||||
* Number of results
|
||||
*/
|
||||
@@ -107,9 +112,11 @@ class _Content extends Table
|
||||
* @param \IPS\Node\Model|NULL $container The container
|
||||
* @param bool|null $includeHidden Flag to pass to getItemsWithPermission() method for $includeHiddenContent, defaults to NULL
|
||||
* @param string|NULL $permCheck Permission key to check
|
||||
* @param bool $honorPinned Show pinned topics at the top of the table
|
||||
* @param bool $showMovedLinks Show moved links in the result set.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $class, \IPS\Http\Url $baseUrl, $where=NULL, \IPS\Node\Model $container=NULL, $includeHidden=NULL, $permCheck='view', $honorPinned=TRUE )
|
||||
public function __construct( $class, \IPS\Http\Url $baseUrl, $where=NULL, \IPS\Node\Model $container=NULL, $includeHidden=\IPS\Content\Hideable::FILTER_AUTOMATIC, $permCheck='view', $honorPinned=TRUE, $showMovedLinks=FALSE )
|
||||
{
|
||||
/* Init */
|
||||
$this->include = array();
|
||||
@@ -118,6 +125,7 @@ class _Content extends Table
|
||||
$this->container = $container;
|
||||
$this->includeHiddenContent = $includeHidden;
|
||||
$this->honorPinned = $honorPinned;
|
||||
$this->showMovedLinks = $showMovedLinks;
|
||||
$this->permCheck = $permCheck;
|
||||
|
||||
/* Init */
|
||||
@@ -133,14 +141,14 @@ class _Content extends Table
|
||||
|
||||
if ( !$this->sortBy and $container->_sortBy !== NULL )
|
||||
{
|
||||
$this->sortBy = $container->_sortBy;
|
||||
$this->sortBy = $class::$databaseTable . '.' . $class::$databasePrefix . $container->_sortBy;
|
||||
}
|
||||
if ( !$this->filter )
|
||||
{
|
||||
$this->filter = $container->_filter;
|
||||
}
|
||||
|
||||
if ( $this->includeHiddenContent === NULL )
|
||||
if ( $this->includeHiddenContent === \IPS\Content\Hideable::FILTER_AUTOMATIC )
|
||||
{
|
||||
$this->includeHiddenContent = $class::canViewHiddenItems( \IPS\Member::loggedIn(), $container );
|
||||
}
|
||||
@@ -153,9 +161,11 @@ class _Content extends Table
|
||||
\IPS\Output::i()->breadcrumb[] = array( NULL, $container->_title );
|
||||
|
||||
/* Meta tags */
|
||||
\IPS\Output::i()->title = ( $this->page > 1 ) ? \IPS\Member::loggedIn()->language()->addToStack( 'title_with_page_number', FALSE, array( 'sprintf' => array( $container->_title, $this->page ) ) ) : $container->_title;
|
||||
\IPS\Output::i()->metaTags['title'] = $container->_title;
|
||||
\IPS\Output::i()->title = ( $this->page > 1 ) ? \IPS\Member::loggedIn()->language()->addToStack( 'title_with_page_number', FALSE, array( 'sprintf' => array( $container->metaTitle(), $this->page ) ) ) : $container->metaTitle();
|
||||
\IPS\Output::i()->metaTags['title'] = $container->metaTitle();
|
||||
\IPS\Output::i()->metaTags['description'] = $container->metaDescription();
|
||||
\IPS\Output::i()->metaTags['og:title'] = $container->metaTitle();
|
||||
\IPS\Output::i()->metaTags['og:description'] = $container->metaDescription();
|
||||
\IPS\Output::i()->linkTags['canonical'] = (string) $baseUrl;
|
||||
}
|
||||
|
||||
@@ -221,16 +231,28 @@ class _Content extends Table
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->sortBy = in_array( $this->sortBy, $this->sortOptions ) ? $this->sortBy :
|
||||
( array_key_exists( $this->sortBy, $this->sortOptions) ? $this->sortOptions[ $this->sortBy ] : $defaultSort );
|
||||
|
||||
if ( ! mb_stristr( $this->sortBy, '`' ) )
|
||||
{
|
||||
$compareSortBy = $this->sortBy;
|
||||
$lookFor = $class::$databaseTable . '.' . $class::$databasePrefix;
|
||||
|
||||
if ( mb_substr( $this->sortBy, 0, mb_strlen( $lookFor ) ) === $lookFor )
|
||||
{
|
||||
$compareSortBy = mb_substr( $this->sortBy, mb_strlen( $lookFor ) );
|
||||
}
|
||||
|
||||
$this->sortBy = in_array( $compareSortBy, $this->sortOptions ) ? $this->sortBy :
|
||||
( array_key_exists( $compareSortBy, $this->sortOptions ) ? $this->sortOptions[ $compareSortBy ] : $defaultSort );
|
||||
}
|
||||
|
||||
/* Callback? */
|
||||
if ( $this->advancedSearchCallback and !empty( $advancedSearchValues ) )
|
||||
{
|
||||
$obj = $this;
|
||||
call_user_func( $this->advancedSearchCallback, $obj, $advancedSearchValues );
|
||||
}
|
||||
|
||||
|
||||
/* What are we sorting by? */
|
||||
$sortBy = $this->sortBy . ' ' . ( mb_strtolower( $this->sortDirection ) == 'asc' ? 'asc' : 'desc' );
|
||||
if ( in_array( 'IPS\Content\Pinnable', class_implements( $class ) ) and $this->honorPinned )
|
||||
@@ -245,10 +267,10 @@ class _Content extends Table
|
||||
{
|
||||
$where[] = is_array( $this->filters[ $this->filter ] ) ? $this->filters[ $this->filter ] : array( $this->filters[ $this->filter ] );
|
||||
}
|
||||
|
||||
|
||||
/* Get results */
|
||||
$this->count = $class::getItemsWithPermission( $where, $sortBy, NULL, $this->permCheck, $this->includeHiddenContent, 0, NULL, $this->joinContainer, $this->joinComments, $this->joinReviews, TRUE, $this->joins );
|
||||
$it = $class::getItemsWithPermission( $where, $sortBy, array( ( $this->limit * ( $this->page - 1 ) ), $this->limit ), $this->permCheck, $this->includeHiddenContent, 0, NULL, $this->joinContainer, $this->joinComments, $this->joinReviews, FALSE, $this->joins );
|
||||
$this->count = $class::getItemsWithPermission( $where, $sortBy, NULL, $this->permCheck, $this->includeHiddenContent, 0, NULL, $this->joinContainer, $this->joinComments, $this->joinReviews, TRUE, $this->joins, FALSE, TRUE, TRUE, TRUE, $this->showMovedLinks );
|
||||
$it = $class::getItemsWithPermission( $where, $sortBy, array( ( $this->limit * ( $this->page - 1 ) ), $this->limit ), $this->permCheck, $this->includeHiddenContent, 0, NULL, $this->joinContainer, $this->joinComments, $this->joinReviews, FALSE, $this->joins, FALSE, TRUE, TRUE, TRUE, $this->showMovedLinks );
|
||||
$this->pages = ceil( $this->count / $this->limit );
|
||||
$rows = iterator_to_array( $it );
|
||||
|
||||
@@ -385,9 +407,17 @@ class _Content extends Table
|
||||
{
|
||||
$return[] = 'unhide';
|
||||
}
|
||||
elseif ( $item->hidden() === 1 and $item->canUnhide() )
|
||||
elseif ( $item->hidden() === 1 )
|
||||
{
|
||||
$return[] = 'approve';
|
||||
if( $item->canUnhide() )
|
||||
{
|
||||
$return[] = 'approve';
|
||||
}
|
||||
|
||||
if( $item->canHide() )
|
||||
{
|
||||
$return[] = 'hide';
|
||||
}
|
||||
}
|
||||
elseif ( $item->canHide() )
|
||||
{
|
||||
@@ -455,6 +485,14 @@ class _Content extends Table
|
||||
*/
|
||||
protected function multimod()
|
||||
{
|
||||
\IPS\Session::i()->csrfCheck();
|
||||
|
||||
/* Basic check that we selected something */
|
||||
if( !isset( \IPS\Request::i()->moderate ) OR empty( \IPS\Request::i()->moderate ) )
|
||||
{
|
||||
\IPS\Output::i()->error( 'nothing_mm_selected', '1S330/1', 403, '' );
|
||||
}
|
||||
|
||||
$class = $this->class;
|
||||
$params = array();
|
||||
|
||||
@@ -568,6 +606,15 @@ class _Content extends Table
|
||||
$form->hiddenValues['modaction'] = 'merge';
|
||||
$form->hiddenValues['moderate'] = \IPS\Request::i()->moderate;
|
||||
$form->add( new \IPS\Helpers\Form\Radio( 'merge_master', NULL, TRUE, array( 'options' => $options, 'descriptions' => $descriptions ) ) );
|
||||
if ( isset( $class::$databaseColumnMap['moved_to'] ) )
|
||||
{
|
||||
$form->add( new \IPS\Helpers\Form\Checkbox( 'move_keep_link' ) );
|
||||
|
||||
if ( \IPS\Settings::i()->topic_redirect_prune )
|
||||
{
|
||||
\IPS\Member::loggedIn()->language()->words['move_keep_link_desc'] = \IPS\Member::loggedIn()->language()->addToStack( '_move_keep_link_desc', FALSE, array( 'pluralize' => array( \IPS\Settings::i()->topic_redirect_prune ) ) );
|
||||
}
|
||||
}
|
||||
if ( $values = $form->values() )
|
||||
{
|
||||
$otherItems = array();
|
||||
@@ -579,7 +626,7 @@ class _Content extends Table
|
||||
}
|
||||
}
|
||||
|
||||
$class::load( $values['merge_master'] )->mergeIn( $otherItems );
|
||||
$class::load( $values['merge_master'] )->mergeIn( $otherItems, isset( $values['move_keep_link'] ) ? $values['move_keep_link'] : FALSE );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Table Builder using an array datasource
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -38,6 +38,11 @@ class _Custom extends Table
|
||||
*/
|
||||
public $count = 0;
|
||||
|
||||
/**
|
||||
* Number of pages
|
||||
*/
|
||||
public $pages = NULL;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -47,6 +52,7 @@ class _Custom extends Table
|
||||
public function __construct( $dataSource, \IPS\Http\Url $baseUrl )
|
||||
{
|
||||
$this->dataSource = $dataSource;
|
||||
$this->count = count( $this->dataSource );
|
||||
|
||||
return parent::__construct( $baseUrl );
|
||||
}
|
||||
@@ -60,9 +66,10 @@ class _Custom extends Table
|
||||
*/
|
||||
public function getRows( $advancedSearchValues )
|
||||
{
|
||||
/* Sort out paging */
|
||||
$this->count = count( $this->dataSource );
|
||||
$this->pages = ceil( $this->count / $this->limit );
|
||||
if ( ! $this->pages )
|
||||
{
|
||||
$this->pages = ceil( $this->count / $this->limit );
|
||||
}
|
||||
|
||||
/* Get them */
|
||||
$rows = array();
|
||||
@@ -86,23 +93,17 @@ class _Custom extends Table
|
||||
/* Add it to the array */
|
||||
$rows[ $i ] = $row;
|
||||
}
|
||||
|
||||
|
||||
/* Quicksearch */
|
||||
if ( $this->quickSearch !== NULL and \IPS\Request::i()->quicksearch )
|
||||
{
|
||||
$quickSearchColumn = $this->quickSearch;
|
||||
$rows = array_filter( $rows, is_callable( $this->quickSearch ) ? $this->quickSearch : function( $row ) use ( $quickSearchColumn )
|
||||
{
|
||||
return mb_strpos( $row[ $quickSearchColumn ], trim( \IPS\Request::i()->quicksearch ) ) !== FALSE;
|
||||
return mb_strpos( mb_strtolower( $row[ $quickSearchColumn ] ), mb_strtolower( trim( \IPS\Request::i()->quicksearch ) ) ) !== FALSE;
|
||||
} );
|
||||
}
|
||||
|
||||
/* Limit */
|
||||
if ( $this->limit and $this->count > $this->limit )
|
||||
{
|
||||
$rows = array_slice( $rows, ( $this->limit * ( $this->page - 1 ) ), $this->limit );
|
||||
}
|
||||
|
||||
|
||||
/* Do we need to sort? */
|
||||
if( !empty( $rows ) and $this->sortBy and isset( $rows[ key( $rows ) ][ $this->sortBy ] ) )
|
||||
{
|
||||
@@ -120,6 +121,12 @@ class _Custom extends Table
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Limit */
|
||||
if ( $this->limit and $this->count > $this->limit )
|
||||
{
|
||||
$rows = array_slice( $rows, ( $this->limit * ( $this->page - 1 ) ), $this->limit );
|
||||
}
|
||||
|
||||
/* Apply parsers */
|
||||
foreach( $rows as $i => $row )
|
||||
|
||||
+100
-47
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Table Builder using a database table datasource
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -58,10 +58,15 @@ class _Db extends Table
|
||||
*/
|
||||
public $keyField = NULL;
|
||||
|
||||
/**
|
||||
* @brief Restrict select columns to only those listed - useful when grouping
|
||||
*/
|
||||
public $onlySelected = NULL;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $table Database table
|
||||
* @param array|string $table Database table
|
||||
* @param \IPS\Http\Url $baseUrl Base URL
|
||||
* @param array|null $where WHERE clause
|
||||
* @param string|null $group GROUP clause
|
||||
@@ -106,7 +111,7 @@ class _Db extends Table
|
||||
$columns = is_array( $this->quickSearch ) ? $this->quickSearch[0] : $this->quickSearch;
|
||||
$columns = is_array( $columns ) ? $columns : array( $columns );
|
||||
|
||||
$_where = '';
|
||||
$_where = array();
|
||||
foreach ( $columns as $c )
|
||||
{
|
||||
$_where[] = "LOWER(`{$c}`) LIKE CONCAT( '%', ?, '%' )";
|
||||
@@ -121,7 +126,7 @@ class _Db extends Table
|
||||
{
|
||||
foreach ( $advancedSearchValues as $k => $v )
|
||||
{
|
||||
if ( isset( $this->advancedSearch[ $k ] ) )
|
||||
if ( isset( $this->advancedSearch[ $k ] ) AND $v !== '' )
|
||||
{
|
||||
$type = $this->advancedSearch[ $k ];
|
||||
|
||||
@@ -151,14 +156,39 @@ class _Db extends Table
|
||||
case SEARCH_CONTAINS_TEXT:
|
||||
$where[] = array( "{$k} LIKE ?", '%' . $v . '%' );
|
||||
break;
|
||||
|
||||
case SEARCH_QUERY_TEXT:
|
||||
switch ( $v[0] )
|
||||
{
|
||||
case 'c':
|
||||
$where[] = array( "{$k} LIKE ?", '%' . $v[1] . '%' );
|
||||
break;
|
||||
case 'bw':
|
||||
$where[] = array( "{$k} LIKE ?", $v[1] . '%' );
|
||||
break;
|
||||
case 'eq':
|
||||
$where[] = array( "{$k}=?", $v[1] );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SEARCH_DATE_RANGE:
|
||||
$timezone = ( \IPS\Member::loggedIn()->timezone ? new \DateTimeZone( \IPS\Member::loggedIn()->timezone ) : NULL );
|
||||
|
||||
if ( $v['start'] )
|
||||
{
|
||||
if( !( $v['start'] instanceof \IPS\DateTime ) )
|
||||
{
|
||||
$v['start'] = new \IPS\DateTime( $v['start'], $timezone );
|
||||
}
|
||||
|
||||
$where[] = array( "{$k}>?", $v['start']->getTimestamp() );
|
||||
}
|
||||
if ( $v['end'] )
|
||||
{
|
||||
if( !( $v['end'] instanceof \IPS\DateTime ) )
|
||||
{
|
||||
$v['end'] = new \IPS\DateTime( $v['end'], $timezone );
|
||||
}
|
||||
|
||||
$where[] = array( "{$k}<?", $v['end']->getTimestamp() );
|
||||
}
|
||||
break;
|
||||
@@ -175,7 +205,10 @@ class _Db extends Table
|
||||
break;
|
||||
|
||||
case SEARCH_MEMBER:
|
||||
$where[] = array( "{$k}=?", $v->member_id );
|
||||
if( $v instanceof \IPS\Member )
|
||||
{
|
||||
$where[] = array( "{$k}=?", $v->member_id );
|
||||
}
|
||||
break;
|
||||
|
||||
case SEARCH_NODE:
|
||||
@@ -211,6 +244,7 @@ class _Db extends Table
|
||||
break;
|
||||
|
||||
case SEARCH_NUMERIC:
|
||||
case SEARCH_NUMERIC_TEXT:
|
||||
switch ( $v[0] )
|
||||
{
|
||||
case 'gt':
|
||||
@@ -230,40 +264,55 @@ class _Db extends Table
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unset( $advancedSearchValues[ $k ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$selects = $this->selects;
|
||||
if ( count( $this->joins ) )
|
||||
|
||||
if( $this->onlySelected !== NULL )
|
||||
{
|
||||
foreach( $this->joins as $join )
|
||||
foreach( $this->onlySelected as $column )
|
||||
{
|
||||
if ( isset( $join['select'] ) )
|
||||
$selects[] = $column;
|
||||
}
|
||||
|
||||
if( $this->group !== NULL )
|
||||
{
|
||||
$this->group = is_array( $this->group ) ? $this->group : array( $this->group );
|
||||
$this->group = array_unique( array_merge( $this->group, $this->onlySelected ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( count( $this->joins ) )
|
||||
{
|
||||
foreach( $this->joins as $join )
|
||||
{
|
||||
$selects[] = $join['select'];
|
||||
if ( isset( $join['select'] ) )
|
||||
{
|
||||
$selects[] = $join['select'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Count results (for pagination) */
|
||||
if ( $this->group === null )
|
||||
$count = \IPS\Db::i()->select( 'count(*)', $this->table, $where );
|
||||
if ( count( $this->joins ) )
|
||||
{
|
||||
$count = \IPS\Db::i()->select( 'count(*)', $this->table, $where );
|
||||
if ( count( $this->joins ) )
|
||||
foreach( $this->joins as $join )
|
||||
{
|
||||
foreach( $this->joins as $join )
|
||||
{
|
||||
$count->join( $join['from'], ( isset( $join['where'] ) ? $join['where'] : null ), 'LEFT' );
|
||||
}
|
||||
$count->join( $join['from'], ( isset( $join['where'] ) ? $join['where'] : null ), ( isset( $join['type'] ) ) ? $join['type'] : 'LEFT' );
|
||||
}
|
||||
$count = $count->first();
|
||||
}
|
||||
$count = $count->first();
|
||||
|
||||
$query = \IPS\Db::i()->select( '*' . ( count( $selects ) ? ', ' . implode( ', ', $selects ) : '' ), $this->table, $where, NULL, array( 0, 1 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
$query = \IPS\Db::i()->select( '*, count(DISTINCT( '.$this->table.'.' . $this->group . ')) as _count' . ( count( $selects ) ? ', ' . implode( ', ', $selects ) : '' ), $this->table, $where, NULL, array( 0, 1 ) );
|
||||
}
|
||||
/* Now get column headers */
|
||||
$query = \IPS\Db::i()->select( $this->onlySelected ? implode( ', ', $selects ) : '*', $this->table, $where, NULL, array( 0, 1 ), $this->group );
|
||||
|
||||
if ( count( $this->joins ) )
|
||||
{
|
||||
@@ -277,23 +326,14 @@ class _Db extends Table
|
||||
{
|
||||
$query->forceIndex( $this->index );
|
||||
}
|
||||
|
||||
if ( $this->group === null )
|
||||
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
$results = $query->first();
|
||||
}
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
$results = array();
|
||||
}
|
||||
$results = $query->first();
|
||||
}
|
||||
else
|
||||
catch( \UnderflowException $e )
|
||||
{
|
||||
$count = $query->first();
|
||||
$results = $count;
|
||||
$count = $count['_count'];
|
||||
$results = array();
|
||||
}
|
||||
|
||||
$this->pages = ceil( $count / $this->limit );
|
||||
@@ -304,15 +344,20 @@ class _Db extends Table
|
||||
{
|
||||
$orderBy = implode( ',', array_map( function( $v )
|
||||
{
|
||||
/* This gives you something like "g`.`g_id" which is then turned into "`g`.`g_id`" below */
|
||||
$v = str_replace( '.', "`.`", $v );
|
||||
|
||||
if ( ! mb_strstr( trim( $v ), ' ' ) )
|
||||
{
|
||||
return '`' . trim( $v ) . '`';
|
||||
$return = ( isset( $this->advancedSearch[$v] ) and $this->advancedSearch[$v] == SEARCH_NUMERIC_TEXT ) ? 'LENGTH(' . '`' . trim( $v ) . '`' . ') ' . $this->sortDirection . ', ' . '`' . trim( $v ) . '` ' : '`' . trim( $v ) . '` ';
|
||||
}
|
||||
else
|
||||
{
|
||||
list( $field, $direction ) = explode( ' ', $v );
|
||||
return '`' . trim( $field ) . '` ' . $direction;
|
||||
$return = ( isset( $this->advancedSearch[$v] ) and $this->advancedSearch[$v] == SEARCH_NUMERIC_TEXT ) ? 'LENGTH(' . '`' . trim( $field ) . '`' . ') ' . mb_strtolower( $direction ) == 'asc' ? 'asc' : 'desc' . ', ' . '`' . trim( $field ) . '` ' : '`' . trim( $field ) . '` ';
|
||||
$return .= ( mb_strtolower( $direction ) == 'asc' ? 'asc' : 'desc' );
|
||||
}
|
||||
return $return;
|
||||
}, explode( ',', $this->sortBy ) ) );
|
||||
|
||||
$orderBy .= $this->sortDirection == 'asc' ? ' asc' : ' desc';
|
||||
@@ -321,13 +366,14 @@ class _Db extends Table
|
||||
/* Run query */
|
||||
$rows = array();
|
||||
$select = \IPS\Db::i()->select(
|
||||
( count( $selects ) ) ? $this->table . '.*, ' . implode( ', ', $selects ) : '*',
|
||||
$this->onlySelected ? implode( ', ', $selects ) : ( ( count( $selects ) ) ? $this->table . '.*, ' . implode( ', ', $selects ) : '*' ),
|
||||
$this->table,
|
||||
$where,
|
||||
$orderBy,
|
||||
array( ( $this->limit * ( $this->page - 1 ) ), $this->limit ), $this->group
|
||||
array( ( $this->limit * ( $this->page - 1 ) ), $this->limit ),
|
||||
$this->group
|
||||
);
|
||||
|
||||
|
||||
if ( $this->index )
|
||||
{
|
||||
$select->forceIndex( $this->index );
|
||||
@@ -337,14 +383,14 @@ class _Db extends Table
|
||||
{
|
||||
foreach( $this->joins as $join )
|
||||
{
|
||||
$select->join( $join['from'], $join['where'], 'LEFT' );
|
||||
$select->join( $join['from'], $join['where'], ( isset( $join['type'] ) ) ? $join['type'] : 'LEFT' );
|
||||
}
|
||||
}
|
||||
if ( $this->keyField !== NULL )
|
||||
{
|
||||
$select->setKeyField( $this->keyField );
|
||||
}
|
||||
|
||||
|
||||
foreach ( $select as $rowId => $row )
|
||||
{
|
||||
/* Add in any 'custom' fields */
|
||||
@@ -437,6 +483,13 @@ class _Db extends Table
|
||||
{
|
||||
foreach( explode( ',', $this->sortBy ) as $field )
|
||||
{
|
||||
/* Get rid of table alias if there is one */
|
||||
if( mb_strpos( $field, '.' ) !== FALSE )
|
||||
{
|
||||
$field = explode( '.', $field );
|
||||
$field = $field[1];
|
||||
}
|
||||
|
||||
$field = trim($field);
|
||||
|
||||
if ( mb_strstr( $field, ' ' ) )
|
||||
@@ -452,7 +505,7 @@ class _Db extends Table
|
||||
|
||||
return true;
|
||||
}
|
||||
elseif ( array_key_exists( $this->sortBy, $count ) )
|
||||
elseif ( array_key_exists( preg_replace( "/^.+?\.(.+?)$/", "$1", $this->sortBy ), $count ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Table Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 18 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -28,7 +28,8 @@ const SEARCH_NUMERIC = 6;
|
||||
const SEARCH_BOOL = 7;
|
||||
const HEADER = 8;
|
||||
const SEARCH_RADIO = 9;
|
||||
|
||||
const SEARCH_NUMERIC_TEXT = 10;
|
||||
const SEARCH_QUERY_TEXT = 11;
|
||||
/**
|
||||
* List Table Builder
|
||||
*/
|
||||
@@ -306,6 +307,28 @@ abstract class _Table
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column without a table prefix
|
||||
* For example, we might allow array( 'last_post', 'author' ) but the $this->sortBy property is often set as "app_table.last_post" meaning
|
||||
* that the filter drop down doesn't show the selected value correctly.
|
||||
*
|
||||
* @param string $property Property we are updating
|
||||
* @param mixed $value Value being set
|
||||
* @return void
|
||||
*/
|
||||
public function getSortByColumn()
|
||||
{
|
||||
if ( mb_strpos( $this->sortBy, '.' ) )
|
||||
{
|
||||
list( $table, $column ) = explode( '.', $this->sortBy );
|
||||
return $column;
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->sortBy;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build Advanced Search Form
|
||||
*
|
||||
@@ -337,6 +360,21 @@ abstract class _Table
|
||||
$form->add( new \IPS\Helpers\Form\Text( $this->langPrefix . $k, NULL, FALSE, $options ) );
|
||||
break;
|
||||
|
||||
case SEARCH_QUERY_TEXT:
|
||||
$form->add( new \IPS\Helpers\Form\Custom( $this->langPrefix . $k, NULL, FALSE, array(
|
||||
'getHtml' => function( $element )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'forms', 'core' )->select( "{$element->name}[0]", $element->value[0], $element->required, array(
|
||||
'c' => \IPS\Member::loggedIn()->language()->addToStack('contains'),
|
||||
'bw' => \IPS\Member::loggedIn()->language()->addToStack('begins_with'),
|
||||
'eq' => \IPS\Member::loggedIn()->language()->addToStack('exactly'),
|
||||
) )
|
||||
. ' '
|
||||
. \IPS\Theme::i()->getTemplate( 'forms', 'core', 'global' )->text( "{$element->name}[1]", 'text', $element->value[1], $element->required, NULL, FALSE, NULL, NULL, NULL, '', NULL, FALSE, NULL, array(), array(), array( $element->name . '-qty' ) );
|
||||
}
|
||||
) ) );
|
||||
break;
|
||||
|
||||
case SEARCH_DATE_RANGE:
|
||||
$form->add( new \IPS\Helpers\Form\DateRange( $this->langPrefix . $k, array( 'start' => '', 'end' => '' ), FALSE, $options ) );
|
||||
break;
|
||||
@@ -358,6 +396,7 @@ abstract class _Table
|
||||
break;
|
||||
|
||||
case SEARCH_NUMERIC:
|
||||
case SEARCH_NUMERIC_TEXT:
|
||||
$form->add( new \IPS\Helpers\Form\Custom( $this->langPrefix . $k, NULL, FALSE, array(
|
||||
'getHtml' => function( $element )
|
||||
{
|
||||
@@ -411,6 +450,9 @@ abstract class _Table
|
||||
/* Are we displaying the advanced search form? */
|
||||
if ( \IPS\Request::i()->advancedSearchForm )
|
||||
{
|
||||
/* If we are showing just the advanced search form, send a noindex meta tag */
|
||||
\IPS\Output::i()->metaTags['robots'] = 'noindex';
|
||||
|
||||
return (string) $this->advancedSearch();
|
||||
}
|
||||
/* No? Try getting some values then */
|
||||
@@ -422,7 +464,7 @@ abstract class _Table
|
||||
|
||||
/* Get rows */
|
||||
$rows = $this->getRows( $advancedSearchValues );
|
||||
|
||||
|
||||
/* Check we're on a valid page (must come after getRows() as this is where $this->pages is set) */
|
||||
if ( $this->page )
|
||||
{
|
||||
@@ -435,9 +477,15 @@ abstract class _Table
|
||||
/* Add link tags */
|
||||
if ( $this->page != 1 )
|
||||
{
|
||||
\IPS\Output::i()->linkTags['canonical'] = (string) $this->baseUrl->setQueryString( $this->paginationKey, $this->page );
|
||||
\IPS\Output::i()->linkTags['first'] = (string) $this->baseUrl->setQueryString( $this->paginationKey, 1 );
|
||||
\IPS\Output::i()->linkTags['prev'] = (string) $this->baseUrl->setQueryString( $this->paginationKey, $this->page - 1 );
|
||||
}
|
||||
/* If we literally requested ?page=1 add canonical tag to get rid of the page query string param */
|
||||
elseif( isset( $this->baseUrl->data[ \IPS\Http\Url::COMPONENT_QUERY ][ $this->paginationKey ] ) )
|
||||
{
|
||||
\IPS\Output::i()->linkTags['canonical'] = (string) $this->baseUrl->stripQueryString( $this->paginationKey );
|
||||
}
|
||||
if ( $this->pages > $this->page )
|
||||
{
|
||||
\IPS\Output::i()->linkTags['next'] = (string) $this->baseUrl->setQueryString( $this->paginationKey, $this->page + 1 );
|
||||
@@ -476,6 +524,10 @@ abstract class _Table
|
||||
{
|
||||
\IPS\IPS::exceptionHandler( $e );
|
||||
}
|
||||
catch ( \Throwable $e )
|
||||
{
|
||||
\IPS\IPS::exceptionHandler( $e );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -558,7 +610,16 @@ abstract class _Table
|
||||
{
|
||||
if( !empty( $advancedSearchValues ) )
|
||||
{
|
||||
$headers = array_combine( array_merge( $this->include, array_keys( $advancedSearchValues ) ), array_merge( $this->include, array_keys( $advancedSearchValues ) ) );
|
||||
$headers = array_combine( $this->include, $this->include );
|
||||
|
||||
foreach ( $this->getRows( $advancedSearchValues ) as $row )
|
||||
{
|
||||
foreach ( array_keys( $row ) as $header )
|
||||
{
|
||||
$headers[ $header ] = $header;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -589,7 +650,7 @@ abstract class _Table
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the advanced search values
|
||||
*
|
||||
@@ -623,7 +684,7 @@ abstract class _Table
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $v )
|
||||
if ( $v !== NULL )
|
||||
{
|
||||
if( \IPS\Request::i()->isAjax() )
|
||||
{
|
||||
@@ -638,7 +699,10 @@ abstract class _Table
|
||||
}
|
||||
else
|
||||
{
|
||||
$v = urldecode( $v );
|
||||
if ( ! is_object( $v ) )
|
||||
{
|
||||
$v = urldecode( $v );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Tree Builder
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 20 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -158,5 +158,9 @@ class _Tree
|
||||
{
|
||||
\IPS\IPS::exceptionHandler( $e );
|
||||
}
|
||||
catch ( \Throwable $e )
|
||||
{
|
||||
\IPS\IPS::exceptionHandler( $e );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief Wizard Helper
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 25 Jul 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -152,15 +152,16 @@ class _Wizard
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get it's output */
|
||||
$output = call_user_func( $this->steps[ $activeStep ], $data );
|
||||
while ( is_array( $output ) )
|
||||
{
|
||||
$data = array_merge( $data, $output );
|
||||
|
||||
|
||||
$nextStep = NULL;
|
||||
$foundJustDone = FALSE;
|
||||
|
||||
|
||||
foreach ( $stepKeys as $key )
|
||||
{
|
||||
if ( $foundJustDone )
|
||||
@@ -173,14 +174,14 @@ class _Wizard
|
||||
$foundJustDone = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Update the Wizard session data */
|
||||
$_SESSION[ 'wizard-' . md5( $this->baseUrl ) . '-step' ] = $activeStep;
|
||||
$_SESSION[ 'wizard-' . md5( $this->baseUrl ) . '-data' ] = $data;
|
||||
|
||||
$output = call_user_func( $this->steps[ $activeStep ], $data );
|
||||
}
|
||||
|
||||
/* Save the data */
|
||||
$_SESSION[ 'wizard-' . md5( $this->baseUrl ) . '-data' ] = $data;
|
||||
|
||||
|
||||
/* Display */
|
||||
return call_user_func( $this->template, $stepKeys, $activeStep, $output, $this->baseUrl, $this->showSteps );
|
||||
}
|
||||
@@ -188,5 +189,9 @@ class _Wizard
|
||||
{
|
||||
\IPS\IPS::exceptionHandler( $e );
|
||||
}
|
||||
catch ( \Throwable $e )
|
||||
{
|
||||
\IPS\IPS::exceptionHandler( $e );
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user