Version 4.1.19

This commit is contained in:
Neo committed 2025-12-19 05:38:56 -08:00
1 parent 28bd025b35
commit 2bd5025018
2674 files changed
+233518 -77766

No files matched your search

@@ -2,9 +2,9 @@
/**
* @brief Emoticons
* @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 02 May 2013
* @version SVN_VERSION_NUMBER
*/
@@ -132,14 +132,14 @@ class _emoticons extends \IPS\Dispatcher\Controller
{
$filename_2x = preg_replace( "/^(.+?)\.[0-9a-f]{32}(?:\..+?)$/i", "$1", str_replace( '@2x', '', $file->filename ) );
$images2x[ $filename_2x ] = (string) $file;
$images2x[ $this->_getRawFilename( $filename_2x ) ] = (string) $file;
continue;
}
$filename = preg_replace( "/^(.+?)\.[0-9a-f]{32}(?:\..+?)$/i", "$1", $file->filename );
$inserts[] = array(
'typed' => ':' . mb_substr( $filename, 0, mb_strrpos( $filename, '.' ) ) . ':',
'typed' => ':' . preg_replace( "#\s#", "", $this->_getRawFilename( $filename ) ) . ':',
'image' => (string) $file,
'clickable' => TRUE,
'emo_set' => $setId,
@@ -158,21 +158,24 @@ class _emoticons extends \IPS\Dispatcher\Controller
foreach( \IPS\Db::i()->select( '*', 'core_emoticons', array( 'emo_set=?', $setId ) ) as $emo )
{
$file = \IPS\File::get( 'core_Emoticons', $emo['image'] );
$imageDimensions = $file->getImageDimensions();
$filename = $this->_getRawFilename( $file->filename );
/* There isn't an original for the 2x emo */
if( !isset( $images2x[ $file->filename ] ) )
if( !isset( $images2x[ $filename ] ) )
{
continue;
}
/* Get the dimensions of the smaller emoticon */
$imageDimensions = $file->getImageDimensions();
\IPS\Db::i()->update( 'core_emoticons', array(
'image_2x' => $images2x[ $file->filename ],
'image_2x' => $images2x[ $filename ],
'width' => $imageDimensions[0],
'height' => $imageDimensions[1]
), 'id=' . $emo['id']);
), 'id=' . $emo['id'] );
unset( $images2x[ $file->filename ] );
unset( $images2x[ $filename ] );
}
/* Delete any unused 2x files */
@@ -203,7 +206,7 @@ class _emoticons extends \IPS\Dispatcher\Controller
protected function edit()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'emoticons_edit' );
$position = 0;
$set = NULL;
@@ -242,15 +245,9 @@ class _emoticons extends \IPS\Dispatcher\Controller
}
$emoticons = $this->_getEmoticons( FALSE );
foreach ( \IPS\Request::i()->emo as $id => $data )
{
if ( isset( $data['__set__'] ) )
{
$set = mb_substr( $data['__set__'], \strlen( 'core_emoticon_group_' ) );
continue;
}
if ( isset( $emoticons[ $id ] ) )
{
if ( !$data['name'] )
@@ -260,30 +257,30 @@ class _emoticons extends \IPS\Dispatcher\Controller
if ( !isset( $data['order'] ) )
{
if ( !isset( $orders[ $set ] ) )
if ( !isset( $orders[ $data['set'] ] ) )
{
$orders[ $set ] = 0;
$orders[ $data['set'] ] = 0;
}
$data['order'] = ++$orders[ $set ];
$data['order'] = ++$orders[ $data['set'] ];
}
if ( $emoticons[ $id ]['typed'] !== $data['name'] or $data['order'] != $emoticons[ $id ]['emo_position'] )
{
$save = array( 'typed' => $data['name'] );
$save = array( 'typed' => preg_replace( "#\s#", "", $data['name'] ) );
if ( isset( $data['order'] ) )
{
$save['emo_position'] = $data['order'];
}
if ( $set !== NULL )
{
$save['emo_set'] = $set;
$save['emo_set'] = str_replace( 'core_emoticon_group_', '', $data['set'] );
}
\IPS\Db::i()->update( 'core_emoticons', $save, array( 'id=?', $id ) );
}
}
}
unset( \IPS\Data\Store::i()->emoticons );
/* Clear guest page caches */
@@ -302,7 +299,10 @@ class _emoticons extends \IPS\Dispatcher\Controller
protected function delete()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'emoticons_delete' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
try
{
$emoticon = \IPS\Db::i()->select( '*', 'core_emoticons', array( 'id=?', \IPS\Request::i()->id ) )->first();
@@ -342,6 +342,9 @@ class _emoticons extends \IPS\Dispatcher\Controller
public function deleteSet()
{
\IPS\Dispatcher::i()->checkAcpPermission( 'emoticons_delete' );
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
$set = preg_replace( '/^core_emoticon_group_/', '', \IPS\Request::i()->key );
@@ -417,4 +420,19 @@ class _emoticons extends \IPS\Dispatcher\Controller
return $emoticons;
}
/**
* Returns the filename and extension for given emoticon path
*
* @param string $path Emoticon path
* @return array
*/
protected function _getRawFilename( $path )
{
$parts = explode( '/', $path );
$filenamePart = array_pop( $parts );
$filename = mb_substr( $filenamePart, 0, mb_strrpos( $filenamePart, '.' ) );
return $filename;
}
}
@@ -2,9 +2,9 @@
/**
* @brief settings
* @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 13 Aug 2015
* @version SVN_VERSION_NUMBER
*/
@@ -2,9 +2,9 @@
/**
* @brief Editor Toolbars
* @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 30 Apr 2013
* @version SVN_VERSION_NUMBER
*/
@@ -23,6 +23,55 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _toolbar extends \IPS\Dispatcher\Controller
{
protected static $defaultPlugins = array(
'basicstyles',
'button',
'clipboard',
'colorbutton',
'dialog',
'dialogui',
'divarea',
'elementspath',
'enterkey',
'entities',
'floatingspace',
'floatpanel',
'font',
'htmlwriter',
'indent',
'indentblock',
'indentlist',
'index.html',
'ipsautogrow',
'ipsautolink',
'ipsautosave',
'ipscode',
'ipscontextmenu',
'ipsemoticon',
'ipsimage',
'ipslink',
'ipsmentions',
'ipspage',
'ipspaste',
'ipspreview',
'ipsquote',
'ipssource',
'ipsspoiler',
'justify',
'lineutils',
'list',
'listblock',
'menu',
'panel',
'panelbutton',
'removeformat',
'richcombo',
'sourcearea',
'toolbar',
'undo',
'widget',
);
/**
* Execute
*
@@ -134,9 +183,16 @@ class _toolbar extends \IPS\Dispatcher\Controller
$form = new \IPS\Helpers\Form;
/* Custom Plugin */
if ( preg_match( '/^custom-(\w{32})$/i', $button, $matches ) and !\IPS\IN_DEV )
if ( preg_match( '/^custom-(\w{32})$/i', $button, $matches ) and !\IPS\IN_DEV and !\IPS\NO_WRITES )
{
$code = file_get_contents( \IPS\ROOT_PATH . "/applications/core/interface/ckeditor/ckeditor/plugins/{$matches[0]}/plugin.js" );
$option = file_exists( \IPS\ROOT_PATH . "/applications/core/interface/ckeditor/ckeditor/plugins/{$matches[0]}/dialogs/{$matches[0]}.js" );
if ( $option )
{
$code = file_get_contents( \IPS\ROOT_PATH . "/applications/core/interface/ckeditor/ckeditor/plugins/{$matches[0]}/dialogs/{$matches[0]}.js" );
}
$type = 'inline';
if ( mb_strpos( $code, 'ips.utils.defaultEditorPlugins.singleblock' ) !== FALSE )
{
@@ -146,14 +202,11 @@ class _toolbar extends \IPS\Dispatcher\Controller
{
$type = 'block';
}
$option = file_exists( \IPS\ROOT_PATH . "/applications/core/interface/ckeditor/ckeditor/plugins/{$matches[0]}/dialogs/{$matches[0]}.js" );
if ( $option )
{
$code = file_get_contents( \IPS\ROOT_PATH . "/applications/core/interface/ckeditor/ckeditor/plugins/{$matches[0]}/dialogs/{$matches[0]}.js" );
}
if ( $type == 'block' or $type == 'singleblock' )
{
preg_match( "/ips.utils.defaultEditorPlugins.{$type}\( '{$matches[0]}', '(.+?)', ([{\[].*[}\]]), (\".*\"), (true|false), (\".*\") \)/", $code, $matches2 );
preg_match( "/ips.utils.defaultEditorPlugins.{$type}\( '{$matches[0]}', '(.+?)', ([{\[].*[}\]]), (\".*\"), (true|false), (\".*\")/", $code, $matches2 );
$attributes = array();
foreach ( json_decode( $matches2[2] ) as $k => $v )
{
@@ -188,13 +241,13 @@ class _toolbar extends \IPS\Dispatcher\Controller
/* If this is a custom one, add a delete button */
if ( in_array( mb_strtolower( $button ), explode( ',', mb_strtolower( \IPS\Settings::i()->ckeditor_extraPlugins ) ) ) or preg_match( '/^custom-\w{32}$/i', $button ) )
{
$form->addButton( 'delete', 'link', (string) \IPS\Http\Url::internal( "app=core&module=editor&controller=toolbar&do=deletePlugin&key={$button}" ), 'ipsButton_alternate' );
$form->addButton( 'delete', 'link', (string) \IPS\Http\Url::internal( "app=core&module=editor&controller=toolbar&do=deletePlugin&key={$button}" ), 'ipsButton ipsButton_negative' );
}
/* Handle Saves */
if ( $values = $form->values() )
{
if ( preg_match( '/^custom-(\w{32})$/i', $button, $matches ) and !\IPS\IN_DEV )
if ( preg_match( '/^custom-(\w{32})$/i', $button, $matches ) and !\IPS\IN_DEV and !\IPS\NO_WRITES )
{
$this->_saveCustomPlugin( $matches[0], $values );
}
@@ -208,6 +261,9 @@ class _toolbar extends \IPS\Dispatcher\Controller
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* IPS Cloud Sync */
\IPS\IPS::resyncIPSCloud();
\IPS\Output::i()->redirect( \IPS\Http\Url::internal('app=core&module=editor&controller=toolbar') );
}
@@ -265,6 +321,9 @@ class _toolbar extends \IPS\Dispatcher\Controller
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* IPS Cloud Sync */
\IPS\IPS::resyncIPSCloud();
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=toolbar' ), 'saved' );
}
@@ -287,7 +346,7 @@ class _toolbar extends \IPS\Dispatcher\Controller
$plugins = array();
foreach ( new \DirectoryIterator( \IPS\ROOT_PATH . '/applications/core/interface/ckeditor/ckeditor/plugins' ) as $f )
{
if ( !$f->isDot() and $f->isDir() and $f !== 'index.html' and !in_array( (string) $f, array_merge( array( 'autogrow', 'basicstyles', 'button', 'clipboard', 'colorbutton', 'dialog', 'dialogui', 'enterkey', 'entities', 'fakeobjects', 'floatingspace', 'floatpanel', 'font', 'indent', 'indentblock', 'indentlist', 'index.html', 'ipsattach', 'ipsautolink', 'ipsemoticon', 'ipsimage', 'ipslink', 'ipsmentions', 'ipspage', 'ipsprefs', 'ipsquote', 'ipsspoiler', 'justify', 'link', 'list', 'listblock', 'magicline', 'panel', 'panelbutton', 'pastetext', 'pbckcode', 'removeformat', 'richcombo', 'sourcearea', 'toolbar', 'undo', 'wysiwygarea' ), explode( ',', \IPS\Settings::i()->ckeditor_extraPlugins ) ) ) )
if ( !$f->isDot() and $f->isDir() and $f !== 'index.html' and !in_array( (string) $f, array_merge( static::$defaultPlugins, explode( ',', \IPS\Settings::i()->ckeditor_extraPlugins ) ) ) )
{
$plugins[ (string) $f ] = (string) $f;
}
@@ -309,9 +368,12 @@ class _toolbar extends \IPS\Dispatcher\Controller
break;
}
$tmpName = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );
move_uploaded_file( $values['editor_plugin_zip'], $tmpName );
/* Get the plugin name */
$inRoot = TRUE;
$zip = zip_open( $values['editor_plugin_zip'] );
$zip = zip_open( $tmpName );
while( $resource = zip_read( $zip ) )
{
$name = mb_substr( zip_entry_name( $resource ), 0, -1 );
@@ -335,14 +397,21 @@ class _toolbar extends \IPS\Dispatcher\Controller
$extractTo .= '/' . $name;
}
/* Check it isn't already installed */
if ( in_array( $name, array_merge( static::$defaultPlugins, explode( ',', \IPS\Settings::i()->ckeditor_extraPlugins ) ) ) )
{
$form->error = \IPS\Member::loggedIn()->language()->addToStack('editor_plugin_already_installed');
goto displayForm;
}
/* Extract it */
$zip = new \ZipArchive;
$zip->open( $values['editor_plugin_zip'] );
$zip->open( $tmpName );
$zip->extractTo( $extractTo );
$zip->close();
/* Delete the temp file */
unlink( $values['editor_plugin_zip'] );
unlink( $tmpName );
}
else
{
@@ -361,19 +430,32 @@ class _toolbar extends \IPS\Dispatcher\Controller
}
$file = \file_get_contents( \IPS\ROOT_PATH . '/applications/core/interface/ckeditor/ckeditor/plugins/' . $name . '/plugin.js' );
preg_match( "#requires: \'(.+?)\',#i", $file, $matches );
if ( isset( $matches[1] ) )
{
$required = explode( ',', $matches[1] );
$current = array_merge( array( 'basicstyles', 'button', 'panelbutton', 'panel', 'floatpanel', 'colorbutton', 'dialogui', 'enterkey', 'entities', 'fakeobjects', 'floatingspace', 'listblock', 'richcombo', 'font', 'indent', 'indentblock', 'indentlist', 'justify', 'list', 'magicline', 'dialog', 'clipboard', 'pastetext', 'pbckcode', 'removeformat', 'sourcearea', 'toolbar', 'undo', 'wysiwygarea', 'ipsattach', 'ipsautolink', 'ipsemoticon', 'ipsimage', 'ipslink', 'ipsmentions', 'ipsquote', 'ipsspoiler', 'ipsprefs' ), explode( ',', \IPS\Settings::i()->ckeditor_extraPlugins ) );
$rewriteFileWithIpsContextMenuRequirement = FALSE;
if ( in_array( 'contextmenu', $required ) )
{
$required[ array_search( 'contextmenu', $required ) ] = 'ipscontextmenu';
$rewriteFileWithIpsContextMenuRequirement = TRUE;
}
$current = array_merge( static::$defaultPlugins, explode( ',', \IPS\Settings::i()->ckeditor_extraPlugins ) );
$missing = array_diff( $required, $current );
if ( count( $missing ) > 0 )
{
\IPS\Output::i()->error( \IPS\Member::loggedIn()->language()->addToStack( 'editor_missing_requirements', FALSE, array( 'sprintf' => array( count( $missing ), implode( ', ', $missing ) ) ) ), '2C120/5', 404, '' );
}
if ( $rewriteFileWithIpsContextMenuRequirement )
{
$file = preg_replace_callback( "#requires: \'(.+?)\',#i", function( $matches )
{
return str_replace( 'contextmenu', 'ipscontextmenu', $matches[0] );
}, $file );
\file_put_contents( \IPS\ROOT_PATH . '/applications/core/interface/ckeditor/ckeditor/plugins/' . $name . '/plugin.js', $file );
}
}
/* Save */
@@ -385,13 +467,17 @@ class _toolbar extends \IPS\Dispatcher\Controller
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* IPS Cloud Sync */
\IPS\IPS::resyncIPSCloud();
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=toolbar' ), 'saved' );
}
}
/* If this is an AJAX request, just return it */
displayForm:
if( \IPS\Request::i()->isAjax() )
{
if ( \IPS\Request::i()->existing )
@@ -591,7 +677,7 @@ contents: [
}
],
onOk: function() {
var cmd = ips.utils.defaultEditorPlugins.inline( '{$key}', {$html}.replace( '{option}', this.getValueOf( 'tab', 'option' ) ) );
var cmd = ips.utils.defaultEditorPlugins.inline( '{$key}', {$html}.replace( /\{option\}/g, this.getValueOf( 'tab', 'option' ) ) );
cmd.exec( editor );
}
};
@@ -669,6 +755,9 @@ JS;
{
\IPS\Output::i()->error( 'no_writes', '1C120/3', 403, '' );
}
/* Make sure the user confirmed the deletion */
\IPS\Request::i()->confirmedDelete();
/* Check it's not required for something else */
foreach ( new \DirectoryIterator( \IPS\ROOT_PATH . '/applications/core/interface/ckeditor/ckeditor/plugins' ) as $file )
@@ -687,7 +776,7 @@ JS;
}
/* Delete it */
$key = \IPS\Request::i()->key;
$key = mb_strtolower( \IPS\Request::i()->key );
$dir = \IPS\ROOT_PATH . '/applications/core/interface/ckeditor/ckeditor/plugins/' . $key;
if ( is_dir( $dir ) )
{
@@ -695,7 +784,7 @@ JS;
}
/* Remove from plugin list */
$extraPlugins = explode( ',', \IPS\Settings::i()->ckeditor_extraPlugins );
$extraPlugins = explode( ',', mb_strtolower( \IPS\Settings::i()->ckeditor_extraPlugins ) );
foreach ( $extraPlugins as $k => $v )
{
if ( $v == $key )
@@ -708,6 +797,9 @@ JS;
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* IPS Cloud Sync */
\IPS\IPS::resyncIPSCloud();
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=editor&controller=toolbar' ), 'saved' );
@@ -767,7 +859,11 @@ JS;
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* IPS Cloud Sync */
\IPS\IPS::resyncIPSCloud();
/* Redirect */
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=editor&controller=toolbar" ), 'saved' );
}