Version 5.0.6

This commit is contained in:
Neo committed 2025-12-19 18:55:49 -08:00
1 parent a3a4a9ccbd
commit b89858b2ff
1214 files changed
+92828 -14859

No files matched your search

+14
View File
@@ -113,6 +113,20 @@ class Codemirror extends TextArea
{
if( $this->options['simple'] )
{
if ( isset( $this->options['mode'] ) )
{
if ( empty( $this->options['codeModeAllowedLanguages'] ) )
{
$this->options['codeModeAllowedLanguages'] = [];
}
$this->options['codeModeAllowedLanguages'][] = $this->options['mode'];
}
if ( is_array( $this->options['codeModeAllowedLanguages'] ) )
{
// HTMLMixed is not a valid option for Monaco
$this->options['codeModeAllowedLanguages'] = array_unique( array_map( function ($lang) { return $lang === 'htmlmixed' ? 'html' : $lang; }, $this->options['codeModeAllowedLanguages'] ) );
}
return parent::html();
}
+23 -2
View File
@@ -38,6 +38,7 @@ use IPS\Theme;
use IPS\Xml\SimpleXML;
use OutOfBoundsException;
use UnderflowException;
use UnexpectedValueException;
use function count;
use function defined;
use function file_get_contents;
@@ -45,6 +46,8 @@ use function in_array;
use function is_array;
use function is_null;
use function is_string;
use function md5;
use function session_id;
use function strlen;
use const IPS\ROOT_PATH;
@@ -140,6 +143,9 @@ class Editor extends FormAbstract
"external_video",
'og_embed',
"raw_embed",
'native_emoji',
'custom_emoji',
'fa_icons'
];
/**
@@ -296,9 +302,13 @@ class Editor extends FormAbstract
which creates a discrepency between wheat displays in a post and what displays in the editor */
// $value = preg_replace( '/<p>\s*<\/p>/', '', $value );
/* It is possible that the autosave key was updated, so we make doubly sure the uploader's post key matches our own */
$finalPostKey = md5( $this->options['autoSaveKey'] . ':' . session_id() );
/* Show full uploader */
if ( $this->uploader )
{
$this->uploader->options['postKey'] = $finalPostKey;
$attachmentArea = $this->uploader->html();
}
/* Or show a loading icon where the uploader will go if the editor is minimized */
@@ -320,7 +330,7 @@ class Editor extends FormAbstract
/* Or if the user can't attach, just show a bar */
else
{
$attachmentArea = Theme::i()->getTemplate( 'forms', 'core', 'global' )->editorAttachmentsPlaceholder( $this->name, $this->postKey, $this->noUploaderError, $this->canUseMediaExtension() );
$attachmentArea = Theme::i()->getTemplate( 'forms', 'core', 'global' )->editorAttachmentsPlaceholder( $this->name, $finalPostKey, $this->noUploaderError, $this->canUseMediaExtension() );
}
if ( Member::loggedIn()->group['g_bypass_badwords'] )
@@ -1000,7 +1010,18 @@ class Editor extends FormAbstract
$editorFile = Application::getRootPath( $app->directory ) . "/applications/" . $app->directory . "/data/editor.xml";
if( file_exists( $editorFile ) )
{
$xml = SimpleXML::loadFile( $editorFile );
try
{
$xml = SimpleXML::loadFile( $editorFile );
if ( !isset( $xml->plugin ) or !is_iterable( $xml->plugin ) )
{
throw new UnexpectedValueException;
}
}
catch ( Exception $e )
{
continue;
}
foreach( $xml->plugin as $plugin )
{
$contents = (string) $plugin;
+1 -1
View File
@@ -112,7 +112,7 @@ class Radio extends Select
if ( $this->options['parse'] === 'image' )
{
return 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, $this->options['gridspan'] );
return 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
{
+1 -3
View File
@@ -42,7 +42,6 @@ class Select extends FormAbstract
'class' => '', // CSS class
'disabled' => FALSE, // Disables input. Default is FALSE.
'parse' => 'lang', // Sets how the values for options should be parsed. Acceptable values are "lang" (language keys), "normal" (htmlentities), "raw" (no parsing) or "image" (image URLs, only for Radio fields). Default is "lang".
'gridspan' => 3, // If 'parse' is set to 'image', this controls the gridspan to use when creating the option layout
'unlimited' => -1, // If any value other than NULL is provided, an "Unlimited" checkbox will be displayed. If checked, the value specified will be sent.
'unlimitedLang' => 'unlimited', // Language string to use for unlimited checkbox label
'unlimitedToggles' => array(...), // Names of other input fields that should show/hide when the "Unlimited" checkbox is toggled.
@@ -62,7 +61,6 @@ class Select extends FormAbstract
'class' => '',
'disabled' => FALSE,
'parse' => 'lang',
'gridspan' => 3,
'unlimited' => NULL,
'unlimitedLang' => 'all',
'unlimitedToggles' => array(),
@@ -230,7 +228,7 @@ class Select extends FormAbstract
if( isset( $this->options['userSuppliedInput'] ) )
{
$name = $this->options['userSuppliedInput'] . '_' . $this->name;
$userInputValue = Request::i()->$name;
$userInputValue = mb_strpos( $name, '[' ) ? Request::i()->valueFromArray( $name ) : Request::i()->$name;
if( is_array( $userInputValue ) )
{
$userInputValue = $userInputValue[0];
+160
View File
@@ -0,0 +1,160 @@
<?php
/**
* @brief Buttons
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
* @copyright (c) Invision Power Services, Inc.
* @license https://www.invisioncommunity.com/legal/standards/
* @package Invision Community
* @subpackage
* @since 3/28/2025
*/
namespace IPS\Helpers\Menu;
/* To prevent PHP errors (extending class does not exist) revealing path */
use IPS\Helpers\Menu;
use IPS\Http\Url;
use IPS\Theme;
use function is_string;
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
{
header( ( $_SERVER['SERVER_PROTOCOL'] ?? 'HTTP/1.0' ) . ' 403 Forbidden' );
exit;
}
class Buttons extends Menu
{
/**
* @param string $css
*/
public function __construct( string $css = 'ipsButtons' )
{
parent::__construct( '', null, $css );
}
/**
* Adds a seperator element to the stack
*
* @return $this
*/
public function addSeparator(): self
{
/* Separators are not supported in buttons list */
return $this;
}
/**
* Adds a title field to the stack
*
* @param string $title
* @return $this
*/
public function addTitleField( string $title ): self
{
/* Title fields are not supported in buttons list */
return $this;
}
/**
* Static method to build a button.
* Primarily used for 3rd party extensions.
*
* @param Url|string|null $url
* @param string $languageString
* @param string|null $css
* @param array $dataAttributes
* @param bool $opensDialog
* @param string|null $icon
* @param bool|string $tooltip
* @return string|Link
*/
public static function button( Url|string|null $url, string $languageString, ?string $css = null, array $dataAttributes = [], bool $opensDialog = FALSE, ?string $icon = NULL, bool|string $tooltip=false ) : string|Link
{
/* Handle the tooltip */
if( $tooltip !== false )
{
$dataAttributes['title'] = is_string( $tooltip ) ? $tooltip : $languageString;
$dataAttributes['data-ipsTooltip'] = '';
}
/* If the URL is null, then we're just showing a <span> instead of an actual link */
if( $url === null )
{
return Theme::i()->getTemplate( 'menu', 'core', 'front' )->buttonsItem( $css ?? 'ipsButton ipsButton--text', $languageString, $icon ?? '', $dataAttributes );
}
else
{
return new Link( $url, $languageString, $css ?? 'ipsButton ipsButton--inherit', $dataAttributes, $opensDialog, $icon );
}
}
/**
* Build a button
*
* @param Url|string|null $url
* @param string $languageString
* @param string|null $css
* @param array $dataAttributes
* @param bool $opensDialog
* @param string|null $icon
* @param bool|string $tooltip
* @return $this
*/
public function addButton( Url|string|null $url, string $languageString, ?string $css = null, array $dataAttributes = [], bool $opensDialog = FALSE, ?string $icon = NULL, bool|string $tooltip=false ) : self
{
$this->elements[] = static::button( $url, $languageString, $css, $dataAttributes, $opensDialog, $icon, $tooltip );
return $this;
}
/**
* Returns a row wrapper which can contain custom HTML code
* @param string $content
* @return string
*/
public function rowWrapper( string $content ): string
{
return '';
}
/**
* Returns the link
*
* @return string
*/
public function linkHtml(): string
{
return $this->contentHtml();
}
/**
* Returns the parsed menu content
*
* @return string
*/
public function contentHtml(): string
{
if( $this->hasContent() )
{
return Theme::i()->getTemplate( 'menu', 'core', 'front' )->buttonsContent( $this );
}
return '';
}
/**
* Returns the parsed menu
* @return string
*/
public function __toString(): string
{
if( !$this->hasContent() )
{
return '';
}
return Theme::i()->getTemplate( 'menu', 'core', 'front' )->buttonsList( $this );
}
}
+30 -9
View File
@@ -409,10 +409,7 @@ class Content extends Table
}
/* Check extensions for custom where clause */
foreach( UiExtension::i()->run( $class, 'contentTableWhere', array( $this ) ) as $customWhere )
{
$where[] = $customWhere;
}
UiExtension::i()->run( $class, 'contentTableWhere', array( $this, &$where ) );
/* Get results */
$this->count = $class::getItemsWithPermission( $where, $sortBy, NULL, $this->permCheck, $this->includeHiddenContent, 0, NULL, $this->joinContainer, $this->joinComments, $this->joinReviews, TRUE, $this->joins, ( $this->container and $this->limitByContainer ) ? $this->container : FALSE, TRUE, TRUE, TRUE, $this->showMovedLinks );
@@ -619,6 +616,9 @@ class Content extends Table
{
$class::tableGetRows( $rows );
}
/* Extensions */
UiExtension::i()->run( $class, 'contentTableGetRows', [ $this, &$rows ] );
if ( $this->callback != NULL and is_callable( $this->callback ) )
{
@@ -990,11 +990,32 @@ class Content extends Table
$currentTags['prefix'] = $currentPrefix;
}
foreach( $params[ $class::$formLangPrefix . 'tags' ] as $tag )
foreach( $params[ $class::$formLangPrefix . 'tags' ] as $k => $tag )
{
$currentTagIndex = array_search( $tag, $currentTags );
if( Request::i()->modaction == 'tag' )
{
if( !in_array( $tag, $currentTags ) )
/* Prefix should be handled slightly differently */
if( $k == 'prefix' )
{
if( !isset( $currentTags['prefix'] ) or $currentTags['prefix'] != $tag )
{
/* Move the current prefix to the regular tag list */
if( isset( $currentTags['prefix'] ) )
{
$currentTags[] = $currentTags['prefix'];
}
/* Set the tag as the prefix and remove it from the tag list */
$currentTags['prefix'] = $tag;
if( $currentTagIndex !== false )
{
unset( $currentTags[ $currentTagIndex ] );
}
$modified = true;
}
}
elseif( $currentTagIndex === false )
{
$currentTags[] = $tag;
$modified = true;
@@ -1002,10 +1023,10 @@ class Content extends Table
}
else
{
$index = array_search( $tag, $currentTags );
if( $index !== false )
$currentTagIndex = array_search( $tag, $currentTags );
if( $currentTagIndex !== false )
{
unset( $currentTags[ $index ] );
unset( $currentTags[ $currentTagIndex ] );
$modified = true;
}
}