Version 4.3.0

This commit is contained in:
Neo committed 2025-12-19 05:47:12 -08:00
1 parent 96997ddd8e
commit fe1acf984a
1349 files changed
+116159 -67711

No files matched your search

+236 -126
View File
@@ -255,7 +255,7 @@ class _Theme extends \IPS\Node\Model
static::themes();
/* Add in the default theme properties (_data array, etc) */
$default = ( isset( static::$multitons[1] ) ) ? static::$multitons[1] : reset( static::$multitons );
$default = ( isset( static::$multitons[ \IPS\DEFAULT_THEME_ID ] ) ) ? static::$multitons[ \IPS\DEFAULT_THEME_ID ] : reset( static::$multitons );
foreach( $default as $k => $v )
{
@@ -629,7 +629,7 @@ class _Theme extends \IPS\Node\Model
if ( $location === 'interface' )
{
return rtrim( \IPS\Http\Url::baseUrl( \IPS\Http\Url::PROTOCOL_RELATIVE ), '/' ) . "/applications/{$app}/interface{$path}{$name}";
return \IPS\Http\Url::internal( "applications/{$app}/interface{$path}{$name}", 'interface', NULL, array(), \IPS\Http\Url::PROTOCOL_RELATIVE );
}
if ( in_array( $key, array_keys( $this->resource_map ) ) )
@@ -662,7 +662,7 @@ class _Theme extends \IPS\Node\Model
return NULL;
}
$flagKey = 'resource_compiling_' . $this->_id . '_' . md5( $app . '_' . $location . '_' . $path );
$flagKey = 'resource_compiling_' . $this->_id . '_' . md5( $key );
if ( static::checkLock( $flagKey ) )
{
return NULL;
@@ -744,8 +744,23 @@ class _Theme extends \IPS\Node\Model
}
else
{
/* We'll compile it now, but let datastore serve the template this time round */
$this->compileTemplates( $app, $location, $group );
/* If it exists in datastore, use that to write the value */
if ( isset( \IPS\Data\Store::i()->$key ) )
{
try
{
$cache->set( str_replace( 'namespace IPS\Theme;', 'namespace IPS\Theme\Cache;', \IPS\Data\Store::i()->$key ) );
}
catch( \RuntimeException $e )
{
/* Should we log, ignore or collect failures to notify admin? */
}
}
else
{
/* We'll compile it now, but let datastore serve the template this time round */
$this->compileTemplates( $app, $location, $group );
}
}
}
@@ -808,7 +823,7 @@ class _Theme extends \IPS\Node\Model
{
if ( @eval( $compiledGroup ) === FALSE )
{
throw new \UnexpectedValueException;
throw new \IPS\Theme\TemplateException( 'Invalid Template', 1000, NULL, array( 'group' => $group, 'app' => $app, 'location' => $location ), $this );
}
}
catch ( \ParseError $e )
@@ -843,7 +858,7 @@ class _Theme extends \IPS\Node\Model
{
if ( file_exists( \IPS\ROOT_PATH . '/' . $data['file'] ) )
{
if ( class_exists( "{$namespace}\\{$data['class']}", FALSE ) )
if ( class_exists( "{$namespace}\\" . $data['class'], FALSE ) )
{
$class = $data['class'];
continue;
@@ -970,6 +985,9 @@ class _Theme extends \IPS\Node\Model
$this->editor_skin = 'ips';
}
/* Re-calculate customised flag */
$this->customized = $this->isCustomized();
parent::save();
unset( \IPS\Data\Store::i()->themes );
@@ -1072,12 +1090,7 @@ class _Theme extends \IPS\Node\Model
*/
protected function get__description()
{
if( $this->author_name or $this->version )
{
return \IPS\Theme::i()->getTemplate( 'customization', 'core' )->themeDescription( $this->author_name, $this->author_url, $this->version );
}
return NULL;
return \IPS\Theme::i()->getTemplate( 'customization', 'core' )->themeDescription( $this );
}
/**
@@ -1224,9 +1237,6 @@ class _Theme extends \IPS\Node\Model
case 'template_set_id':
$name = $setId;
break;
case 'template_unique_key':
$name = "MD5( CONCAT( {$setId}, ';', template_app, ';', template_location, ';', template_group, ';', LOWER(template_name) ) )";
break;
}
}, $this->id );
@@ -1240,9 +1250,6 @@ class _Theme extends \IPS\Node\Model
case 'css_set_id':
$name = $setId;
break;
case 'css_unique_key':
$name = "MD5( CONCAT( {$setId}, ';', css_app, ';', css_location, ';', css_path, ';', css_name ) )";
break;
}
}, $this->id );
@@ -1295,6 +1302,34 @@ class _Theme extends \IPS\Node\Model
\IPS\Session::i()->log( 'acplogs__themeset_created', array( sprintf( \IPS\Member::loggedIn()->language()->get( 'theme_clone_copy_of' ), \IPS\Member::loggedIn()->language()->get( 'core_theme_set_title_' . $originalId ) ) => FALSE ) );
}
/**
* [Node] Does the currently logged in user have permission to delete this node?
*
* @return bool
*/
public function canDelete()
{
if ( \IPS\IN_DEV AND $this->_id == \IPS\DEFAULT_THEME_ID )
{
return FALSE;
}
if( $this->is_default OR $this->is_acp_default )
{
return FALSE;
}
foreach( $this->children( NULL ) as $childTheme )
{
if( $childTheme->is_default OR $childTheme->is_acp_default )
{
return FALSE;
}
}
return parent::canDelete();
}
/**
* [Node] Delete the theme set
@@ -1303,7 +1338,7 @@ class _Theme extends \IPS\Node\Model
*/
public function delete()
{
if ( \IPS\IN_DEV AND $this->_id == 1 )
if ( \IPS\IN_DEV AND $this->_id == \IPS\DEFAULT_THEME_ID )
{
\IPS\Output::i()->error( 'theme_error_not_available_in_dev', '2S140/1', 403, '' );
}
@@ -1357,8 +1392,6 @@ class _Theme extends \IPS\Node\Model
\IPS\Db::i()->update( 'core_members', array( 'skin' => 0 ), array('skin=?', $this->_id ) );
\IPS\Db::i()->delete( 'core_theme_settings_fields', array( 'sc_set_id=?', $this->_id ) );
\IPS\Session::i()->log( 'acplogs__themeset_delete', array( "core_theme_set_title_{$this->_id}" => true ) );
parent::delete();
unset( \IPS\Data\Store::i()->themes );
@@ -1575,7 +1608,7 @@ class _Theme extends \IPS\Node\Model
{
$form->addTab( 'theme_custom_tab_' . $tabKey );
if ( \IPS\IN_DEV AND $this->_id === 1 )
if ( \IPS\IN_DEV AND $this->_id === \IPS\DEFAULT_THEME_ID )
{
$form->addHeader( 'core_theme_default_dev_reminder' );
}
@@ -1762,7 +1795,7 @@ class _Theme extends \IPS\Node\Model
'icon' => 'upload',
'title' => 'theme_set_import',
'link' => \IPS\Http\Url::internal( "app=core&module=customization&controller=themes&do=importForm&id={$this->_id}" ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('theme_set_import_title', FALSE, array( 'sprintf' => array( $this->name ) ) ) )
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('theme_set_import_title', FALSE, array( 'sprintf' => array( $this->_title ) ) ) )
);
$buttons['download'] = array(
@@ -1792,7 +1825,7 @@ class _Theme extends \IPS\Node\Model
);
}
if ( $this->id !== static::defaultTheme() )
if ( $this->canDelete() )
{
$buttons['delete'] = $parentButtons['delete'];
}
@@ -2054,15 +2087,15 @@ class _Theme extends \IPS\Node\Model
\IPS\Db::i()->delete( 'core_theme_settings_values', array( 'sv_id=?', $id ) );
\IPS\Db::i()->insert( 'core_theme_settings_values', array( 'sv_id' => $id, 'sv_value' => (string) $value ) );
if ( \IPS\IN_DEV AND $this->id === 1 )
if ( \IPS\IN_DEV AND $this->id === \IPS\DEFAULT_THEME_ID )
{
\IPS\Db::i()->update( 'core_theme_settings_fields', array( 'sc_default' => (string) $value ), array( 'sc_set_id=? and sc_id=?', 1, $id ) );
\IPS\Db::i()->update( 'core_theme_settings_fields', array( 'sc_default' => (string) $value ), array( 'sc_set_id=? and sc_id=?', \IPS\DEFAULT_THEME_ID, $id ) );
}
}
\IPS\Db::i()->update( 'core_themes', array( 'set_template_settings' => json_encode( $json ) ), array( 'set_id=?', $this->id ) );
if ( \IPS\IN_DEV AND $this->id === 1 )
if ( \IPS\IN_DEV AND $this->id === \IPS\DEFAULT_THEME_ID )
{
\IPS\Theme\Dev\Theme::writeThemeSettingsToDisk();
}
@@ -2107,16 +2140,6 @@ class _Theme extends \IPS\Node\Model
$this->copyLogosFromSet( $this->parent_id );
}
}
/* Log */
if ( $creating === FALSE )
{
\IPS\Session::i()->log( 'acplogs__themeset_updated', array( "core_theme_set_title_{$this->id}" => true ) );
}
else
{
\IPS\Session::i()->log( 'acplogs__themeset_created', array( "core_theme_set_title_{$this->id}" => true ) );
}
}
/**
@@ -2180,24 +2203,28 @@ class _Theme extends \IPS\Node\Model
$key = static::makeBuiltTemplateLookupHash($data['resource_app'], $data['resource_location'], $data['resource_path']) . '_' . $data['resource_name'];
if ( $data['resource_data'] )
{
$fileName = (string) \IPS\File::create( 'core_Theme', $key, $data['resource_data'], 'set_resources_' . $this->_id, FALSE, NULL, FALSE );
{
try
{
$fileName = (string) \IPS\File::create( 'core_Theme', $key, $data['resource_data'], 'set_resources_' . $this->_id, FALSE, NULL, FALSE );
\IPS\Db::i()->insert( 'core_theme_resources', array(
'resource_set_id' => $this->_id,
'resource_app' => $data['resource_app'],
'resource_location' => $data['resource_location'],
'resource_path' => $data['resource_path'],
'resource_name' => $data['resource_name'],
'resource_added' => time(),
'resource_filename' => $fileName,
'resource_data' => $data['resource_data'],
'resource_plugin' => isset( $data['resource_plugin'] ) ? $data['resource_plugin'] : NULL,
'resource_user_edited' => $data['resource_user_edited']
) );
\IPS\Db::i()->insert( 'core_theme_resources', array(
'resource_set_id' => $this->_id,
'resource_app' => $data['resource_app'],
'resource_location' => $data['resource_location'],
'resource_path' => $data['resource_path'],
'resource_name' => $data['resource_name'],
'resource_added' => time(),
'resource_filename' => $fileName,
'resource_data' => $data['resource_data'],
'resource_plugin' => isset( $data['resource_plugin'] ) ? $data['resource_plugin'] : NULL,
'resource_user_edited' => $data['resource_user_edited']
) );
$resourceMap[ $key ] = $fileName;
}
catch( \Exception $e ) { }
}
$resourceMap[ $key ] = $fileName;
}
/* Update theme map */
@@ -2502,7 +2529,7 @@ class _Theme extends \IPS\Node\Model
{
foreach ( \IPS\IPS::$hooks[ "\\IPS\\Theme\\class_{$app}_{$location}_{$group}" ] as $k => $data )
{
if ( !class_exists( "IPS\\Theme\\{$data['class']}_tmp", FALSE ) )
if ( !class_exists( "IPS\\Theme\\" . $data['class'] . "_tmp", FALSE ) )
{
/* Like code hooks, we should only attempt to load the files contents if it actually exists */
if ( file_exists( \IPS\ROOT_PATH . '/' . $data['file'] ) )
@@ -2511,7 +2538,7 @@ class _Theme extends \IPS\Node\Model
{
if ( eval( "namespace IPS\\Theme;\n\n" . str_replace( array( ' extends _HOOK_CLASS_', 'parent::hookData()' ), array( '_tmp', 'array()' ), file_get_contents( \IPS\ROOT_PATH . '/' . $data['file'] ) ) ) !== FALSE )
{
$class = "IPS\\Theme\\{$data['class']}_tmp";
$class = "IPS\\Theme\\" . $data['class'] . "_tmp";
$templateHooks = array_merge_recursive( $templateHooks, $class::hookData() );
}
}
@@ -2657,14 +2684,7 @@ EOF;
$children[] = $child->_id;
}
try
{
$css = \IPS\Db::i()->select( '*', 'core_theme_css', array( 'css_id=?', (int) $itemId ) )->first();
}
catch ( \UnderflowException $e )
{
throw new \UnderflowException;
}
$css = \IPS\Db::i()->select( '*', 'core_theme_css', array( 'css_id=?', (int) $itemId ) )->first();
static::deleteCompiledCss( $css['css_app'], $css['css_location'], $css['css_path'], $css['css_name'], $css['css_set_id'] );
@@ -2685,7 +2705,12 @@ EOF;
"css_app=? AND css_location=? AND css_path=? AND css_name=? AND css_set_id IN(" . implode( ',', $children ) . ")",
$css['css_app'], $css['css_location'], $css['css_path'], $css['css_name'] ) );
}
if ( ! empty( $css['css_set_id'] ) )
{
static::setThemeCustomized( $css['css_set_id'] );
}
$csses = $this->getRawCss( array( $css['css_app'] ), array( $css['css_location'] ), array( $css['css_path'] ) );
if ( isset( $csses[ $css['css_app'] ][ $css['css_location'] ][ $css['css_path'] ][ $css['css_name'] ] ) )
@@ -2720,14 +2745,7 @@ EOF;
/* Save */
if ( ! empty( $data['item_id'] ) )
{
try
{
$css = \IPS\Db::i()->select( '*', 'core_theme_css', array( 'css_id=?', (int) $data['item_id'] ) )->first();
}
catch ( \UnderflowException $e )
{
throw new \UnderflowException;
}
$css = \IPS\Db::i()->select( '*', 'core_theme_css', array( 'css_id=?', (int) $data['item_id'] ) )->first();
}
else
{
@@ -2758,14 +2776,11 @@ EOF;
'css_added_to' => $data['set_id'],
'css_plugin' => isset( $master['css_plugin'] ) ? $master['css_plugin'] : NULL );
}
/* Unique key */
$css['css_unique_key'] = md5( $data['set_id'] . ';' . $css['css_added_to'] . ';' . $css['css_app'] . ';' . $css['css_location'] . ';' . $css['css_path'] . ';' . $css['css_name'] );
/* Test to make sure CSS isn't broken */
try
{
static::makeProcessFunction( static::fixResourceTags( $data['content'], $css['css_location'] ), 'css_' . md5( uniqid() . time() ), '', FALSE, TRUE );
static::makeProcessFunction( static::fixResourceTags( $data['content'], $css['css_location'] ), 'css_' . md5( mt_rand() . time() ), '', FALSE, TRUE );
}
catch( \InvalidArgumentException $e )
{
@@ -2784,7 +2799,7 @@ EOF;
else
{
/* First modification in this css set */
$newCssId = \IPS\Db::i()->insert( 'core_theme_css', array( 'css_set_id' => $data['set_id'],
$newCssId = \IPS\Db::i()->replace( 'core_theme_css', array( 'css_set_id' => $data['set_id'],
'css_path' => $css['css_path'],
'css_location' => $css['css_location'],
'css_app' => $css['css_app'],
@@ -2795,13 +2810,14 @@ EOF;
'css_position' => intval( $css['css_position'] ),
'css_version' => \IPS\Theme::load( $data['set_id'] )->long_version,
'css_user_edited' => \IPS\Application::load( $css['css_app'] )->long_version,
'css_unique_key' => $css['css_unique_key'],
'css_updated' => time(),
'css_plugin' => isset( $css['css_plugin'] ) ? $css['css_plugin'] : NULL ) );
}
static::deleteCompiledCss( $css['css_app'], $css['css_location'], $css['css_path'], $css['css_name'], $data['set_id'] );
static::setThemeCustomized( $data['set_id'] );
return $newCssId;
}
@@ -2860,7 +2876,12 @@ EOF;
{
\IPS\Db::i()->delete( 'core_theme_templates', array( 'template_id=?', (int) $itemId ) );
}
if ( ! empty( $template['template_set_id'] ) )
{
static::setThemeCustomized( $template['template_set_id'] );
}
$templates = $this->getRawTemplates( array( $template['template_app'] ), array( $template['template_location'] ), array( $template['template_group'] ) );
if ( isset( $templates[ $template['template_app'] ][ $template['template_location'] ][ $template['template_group'] ][ $template['template_name'] ] ) )
@@ -2904,14 +2925,7 @@ EOF;
/* Save */
if ( $data['item_id'] )
{
try
{
$template = \IPS\Db::i()->select( '*', 'core_theme_templates', array( 'template_id=?', (int) $data['item_id'] ) )->first();
}
catch ( \UnderflowException $e )
{
throw new \UnderflowException;
}
$template = \IPS\Db::i()->select( '*', 'core_theme_templates', array( 'template_id=?', (int) $data['item_id'] ) )->first();
}
else
{
@@ -2924,13 +2938,10 @@ EOF;
'template_user_added' => 1 );
}
/* Unique key */
$template['template_unique_key'] = md5( $data['set_id'] . ';' . $template['template_added_to'] . ';' . $template['template_app'] . ';' . $template['template_location'] . ';' . $template['template_group'] . ';' . mb_strtolower( $template['template_name'] ) );
/* Test to make sure CSS isn't broken */
try
{
static::makeProcessFunction( $data['content'], 'template_' . md5( uniqid() . time() ), $data['variables'], TRUE, FALSE );
static::makeProcessFunction( $data['content'], 'template_' . md5( mt_rand() . time() ), $data['variables'], TRUE, FALSE );
}
/* PHP 5 */
catch( \InvalidArgumentException $e )
@@ -2965,9 +2976,6 @@ EOF;
}
else
{
/* First modification in this template set or new bit being added */
\IPS\Db::i()->delete( 'core_theme_templates', array( 'template_set_id=? and template_unique_key=?', $data['set_id'], $template['template_unique_key'] ) );
$newTemplateId = \IPS\Db::i()->insert( 'core_theme_templates', array( 'template_set_id' => $data['set_id'],
'template_group' => $template['template_group'],
'template_location' => $template['template_location'],
@@ -2980,7 +2988,6 @@ EOF;
'template_user_edited' => \IPS\Application::load( $template['template_app'] )->long_version,
'template_removable' => 1,
'template_version' => $theme->long_version,
'template_unique_key' => $template['template_unique_key'],
'template_updated' => time() ) );
}
@@ -3001,7 +3008,8 @@ EOF;
}
static::deleteCompiledTemplate( $template['template_app'], $template['template_location'], $template['template_group'], $data['set_id'] );
static::setThemeCustomized( $data['set_id'] );
return $newTemplateId;
}
@@ -3310,7 +3318,7 @@ EOF;
}
else if ( $row['template_user_added'] and in_array( $row['template_added_to'], array_values( $allParents ) ) )
{
$row['InheritedValue'] = 'inherit';
$row['InheritedValue'] = ( $row['template_removable'] and $this->_id == $row['template_set_id'] ) ? 'changed' : 'inherit';
}
else if ( $row['template_user_added'] and ( $row['template_added_to'] != $this->_id and $row['template_set_id'] != $this->_id ) )
{
@@ -4101,6 +4109,13 @@ EOF;
return $matches[1] . '="json--' . $jsonAttrI . '--"';
}, $rawContent );
/* Remove raw JS as this can cause a timeout if there is a lot of it */
$content = preg_replace_callback( '#<script\b[^>]*>([\s\S]*?)<\/script>#', function( $matches ) use ( &$phpQueryI, &$phpQueryStore )
{
$phpQueryStore[ ++$phpQueryI ] = $matches[0];
return 'he-' . $phpQueryI . '--';
}, $content );
$content = preg_replace_callback( array( '/{{?(?>[^{}]|(?R))*}?}/', '/\{([a-z]+?=([\'"]).+?\\2 ?+)}/' ), function( $matches ) use ( &$phpQueryI, &$phpQueryStore )
{
$phpQueryStore[ ++$phpQueryI ] = $matches[0];
@@ -4230,7 +4245,17 @@ EOF;
public static function checkTemplateSyntax( $content, $params='' )
{
ob_start();
static::makeProcessFunction( $content, 'unique_function_so_it_doesnt_look_in_function_exists_' . uniqid(), $params );
try
{
static::makeProcessFunction( $content, 'unique_function_so_it_doesnt_look_in_function_exists_' . mt_rand(), $params );
}
catch( \ParseError $e )
{
ob_end_clean();
throw new \LogicException( $e->getMessage() );
}
$return = ob_get_contents();
ob_end_clean();
@@ -4318,7 +4343,7 @@ EOF;
/* Parse shortcuts */
foreach ( array( 'request' => 'i', 'member' => 'loggedIn', 'settings' => 'i', 'output' => 'i' ) as $class => $function )
{
$content = preg_replace( '/(^|[^\$\\\])' . $class . "\.(\S+?)/", '$1\IPS\\' . ucfirst( $class ) . '::' . $function . '()->$2', $content );
$content = preg_replace( '/(^|[^\$\\\])' . $class . "\.(\S+?)/", '$1\IPS\\' . mb_ucfirst( $class ) . '::' . $function . '()->$2', $content );
}
foreach( array( 'theme' => '\IPS\\Theme::i()->settings', 'cookie' => '\IPS\\Request::i()->cookie' ) as $shortcut => $array )
@@ -4348,7 +4373,7 @@ EOF;
{
$content = $content . "\n<p id='elCopyright'>
<span id='elCopyright_userLine'>{lang=\"copyright_line_value\"}</span>
<a rel='nofollow' title='Invision Community' href='https://www.invisioncommunity.com/'>Powered by Invision Community</a><br><a href='http://ipbmafia.ru' style='display:none'>Поддержка Invision Community в России</a>
<a rel='nofollow' title='Invision Community' href='https://www.invisioncommunity.com/'>Powered by Invision Community</a><br><a href='//ipbmafia.ru' style='display:none'>Поддержка Invision Community в России</a>
</p>";
}
@@ -4432,7 +4457,7 @@ PHP;
preg_match_all( '/(.+?)='.$matches[2].'([^' . $matches[2] . ']*)'.$matches[2].'\s?/', $matches[1], $submatches );
$plugin = array_shift( $submatches[1] );
$pluginClass = 'IPS\\Output\\Plugin\\' . ucfirst( $plugin );
$pluginClass = 'IPS\\Output\\Plugin\\' . mb_ucfirst( $plugin );
$value = array_shift( $submatches[2] );
$options = array();
@@ -4447,9 +4472,9 @@ PHP;
{
foreach ( \IPS\Application::applications() as $app )
{
if ( file_exists( \IPS\ROOT_PATH . "/applications/{$app->directory}/extensions/core/OutputPlugins/" . ucfirst( $plugin ) . ".php" ) )
if ( file_exists( \IPS\ROOT_PATH . "/applications/{$app->directory}/extensions/core/OutputPlugins/" . mb_ucfirst( $plugin ) . ".php" ) )
{
$pluginClass = 'IPS\\' . $app->directory . '\\extensions\\core\\OutputPlugins\\' . ucfirst( $plugin );
$pluginClass = 'IPS\\' . $app->directory . '\\extensions\\core\\OutputPlugins\\' . mb_ucfirst( $plugin );
}
}
}
@@ -4525,11 +4550,11 @@ PHP;
{
if ( \stristr( $var[1], '|doubleencode' ) )
{
$replace = "\nCONTENT;\n\$return .= htmlspecialchars( \$" . str_ireplace( '|doubleencode', '', $var[1] ) . ", ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', TRUE );\n\$return .= <<<CONTENT\n";
$replace = "\nCONTENT;\n\$return .= htmlspecialchars( \$" . str_ireplace( '|doubleencode', '', $var[1] ) . ", ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', TRUE );\n\$return .= <<<CONTENT\n";
}
else
{
$replace = "\nCONTENT;\n\$return .= htmlspecialchars( \$" . $var[1] . ", ENT_QUOTES | \IPS\HTMLENTITIES, 'UTF-8', FALSE );\n\$return .= <<<CONTENT\n";
$replace = "\nCONTENT;\n\$return .= htmlspecialchars( \$" . $var[1] . ", ENT_QUOTES | ENT_DISALLOWED, 'UTF-8', FALSE );\n\$return .= <<<CONTENT\n";
}
$all = str_replace( $var[0], $replace, $all );
@@ -4742,7 +4767,7 @@ PHP;
/* Insert */
$saveSetId = isset( $data['set_id'] ) ? $data['set_id'] : 0;
$insertId = \IPS\Db::i()->insert( 'core_theme_css', array(
$insertId = \IPS\Db::i()->replace( 'core_theme_css', array(
'css_set_id' => $saveSetId,
'css_app' => mb_strtolower( $data['app'] ),
'css_location' => mb_strtolower( $data['location'] ),
@@ -4752,10 +4777,14 @@ PHP;
'css_added_to' => ( isset( $data['added_to'] ) ) ? intval( $data['added_to'] ) : 0,
'css_updated' => time(),
'css_version' => \IPS\Application::load('core')->long_version,
'css_plugin' => isset( $data['plugin'] ) ? $data['plugin'] : NULL,
'css_unique_key' => md5( $saveSetId . ';' . mb_strtolower( $data['app'] ) . ';' . mb_strtolower( $data['location'] ) . ';' . mb_strtolower( $data['path'] ) . ';' . mb_strtolower( $data['name'] ) )
'css_plugin' => isset( $data['plugin'] ) ? $data['plugin'] : NULL
) );
if ( ! empty( $data['set_id'] ) )
{
static::setThemeCustomized( $data['set_id'] );
}
return $insertId;
}
@@ -4776,23 +4805,50 @@ PHP;
throw new \InvalidArgumentException;
}
/* Check for existing */
$check = \IPS\Db::i()->select( 'template_id', 'core_theme_templates', array(
'template_app=? AND template_location=? AND template_group=? AND LOWER(template_name)=? AND template_set_id=?',
mb_strtolower( $data['app'] ),
mb_strtolower( $data['location'] ),
mb_strtolower( $data['group'] ),
mb_strtolower( $data['name'] ),
0
) );
if ( count( $check ) > 0 )
/* Check for existing and there is not existing template, then it will throw an an UnderflowException */
try
{
throw new \OverflowException;
$check = \IPS\Db::i()->select( 'template_id, template_added_to, template_set_id', 'core_theme_templates', array(
'template_app=? AND template_location=? AND template_group=? AND LOWER(template_name)=? AND template_set_id=?',
mb_strtolower( $data['app'] ),
mb_strtolower( $data['location'] ),
mb_strtolower( $data['group'] ),
mb_strtolower( $data['name'] ),
( isset( $data['set_id'] ) ) ? $data['set_id'] : 0
) )->first();
/* Template bit exists, are we trying to add a new master template with the same name as a third party template? */
if ( isset( $data['_default_template'] ) and $check['template_added_to'] > 0 )
{
/* Update it to make it belong to the theme that added it so it is revertable before adding the new one to fix an issue with early 4.0 releases */
try
{
\IPS\Db::i()->update( 'core_theme_templates', array(
'template_set_id' => $check['template_added_to']
), array( 'template_id=?', $check['template_id'] ) );
}
catch( \Exception $e )
{
/* This template bit exists in a custom template and also in the master space as a custom theme added this bit
as of 4.3 we will not be polluting the master space with additional templates so this can be removed then.
For now, we will remove the master template bit to allow the insert to work below */
\IPS\Db::i()->delete( 'core_theme_templates', array( 'template_id=?', $check['template_id'] ) );
}
}
else
{
/* Master bit exists, skip */
throw new \OverflowException;
}
}
catch( \UnderflowException $e )
{
/* Template doesn't exist, so it's all good bro */
}
/* Insert */
$insertId = \IPS\Db::i()->insert( 'core_theme_templates', array(
'template_set_id' => 0,
$insertId = \IPS\Db::i()->replace( 'core_theme_templates', array(
'template_set_id' => ( isset( $data['set_id'] ) ) ? $data['set_id'] : 0,
'template_app' => mb_strtolower( $data['app'] ),
'template_location' => mb_strtolower( $data['location'] ),
'template_group' => mb_strtolower( $data['group'] ),
@@ -4803,10 +4859,14 @@ PHP;
'template_updated' => time(),
'template_user_added' => ( isset($data['_default_template']) ) ? 0 : 1,
'template_version' => \IPS\Application::load('core')->long_version,
'template_plugin' => isset( $data['plugin'] ) ? $data['plugin'] : NULL,
'template_unique_key' => md5( '0;' . mb_strtolower( $data['app'] ) . ';' . mb_strtolower( $data['location'] ) . ';' . mb_strtolower( $data['group'] ) . ';' . mb_strtolower( $data['name'] ) )
'template_plugin' => isset( $data['plugin'] ) ? $data['plugin'] : NULL
), TRUE );
if ( ! empty( $data['set_id'] ) )
{
static::setThemeCustomized( $data['set_id'] );
}
return $insertId;
}
@@ -5076,6 +5136,56 @@ PHP;
$this->save();
}
/**
* Any custom images/css/templates?
*
* @return boolean
*/
public function isCustomized()
{
try
{
\IPS\Db::i()->select( 'template_id', 'core_theme_templates', array( 'template_set_id=?', $this->id ) )->first();
return TRUE;
}
catch( \UnderflowException $e ) { }
try
{
\IPS\Db::i()->select( 'css_id', 'core_theme_css', array( 'css_set_id=?', $this->id ) )->first();
return TRUE;
}
catch( \UnderflowException $e ) { }
try
{
\IPS\Db::i()->select( 'resource_id', 'core_theme_resources', array( 'resource_set_id=? and resource_user_edited=1', $this->id ) )->first();
return TRUE;
}
catch( \UnderflowException $e ) { }
return FALSE;
}
/**
* Static wrapper for customized
*
* return @void
*/
public static function setThemeCustomized( $themeId )
{
try
{
$theme = static::load( $themeId );
$theme->customized = $theme->isCustomized();
$theme->save();
}
catch( \OutOfRangeException $e )
{
}
}
/**
* Reset all cache keys
* This will make all existing template caches stale for all themes