Version 4.1.2

This commit is contained in:
Neo committed 2025-12-19 05:32:19 -08:00
1 parent 3ba79295ee
commit 28bd025b35
1131 files changed
+63658 -20579

No files matched your search

+26 -12
View File
@@ -289,12 +289,16 @@ EOF;
/**
* Delete compiled versions
*
* @param int|array $ids Integer ID or Array IDs to remove
* @param null|int|array $ids Integer ID or Array IDs to remove
* @return void
*/
public static function deleteCompiled( $ids )
public static function deleteCompiled( $ids=NULL )
{
if ( is_numeric( $ids ) )
if ( $ids === NULL )
{
$ids = iterator_to_array( \IPS\Db::i()->select( 'block_id', 'cms_blocks' )->setValueField('block_id') );
}
else if ( is_numeric( $ids ) )
{
$ids = array( $ids );
}
@@ -431,6 +435,14 @@ EOF;
unset( $buttons['edit']['data'] );
}
/* View Details */
$buttons['details'] = array(
'icon' => 'search',
'title' => 'block_embed_options',
'link' => \IPS\Http\Url::internal( "app=cms&module=pages&controller=blocks&do=embedOptions&id={$this->_id}" ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('block_embed_options') )
);
return $buttons;
}
@@ -447,7 +459,7 @@ EOF;
$block_plugin = ( isset( \IPS\Request::i()->block_plugin ) ) ? \IPS\Request::i()->block_plugin : ( $this->id ? $this->plugin : null );
/* Build form */
$form->addtab( 'content_block_form_tab__details' );
$form->addTab( 'content_block_form_tab__details' );
$form->add( new \IPS\Helpers\Form\Translatable( 'block_name', NULL, TRUE, array(
'app' => 'cms',
'key' => ( $this->id ? "content_block_name_" . $this->id : NULL )
@@ -550,12 +562,12 @@ EOF;
if ( is_callable( array( $this->widget(), 'configuration' ) ) )
{
$form->addtab( 'content_block_form_tab__feed' );
$form->addTab( 'content_block_form_tab__feed' );
$this->widget()->configuration( $form );
}
}
$form->addtab( 'content_block_form_tab__content');
$form->addTab( 'content_block_form_tab__content');
if ( $block_type === 'plugin' )
{
@@ -606,7 +618,8 @@ EOF;
$form->add( new \IPS\Helpers\Form\Editor( 'block_content', $this->content, FALSE, array(
'app' => 'cms',
'key' => 'BlockContent',
'autoSaveKey' => 'block-content-' . ( $this->id ? $this->id : 'new' ) ), NULL, NULL, NULL, 'block_content_editor' ) );
'autoSaveKey' => 'block-content-' . ( $this->id ? $this->id : 'new' ),
'attachIds' => ( $this->id ) ? array( $this->id ) : NULL ), NULL, NULL, NULL, 'block_content_editor' ) );
}
else
{
@@ -656,15 +669,16 @@ EOF;
*/
public function formatFormValues( $values )
{
/* Claim Attachments - we need to adjust the temp key based on presence if this block existed or not */
if ( \IPS\Request::i()->block_editor === 'editor' )
{
\IPS\File::claimAttachments( ( $this->id ) ? 'block-content-' . $this->id : 'block-content-new', $this->id );
}
if ( ! $this->id )
{
$this->active = 1;
$this->save();
if ( \IPS\Request::i()->block_editor === 'editor' )
{
\IPS\File::claimAttachments( 'block-content/block-' . $this->id, $this->id );
}
}
$config = array();
@@ -225,6 +225,22 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
return static::$database;
}
/**
* Test to see if this is a valid container ID
*
* @param int $id Container ID
* @reply boolean
*/
public static function isValidContainerId( $id )
{
if ( static::$containerIds === NULL )
{
static::$containerIds = iterator_to_array( \IPS\Db::i()->select( 'category_id', static::$databaseTable, array( array( 'category_database_id=?', static::$customDatabaseId ) ) ) );
}
return in_array( $id, static::$containerIds );
}
/**
* Fetch All Root Nodes
@@ -308,7 +324,7 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
*/
public function get_fields()
{
return $this->_data['fields'] === '*' ? '*' : json_decode( $this->_data['fields'], TRUE );
return ( $this->_data['fields'] === '*' OR $this->_data['fields'] === NULL ) ? '*' : json_decode( $this->_data['fields'], TRUE );
}
/**
@@ -363,7 +379,7 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
public function form( &$form )
{
/* Build form */
$form->addtab( 'content_content_form_tab__config' );
$form->addTab( 'content_content_form_tab__config' );
$form->add( new \IPS\Helpers\Form\Translatable( 'category_name', NULL, TRUE, array(
'app' => 'cms',
@@ -477,7 +493,7 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
if ( \IPS\Application::appIsEnabled( 'forums' ) )
{
$form->addtab( 'content_content_form_tab__forum' );
$form->addTab( 'content_content_form_tab__forum' );
$form->add( new \IPS\Helpers\Form\YesNo( 'category_forum_override', ( $this->id ? $this->forum_override : NULL ), FALSE, array(
'togglesOn' => array(
@@ -523,11 +539,11 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
$form->addTab( 'content_content_form_header__fields' );
$cats = $this->id ? $this->fields : '*';
$options = array();
$fieldClass = 'IPS\cms\Fields' . \IPS\Request::i()->database_id;
$database = \IPS\cms\Databases::load( \IPS\Request::i()->database_id );
$cats = $this->id ? ( $this->fields === NULL ? '*' : $this->fields ) : '*';
$options = array();
$fieldClass = 'IPS\cms\Fields' . \IPS\Request::i()->database_id;
$database = \IPS\cms\Databases::load( \IPS\Request::i()->database_id );
foreach( $fieldClass::data( NULL, NULL, $fieldClass::FIELD_SKIP_TITLE_CONTENT ) as $field )
{
if ( $field->id !== $database->field_title AND $field->id !== $database->field_content )
@@ -793,7 +809,39 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
* @brief FURL changed
*/
protected $_updatePaths = FALSE;
/**
* Disabled permissions
* Allow node classes to define permissions that are unselectable in the permission matrix
*
* @return array array( {group_id} => array( 'read', 'view', 'perm_7' );
*/
public function disabledPermissions()
{
$database = \IPS\cms\Databases::load( $this->database_id );
$dbPerms = $database->permissions();
$disabled = array();
foreach( array( 'view', 2, 3, 4, 5, 6, 7 ) as $perm )
{
/* Remove unticked database permissions */
if ( $dbPerms['perm_' . $perm ] != '*' )
{
$db = explode( ',', $dbPerms['perm_' . $perm ] );
foreach ( \IPS\Member\Group::groups() as $group )
{
if ( ! in_array( $group->g_id, $db ) )
{
$disabled[ $group->g_id ][] = $perm;
}
}
}
}
return $disabled;
}
/**
* Get permissions
*
@@ -936,6 +984,36 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
return $this->_url;
}
/**
* Get URL from index data
*
* @param array $indexData Data from the search index
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
* @param array|NULL $containerData Basic data about the author. Only includes columns returned by container::basicDataColumns()
* @return \IPS\Http\Url
*/
public static function urlFromIndexData( $indexData, $itemData, $containerData )
{
$recordClass = $indexData['index_class'];
if ( in_array( 'IPS\Content\Comment', class_parents( $recordClass ) ) )
{
$recordClass = $recordClass::$itemClass;
}
if ( $recordClass::$pagePath === NULL )
{
$recordClass::$pagePath = \IPS\Db::i()->select( array( 'page_full_path' ), 'cms_pages', array( 'page_id=?', $recordClass::database()->page_id ) )->first();
}
if ( $recordClass::database()->use_categories )
{
return \IPS\Http\Url::internal( "app=cms&module=pages&controller=page&path=" . $recordClass::$pagePath . '/' . $itemData['extra'], 'front', 'content_page_path', $itemData['extra'] );
}
else
{
return \IPS\Http\Url::internal( "app=cms&module=pages&controller=page&path=" . $recordClass::$pagePath, 'front', 'content_page_path', '' );
}
}
/**
* Get title of category
@@ -1233,7 +1311,7 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
{
$this->last_record_date = $comment->mapped('date');
$this->last_record_member = intval( $comment->author()->member_id );
$this->last_record_name = $comment->author()->member_id ? $comment->author()->name : $comment->mapped('author_name');
$this->last_record_name = $comment->author()->member_id ? $comment->author()->name : NULL;
$this->last_record_seo_name = \IPS\Http\Url::seoTitle( $this->last_poster_name );
$this->last_title = $comment->item()->mapped('title');
$this->last_seo_title = \IPS\Http\Url::seoTitle( $this->last_title );
@@ -1243,8 +1321,8 @@ class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
{
$this->last_record_date = static::$latestRecordAdded->record_saved;
$this->last_record_member = static::$latestRecordAdded->member_id;
$this->last_record_name = static::$latestRecordAdded->record_last_comment_name;
$this->last_record_seo_name = static::$latestRecordAdded->record_last_comment_seo;
$this->last_record_name = static::$latestRecordAdded->member_id ? static::$latestRecordAdded->record_last_comment_name : NULL;
$this->last_record_seo_name = static::$latestRecordAdded->member_id ? static::$latestRecordAdded->record_last_comment_seo : NULL;
$this->last_title = static::$latestRecordAdded->_title;
$this->last_seo_title = \IPS\Http\Url::seoTitle( static::$latestRecordAdded->_title );
$this->last_record_id = static::$latestRecordAdded->_id;
@@ -146,7 +146,7 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
)
)
);
/**
* Return all databases
*
@@ -156,21 +156,38 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
{
if ( ! static::$gotAll )
{
if ( \IPS\Db::i()->checkForTable( static::$databaseTable ) )
if ( ! isset( \IPS\Data\Store::i()->cms_databases ) )
{
\IPS\Data\Store::i()->cms_databases = iterator_to_array( \IPS\Db::i()->select( '*', static::$databaseTable )->setKeyField('database_id') );
}
/* Avoid using SHOW TABLES LIKE / checkForTable() */
try
{
foreach( \IPS\Db::i()->select( '*', static::$databaseTable ) as $db )
foreach( \IPS\Data\Store::i()->cms_databases as $db )
{
$id = $db[ static::$databasePrefix . static::$databaseColumnId ];
static::$multitons[ $id ] = static::constructFromData( $db );
}
}
catch( \Exception $e ) { }
static::$gotAll = true;
}
return static::$multitons;
}
/**
* Can we promote stuff to Pages?
*
* @return boolean
*/
public static function canPromote()
{
return TRUE;
}
/**
* Construct ActiveRecord from database row
*
@@ -329,9 +346,19 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
foreach( \IPS\Lang::languages() as $id => $lang )
{
/* Try to get the actual database noun if it has been created */
try
{
$title = $lang->get( 'content_db_lang_pu_' . $database->id );
}
catch( \Exception $e )
{
$title = $lang->get('content_database_noun_pu');
}
$fieldTitle[ $id ] = $lang->get('content_fields_is_title');
$fieldContent[ $id ] = $lang->get('content_fields_is_content');
$catTitle[ $id ] = $lang->get('content_database_noun_pu');
$catTitle[ $id ] = $title;
$catDesc[ $id ] = '';
}
@@ -660,7 +687,7 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
public function preLoadWords()
{
/* Skip this during installation / uninstallation as the words won't be loaded */
if ( !\IPS\Dispatcher::hasInstance() or \IPS\Dispatcher::i()->controllerLocation === 'setup' OR ( \IPS\Dispatcher::i()->controllerLocation === 'admin' AND ( !\IPS\Dispatcher::i()->module OR \IPS\Dispatcher::i()->module->key === 'applications' ) ) )
if ( !\IPS\Dispatcher::hasInstance() or \IPS\Dispatcher::i()->controllerLocation === 'setup' OR ( \IPS\Dispatcher::i()->controllerLocation === 'admin' AND \IPS\Dispatcher::i()->module->key === 'applications' ) )
{
$this->langLoaded = TRUE;
return;
@@ -671,17 +698,20 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
\IPS\Member::loggedIn()->language()->words['__indefart_content_record_comments_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( '__indefart_content_record_comments_title' );
\IPS\Member::loggedIn()->language()->words['__indefart_content_record_reviews_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( '__indefart_content_record_reviews_title' );
\IPS\Member::loggedIn()->language()->words['content_record_comments_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_record_comments_title', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
\IPS\Member::loggedIn()->language()->words['content_record_reviews_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_record_reviews_title', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
\IPS\Member::loggedIn()->language()->words['content_record_comments_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_record_comment_title', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
\IPS\Member::loggedIn()->language()->words['content_record_reviews_title_' . $this->id ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_record_review_title', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
\IPS\Member::loggedIn()->language()->words['content_record_comments_title_' . $this->id . '_pl' ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_record_comments_title', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
\IPS\Member::loggedIn()->language()->words['content_record_reviews_title_' . $this->id . '_pl' ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_record_reviews_title', FALSE, array( 'sprintf' => array( $this->recordWord( 1, TRUE ) ) ) );
\IPS\Member::loggedIn()->language()->words['content_db_lang_su_' . $this->id . '_pl' ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_db_lang_pu_' . $this->id );
\IPS\Member::loggedIn()->language()->words['content_db_lang_sl_' . $this->id . '_pl_lc' ] = \IPS\Member::loggedIn()->language()->addToStack( 'content_db_lang_pl_' . $this->id );
$fieldsClass = '\IPS\cms\Fields' . $this->id;
$customFields = $fieldsClass::data( 'view', $this );
$customFields = $fieldsClass::databaseFieldIds();
foreach ( $customFields AS $id => $field)
foreach ( $customFields AS $id )
{
\IPS\Member::loggedIn()->language()->words['sort_field_' . $id] = $field->_title;
\IPS\Member::loggedIn()->language()->words['sort_field_' . $id] = \IPS\Member::loggedIn()->language()->addToStack( 'content_field_' . $id );
}
if ( \IPS\Dispatcher::i()->controllerLocation === 'admin' )
@@ -722,6 +752,21 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
return $number == 1 ? \IPS\Member::loggedIn()->language()->addToStack("content_db_lang_s{$case}_{$this->id}") : \IPS\Member::loggedIn()->language()->addToStack("content_db_lang_p{$case}_{$this->id}");
}
/**
* [ActiveRecord] Save Record
*
* @return void
*/
public function save()
{
if ( isset( \IPS\Data\Store::i()->cms_databases ) )
{
unset( \IPS\Data\Store::i()->cms_databases );
}
parent::save();
}
/**
* [ActiveRecord] Delete Record
*
@@ -742,9 +787,18 @@ class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
$field->delete( TRUE );
}
if ( isset( \IPS\Data\Store::i()->cms_databases ) )
{
unset( \IPS\Data\Store::i()->cms_databases );
}
/* Delete comments */
\IPS\Db::i()->delete( 'cms_database_comments', array( 'comment_database_id=?', $this->id ) );
/* Delete from search index */
\IPS\Db::i()->delete( 'core_search_index', array( 'index_class=?', "IPS\cms\Records\Comment" . $this->id ) );
\IPS\Db::i()->delete( 'core_search_index', array( 'index_class=?', "IPS\cms\Records\Review" . $this->id ) );
/* Delete records */
\IPS\Db::i()->dropTable( 'cms_custom_database_' . $this->id, TRUE );
@@ -283,6 +283,8 @@ class _Dispatcher extends \IPS\Dispatcher
}
\IPS\Dispatcher::i()->dispatcherController = $controller;
\IPS\Output::i()->defaultSearchOption = array( "cms_records{$this->databaseId}", "cms_records{$this->databaseId}_pl" );
/* Add database key to body classes for easier database specific themeing */
\IPS\Output::i()->bodyClasses[] = 'cCmsDatabase_' . $database->key;
+366 -99
View File
@@ -167,6 +167,16 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
*/
const FIELD_DISPLAY_FILTERS = 16;
/**
* @brief Fields that cannot be title fields
*/
public static $cannotBeTitleFields = array( 'Editor', 'CheckboxSet', 'YesNo', 'Radio' );
/**
* @brief Fields that cannot be title fields
*/
public static $cannotBeContentFields = array();
/**
* Load Record
*
@@ -198,7 +208,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
*/
public static function roots( $permissionCheck='view', $member=NULL, $where=array() )
{
$permissionCheck = ( \IPS\Dispatcher::i()->controllerLocation === 'admin' ) ? NULL : $permissionCheck;
$permissionCheck = ( \IPS\Dispatcher::hasInstance() AND \IPS\Dispatcher::i()->controllerLocation === 'admin' ) ? NULL : $permissionCheck;
if ( ! isset( static::$cache[ static::$customDatabaseId ][ $permissionCheck ] ) )
{
@@ -209,7 +219,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
foreach( static::$cache[ static::$customDatabaseId ][ $permissionCheck ] as $id => $obj )
{
if ( ! in_array( $obj->type, static::$additionalFieldTypes ) AND ( ! class_exists( '\IPS\Helpers\Form\\' . ucfirst( $obj->type ) ) AND ! class_exists( '\IPS\cms\Fields\\' . ucfirst( $obj->type ) ) ) )
if ( ! array_key_exists( $obj->type, static::$additionalFieldTypes ) AND ( ! class_exists( '\IPS\Helpers\Form\\' . ucfirst( $obj->type ) ) AND ! class_exists( '\IPS\cms\Fields\\' . ucfirst( $obj->type ) ) ) )
{
unset( static::$cache[ static::$customDatabaseId ][ $permissionCheck ][ $id ] );
continue;
@@ -229,6 +239,23 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
return static::$cache[ static::$customDatabaseId ][ $permissionCheck ];
}
/**
* Just return all field IDs in a database without permission checking
*
* @return array
*/
public static function databaseFieldIds()
{
$key = 'cms_fieldids_' . static::$customDatabaseId;
if ( ! isset( \IPS\Data\Store::i()->$key ) )
{
\IPS\Data\Store::i()->$key = iterator_to_array( \IPS\Db::i()->select( 'field_id', 'cms_database_fields', array( array( 'field_database_id=?', static::$customDatabaseId ) ) )->setKeyField('field_id') );
}
return \IPS\Data\Store::i()->$key;
}
/**
* Get Field Data
*
@@ -432,26 +459,53 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
if ( $display === 'listing' )
{
if ( $display === 'listing' and ! $row->display_listing )
if ( ! $row->display_listing )
{
continue;
}
$value = $row->truncate( $value, TRUE );
if ( $value or $value === "0" )
if ( $value )
{
$value = $row->formatForDisplay( $value, $formValue, 'listing', $record );
}
}
else if ( $display === 'display' )
else if ( $display === 'display' or $display === 'display_top' or $display === 'display_bottom' )
{
if ( $display === 'display' and ! $row->display_display )
if ( ! $row->display_display )
{
continue;
}
if ( $value or $value === "0" )
$displayData = $row->display_json;
if ( $display === 'display_bottom' )
{
if ( isset( $displayData['display']['where'] ) )
{
if ( $displayData['display']['where'] !== 'bottom' )
{
continue;
}
}
else
{
continue;
}
}
else if ( $display === 'display_top' )
{
if ( isset( $displayData['display']['where'] ) )
{
if ( $displayData['display']['where'] !== 'top' )
{
continue;
}
}
}
if ( $value )
{
$value = $row->formatForDisplay( $value, $formValue, 'display', $record );
}
@@ -488,7 +542,34 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
{
return (string) \IPS\File::get( static::$uploadStorageExtension, $value )->url;
}
if ( $this->type === 'Item' )
{
if ( ! is_array( $formValue ) and mbs_trstr( $formValue, ',' ) )
{
$value = explode( ',', $formValue );
}
else
{
$value = array( $formValue );
}
if ( count( $value ) and isset( $this->extra['database'] ) and $this->extra['database'] )
{
$results = array();
$class = '\IPS\cms\Records' . $this->extra['database'];
$field = $class::$databasePrefix . $class::$databaseColumnMap['title'];
$where = array( \IPS\Db::i()->in( $class::$databaseColumnId, $value ) );
foreach ( $class::getItemsWithPermission( array( $where ), $field, NULL ) as $item )
{
$results[ $item->_id ] = $item;
}
return $results;
}
}
return $formValue;
}
else if ( $type === 'processed' )
@@ -498,7 +579,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
$options = $this->display_json;
if ( isset( $options[ $type ]['method'] ) )
if ( isset( $options[ $type ]['method'] ) AND $options[ $type ]['method'] !== 'simple' )
{
if ( in_array( $this->type, static::$mediaFields ) )
{
@@ -1044,7 +1125,18 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
public function displayValue( $value=NULL )
{
$database = \IPS\cms\Databases::load( static::$customDatabaseId );
if ( class_exists( '\IPS\cms\Fields\\' . ucfirst( $this->type ) ) )
{
/* Is special! */
$class = '\IPS\cms\Fields\\' . ucfirst( $this->type );
if ( method_exists( $class, 'displayValue' ) )
{
return $class::displayValue( $value, $this );
}
}
switch( ucfirst( $this->type ) )
{
case 'Upload':
@@ -1052,7 +1144,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
break;
case 'Text':
case 'TextArea':
$this->applyFormatter( $value );
$value = $this->applyFormatter( $value );
/* We don't want the parent adding wordbreak to the title */
if ( $this->id == $database->field_title OR $this->id == $database->field_content )
@@ -1084,14 +1176,14 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
$return = array();
foreach( $value as $key )
{
$return[] = isset( $this->extra[ $key ] ) ? htmlentities( $this->extra[ $key ], \IPS\HTMLENTITIES, 'UTF-8', FALSE ) : htmlentities( $key, \IPS\HTMLENTITIES, 'UTF-8', FALSE );
$return[] = isset( $this->extra[ $key ] ) ? htmlspecialchars( $this->extra[ $key ], \IPS\HTMLENTITIES, 'UTF-8', FALSE ) : htmlspecialchars( $key, \IPS\HTMLENTITIES, 'UTF-8', FALSE );
}
return implode( ', ', $return );
}
else
{
return ( isset( $this->extra[ $value ] ) ? htmlentities( $this->extra[ $value ], \IPS\HTMLENTITIES, 'UTF-8', FALSE ) : htmlentities( $value, \IPS\HTMLENTITIES, 'UTF-8', FALSE ) );
return ( isset( $this->extra[ $value ] ) ? htmlspecialchars( $this->extra[ $value ], \IPS\HTMLENTITIES, 'UTF-8', FALSE ) : htmlspecialchars( $value, \IPS\HTMLENTITIES, 'UTF-8', FALSE ) );
}
break;
case 'Member':
@@ -1099,6 +1191,13 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
{
return NULL;
}
else
{
return implode( ', ', array_map( function( $id )
{
return \IPS\Member::load( $id )->link();
}, explode( ',', $value ) ) );
}
break;
case 'Url':
if ( \IPS\Dispatcher::hasInstance() AND class_exists( '\IPS\Dispatcher', FALSE ) and \IPS\Dispatcher::i()->controllerLocation === 'front' )
@@ -1121,6 +1220,33 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
return \IPS\Lang::wordbreak( $time->localeDate() );
break;
case 'Item':
if ( ! is_array( $value ) and mb_strstr( $value, ',' ) )
{
$value = explode( ',', $value );
}
else
{
$value = array( $value );
}
if ( count( $value ) and isset( $this->extra['database'] ) and $this->extra['database'] )
{
$results = array();
$class = '\IPS\cms\Records' . $this->extra['database'];
$field = $class::$databasePrefix . $class::$databaseColumnMap['title'];
$where = array( \IPS\Db::i()->in( $class::$databaseColumnId, $value ) );
foreach( $class::getItemsWithPermission( array( $where ), $field, NULL ) as $item )
{
$results[] = $item;
}
return \IPS\Theme::i()->getTemplate( 'global', 'cms', 'front' )->basicRelationship( $results );
}
return NULL;
break;
}
/* Formatters */
@@ -1142,40 +1268,46 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
*/
public function applyFormatter( $value )
{
switch( $this->format_opts )
if ( is_array( $this->format_opts ) and count( $this->format_opts ) )
{
case 'strtolower':
$value = mb_convert_case( $value, MB_CASE_LOWER );
break;
case 'strtoupper':
$value = mb_convert_case( $value, MB_CASE_UPPER );
break;
case 'ucfirst':
$value = ( mb_strtoupper( mb_substr( $value, 0, 1 ) ) . mb_substr( $value, 1, mb_strlen( $value ) ) );
break;
case 'ucwords':
$value = mb_convert_case( $value, MB_CASE_TITLE );
break;
case 'punct':
$value = preg_replace( "/\?{1,}/" , "?" , $value );
$value = preg_replace( "/(!){1,}/" , "!" , $value );
break;
case 'numerical':
$value = \IPS\Member::loggedIn()->language()->formatNumber( $value );
break;
case 'bold':
$value = '<strong>' . $value . '</strong>';
break;
case 'italic':
$value = '<em>' . $value . '</em>';
break;
foreach( $this->format_opts as $id => $type )
{
switch( $type )
{
case 'strtolower':
$value = mb_convert_case( $value, MB_CASE_LOWER );
break;
case 'strtoupper':
$value = mb_convert_case( $value, MB_CASE_UPPER );
break;
case 'ucfirst':
$value = ( mb_strtoupper( mb_substr( $value, 0, 1 ) ) . mb_substr( $value, 1, mb_strlen( $value ) ) );
break;
case 'ucwords':
$value = mb_convert_case( $value, MB_CASE_TITLE );
break;
case 'punct':
$value = preg_replace( "/\?{1,}/" , "?" , $value );
$value = preg_replace( "/(&#33;){1,}/" , "&#33;" , $value );
break;
case 'numerical':
$value = \IPS\Member::loggedIn()->language()->formatNumber( $value );
break;
case 'bold':
$value = '<strong>' . $value . '</strong>';
break;
case 'italic':
$value = '<em>' . $value . '</em>';
break;
}
}
}
return $value;
@@ -1242,9 +1374,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
*/
public function canBeTitleField()
{
$no = array( 'Address' );
if ( $this->is_multiple or in_array( ucfirst( $this->type ), $no ) )
if ( $this->is_multiple or in_array( ucfirst( $this->type ), static::$cannotBeTitleFields ) )
{
return FALSE;
}
@@ -1261,7 +1391,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
{
$no = array();
if ( $this->is_multiple or in_array( ucfirst( $this->type ), $no ) )
if ( $this->is_multiple or in_array( ucfirst( $this->type ), static::$cannotBeContentFields ) )
{
return FALSE;
}
@@ -1331,30 +1461,31 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
$form->add( new \IPS\Helpers\Form\Translatable( 'field_title', NULL, TRUE, array( 'app' => 'core', 'key' => ( $this->id ? static::$langKey . '_' . $this->id : NULL ) ) ) );
$form->add( new \IPS\Helpers\Form\Translatable( 'field_description', NULL, FALSE, array( 'app' => 'core', 'key' => ( $this->id ? static::$langKey . '_' . $this->id . '_desc' : NULL ) ) ) );
$displayDefaults = array( 'field_display_listing_json_badge', 'field_display_listing_json_badge_right', 'field_display_listing_json_custom', 'field_display_display_json_badge', 'field_display_display_json_custom' );
$displayDefaults = array( 'field_display_listing_json_badge', 'field_display_listing_json_badge_right', 'field_display_listing_json_custom', 'field_display_display_json_badge', 'field_display_display_json_custom', 'field_display_display_json_where' );
$options = array_merge( array(
'Address' => 'pf_type_Address',
'Checkbox' => 'pf_type_Checkbox',
'Address' => 'pf_type_Address',
'Checkbox' => 'pf_type_Checkbox',
'CheckboxSet' => 'pf_type_CheckboxSet',
'Codemirror'=> 'pf_type_Codemirror',
'Date' => 'pf_type_Date',
'Editor' => 'pf_type_Editor',
'Email' => 'pf_type_Email',
'Member' => 'pf_type_Member',
'Number' => 'pf_type_Number',
'Password' => 'pf_type_Password',
'Radio' => 'pf_type_Radio',
'Select' => 'pf_type_Select',
'Tel' => 'pf_type_Tel',
'Text' => 'pf_type_Text',
'TextArea' => 'pf_type_TextArea',
'Upload' => 'pf_type_Upload',
'Url' => 'pf_type_Url',
'YesNo' => 'pf_type_YesNo',
'Youtube' => 'pf_type_Youtube',
'Spotify' => 'pf_type_Spotify',
'Soundcloud'=> 'pf_type_Soundcloud',
'Codemirror' => 'pf_type_Codemirror',
'Item' => 'pf_type_Relational',
'Date' => 'pf_type_Date',
'Editor' => 'pf_type_Editor',
'Email' => 'pf_type_Email',
'Member' => 'pf_type_Member',
'Number' => 'pf_type_Number',
'Password' => 'pf_type_Password',
'Radio' => 'pf_type_Radio',
'Select' => 'pf_type_Select',
'Tel' => 'pf_type_Tel',
'Text' => 'pf_type_Text',
'TextArea' => 'pf_type_TextArea',
'Upload' => 'pf_type_Upload',
'Url' => 'pf_type_Url',
'YesNo' => 'pf_type_YesNo',
'Youtube' => 'pf_type_Youtube',
'Spotify' => 'pf_type_Spotify',
'Soundcloud' => 'pf_type_Soundcloud',
), static::$additionalFieldTypes );
$toggles = array(
@@ -1365,6 +1496,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
'Date' => array_merge( array( 'field_default_value', 'field_date_time_override' ), $displayDefaults ),
'Editor' => array_merge( array( 'field_max_length', 'field_default_value', 'field_truncate' ), $displayDefaults ),
'Email' => array_merge( array( 'field_max_length', 'field_default_value' ), $displayDefaults ),
'Item' => array_merge( array( 'field_is_multiple', 'field_relational_db' ), $displayDefaults ),
'Member' => array_merge( array( 'field_is_multiple' ), $displayDefaults ),
'Number' => array_merge( array( 'field_default_value' ), $displayDefaults ),
'Password' => array_merge( array( 'field_default_value' ), $displayDefaults ),
@@ -1385,7 +1517,30 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
{
$toggles[ $k ] = isset( static::$additionalFieldToggles[ $k ] ) ? static::$additionalFieldToggles[ $k ] : array( 'pf_not_null' );
}
/* Title or content? */
if ( $this->id )
{
$database = \IPS\cms\Databases::load( static::$customDatabaseId );
if ( $this->id == $database->field_title )
{
foreach( static::$cannotBeTitleFields as $type )
{
unset( $options[ $type ] );
unset( $toggles[ $type ] );
}
}
else if ( $this->id == $database->field_content )
{
foreach( static::$cannotBeContentFields as $type )
{
unset( $options[ $type ] );
unset( $toggles[ $type ] );
}
}
}
ksort( $options );
if ( !$this->_new )
@@ -1406,6 +1561,26 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
'toggles' => $toggles
) ) );
/* Relational specific */
$databases = array();
$disabled = array();
foreach( \IPS\cms\Databases::databases() as $db )
{
if ( $db->page_id and $db->id !== static::$customDatabaseId )
{
$databases[ $db->id ] = $db->_title;
}
}
if ( ! count( $databases ) )
{
$databases[0] = \IPS\Member::loggedIn()->language()->addToStack('cms_relational_field_no_dbs');
$disabled[] = 0;
}
$form->add( new \IPS\Helpers\Form\Select( 'field_relational_db', ( isset( $this->extra['database'] ) ? $this->extra['database'] : NULL ), FALSE, array( 'options' => $databases, 'disabled' => $disabled ), NULL, NULL, NULL, 'field_relational_db' ) );
/* Upload specific */
$form->add( new \IPS\Helpers\Form\YesNo( 'field_upload_is_multiple', $this->id ? $this->is_multiple : 0, FALSE, array( ), NULL, NULL, NULL, 'field_upload_is_multiple' ) );
$form->add( new \IPS\Helpers\Form\Radio( 'field_upload_is_image', $this->id ? ( ( isset( $this->extra['type'] ) and $this->extra['type'] == 'image' ) ? 'yes' : 'no' ) : 'yes', TRUE, array(
@@ -1592,6 +1767,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
$listingToggles[ $id ] = array( 'field_display_listing_json_badge_right' );
}
$displayOptions['simple'] = $listingOptions['simple'] = \IPS\Theme::i()->getTemplate( 'records', 'cms', 'global' )->fieldDefault( \IPS\Member::loggedIn()->language()->addToStack('cms_badge_label'), \IPS\Member::loggedIn()->language()->addToStack('cms_badge_value' ) );
$displayOptions['custom'] = $listingOptions['custom'] = \IPS\Member::loggedIn()->language()->addToStack('field_display_custom');
$displayOptions['none'] = $listingOptions['none'] = \IPS\Member::loggedIn()->language()->addToStack('field_display_none');
@@ -1659,6 +1835,9 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
}, NULL, NULL, 'field_display_display_json_custom' ) );
/* Display where? */
$form->add( new \IPS\Helpers\Form\Radio( 'field_display_display_json_where', ( isset( $displayJson['display']['where'] ) ? $displayJson['display']['where'] : 'top' ), FALSE, array( 'options' => array( 'top' => 'cms_field_display_top', 'bottom' => 'cms_field_display_bottom' ) ), NULL, NULL, NULL, 'field_display_display_json_where' ) );
/* Media display */
$form->add( new \IPS\Helpers\Form\Radio( 'media_display_display_method', $mediaDisplayDefault, FALSE, array( 'options' => $mediaListingOptions ), NULL, NULL, NULL, 'media_display_display_method' ) );
@@ -1723,7 +1902,6 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
$values['field_extra'] = $extra;
}
}
if ( $values['field_type'] === 'Select' )
{
$columnDefinition['type'] = 'TEXT';
@@ -1817,15 +1995,26 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
{
\IPS\Db::i()->addColumn( static::$contentDatabaseTable, $columnDefinition );
if ( $values['field_type'] != 'Upload' )
if ( ! empty( $values['field_filter'] ) and $values['field_type'] != 'Upload' )
{
if ( $columnDefinition['type'] == 'TEXT' )
try
{
\IPS\Db::i()->addIndex( static::$contentDatabaseTable, array( 'type' => 'fulltext', 'name' => "field_{$this->id}", 'columns' => array( "field_{$this->id}" ) ) );
if ( $columnDefinition['type'] == 'TEXT' )
{
\IPS\Db::i()->addIndex( static::$contentDatabaseTable, array( 'type' => 'fulltext', 'name' => "field_{$this->id}", 'columns' => array( "field_{$this->id}" ) ) );
}
else
{
\IPS\Db::i()->addIndex( static::$contentDatabaseTable, array( 'type' => 'key', 'name' => "field_{$this->id}", 'columns' => array( "field_{$this->id}" ) ) );
}
}
else
catch( \IPS\Db\Exception $e )
{
\IPS\Db::i()->addIndex( static::$contentDatabaseTable, array( 'type' => 'key', 'name' => "field_{$this->id}", 'columns' => array( "field_{$this->id}" ) ) );
if ( $e->getCode() !== 1069 )
{
# 1069: MyISAM can only have 64 indexes per table. This should be really rare though so we silently ignore it.
throw $e;
}
}
}
}
@@ -1837,28 +2026,60 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
\IPS\Db::i()->dropIndex( static::$contentDatabaseTable, "field_{$this->id}" );
\IPS\Db::i()->dropColumn( static::$contentDatabaseTable, "field_{$this->id}" );
}
catch ( \IPS\Db\Exception $e )
{
}
catch ( \IPS\Db\Exception $e ) { }
\IPS\Db::i()->addColumn( static::$contentDatabaseTable, $columnDefinition );
if ( $values['field_type'] != 'Upload' )
{
if ( $columnDefinition['type'] == 'TEXT' )
try
{
\IPS\Db::i()->addIndex( static::$contentDatabaseTable, array( 'type' => 'fulltext', 'name' => "field_{$this->id}", 'columns' => array( "field_{$this->id}" ) ) );
if ( $columnDefinition['type'] == 'TEXT' )
{
\IPS\Db::i()->addIndex( static::$contentDatabaseTable, array( 'type' => 'fulltext', 'name' => "field_{$this->id}", 'columns' => array( "field_{$this->id}" ) ) );
}
else
{
\IPS\Db::i()->addIndex( static::$contentDatabaseTable, array( 'type' => 'key', 'name' => "field_{$this->id}", 'columns' => array( "field_{$this->id}" ) ) );
}
}
else
catch( \IPS\Db\Exception $e )
{
\IPS\Db::i()->addIndex( static::$contentDatabaseTable, array( 'type' => 'key', 'name' => "field_{$this->id}", 'columns' => array( "field_{$this->id}" ) ) );
if ( $e->getCode() !== 1069 )
{
# 1069: MyISAM can only have 64 indexes per table. This should be really rare though so we silently ignore it.
throw $e;
}
}
}
}
elseif ( isset( static::$contentDatabaseTable ) AND isset( $columnDefinition ) )
{
\IPS\Db::i()->dropIndex( static::$contentDatabaseTable, "field_{$this->id}" );
\IPS\Db::i()->changeColumn( static::$contentDatabaseTable, "field_{$this->id}", $columnDefinition );
if ( $values['field_filter'] and $values['field_type'] != 'Upload' )
{
try
{
if ( $columnDefinition['type'] == 'TEXT' )
{
\IPS\Db::i()->addIndex( static::$contentDatabaseTable, array( 'type' => 'fulltext', 'name' => "field_{$this->id}", 'columns' => array( "field_{$this->id}" ) ) );
}
else
{
\IPS\Db::i()->addIndex( static::$contentDatabaseTable, array( 'type' => 'key', 'name' => "field_{$this->id}", 'columns' => array( "field_{$this->id}" ) ) );
}
}
catch( \IPS\Db\Exception $e )
{
if ( $e->getCode() !== 1069 )
{
# 1069: MyISAM can only have 64 indexes per table. This should be really rare though so we silently ignore it.
throw $e;
}
}
}
}
/* Save the name and desctipn */
@@ -1998,6 +2219,11 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
{
$displayJson['display']['method'] = $values['field_display_display_json_badge'];
}
if ( isset( $values['field_display_display_json_where'] ) )
{
$displayJson['display']['where'] = $values['field_display_display_json_where'];
}
}
}
@@ -2041,13 +2267,24 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
}
}
/* Special relational stuff */
if ( isset( $values['field_type'] ) AND $values['field_type'] === 'Item' )
{
if ( array_key_exists( 'field_relational_db', $values ) and empty( $values['field_relational_db'] ) )
{
throw new \LogicException( \IPS\Member::loggedIn()->language()->addToStack('cms_relational_field_no_db_selected') );
}
$values['extra'] = array( 'database' => $values['field_relational_db'] );
}
if ( ! $this->new AND isset( $values['field_default_update_existing'] ) AND $values['field_default_update_existing'] and $values['field_default_value'] !== $this->default_value )
{
$this->_updateDefaultValue = TRUE;
$this->_oldDefaultValue = $this->default_value;
}
foreach( array( 'field_upload_is_multiple', 'field_default_update_existing', 'field_date_time_override', 'field_date_timezone', 'field_upload_is_image', 'field_image_size', 'field_title', 'field_display_display_json_badge', 'field_display_display_json_custom', 'field_display_listing_json_badge', 'field_display_listing_json_custom', 'field_display_listing_json_badge_right', 'media_display_listing_method', 'media_display_display_method', 'field_show_map_listing', 'field_show_map_listing_dims', 'field_show_map_display', 'field_show_map_display_dims' ) as $field )
foreach( array( 'field_relational_db', 'field_upload_is_multiple', 'field_default_update_existing', 'field_date_time_override', 'field_date_timezone', 'field_upload_is_image', 'field_image_size', 'field_title', 'field_display_display_json_badge', 'field_display_display_json_custom', 'field_display_listing_json_badge', 'field_display_listing_json_custom', 'field_display_listing_json_badge_right', 'media_display_listing_method', 'media_display_display_method', 'field_show_map_listing', 'field_show_map_listing_dims', 'field_show_map_display', 'field_show_map_display_dims', 'field_display_display_json_where' ) as $field )
{
if ( array_key_exists( $field, $values ) )
{
@@ -2086,7 +2323,7 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
*/
protected function canKeepValueOnChange( $newType )
{
$custom = array( 'Youtube', 'Spotify', 'Soundcloud');
$custom = array( 'Youtube', 'Spotify', 'Soundcloud', 'Relational' );
if ( ! in_array( $this->type, $custom ) )
{
@@ -2131,15 +2368,15 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
{
unset( \IPS\Data\Store::i()->$functionName );
}
$key = 'cms_fieldids_' . static::$customDatabaseId;
if ( isset( \IPS\Data\Store::i()->$key ) )
{
unset( \IPS\Data\Store::i()->$key );
}
if ( $this->_new )
{
parent::save();
}
else
{
parent::save();
}
parent::save();
}
/**
@@ -2152,7 +2389,14 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
{
static::$contentDatabaseTable = 'cms_custom_database_' . static::$customDatabaseId;
static::$cache = array();
$key = 'cms_fieldids_' . static::$customDatabaseId;
if ( isset( \IPS\Data\Store::i()->$key ) )
{
unset( \IPS\Data\Store::i()->$key );
}
parent::delete();
if( $skipDrop === TRUE )
@@ -2302,9 +2546,28 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
if ( $this->is_multiple and ! is_array( $value ) and mb_stristr( $value, ',' ) )
{
$value = explode( ',', $value );
$exp = explode( ',', $value );
$value = array();
foreach( $exp as $val )
{
if ( is_numeric( $val ) and intval( $val ) == $val )
{
$value[] = intval( $val );
}
else
{
$value[] = $val;
}
}
}
else
{
if ( is_numeric( $value ) and intval( $value ) == $value )
{
$value = intval( $value );
}
}
$json = $this->extra;
$options['options'] = ( $json ) ? $json : array();
break;
@@ -2356,6 +2619,10 @@ class _Fields extends \IPS\CustomField implements \IPS\Node\Permissions
}
}
break;
case 'Item':
$options['maxItems'] = ( $this->is_multiple ) ? NULL : 1;
$options['class'] = '\IPS\cms\Records' . $this->extra['database'];
break;
}
+341
View File
@@ -0,0 +1,341 @@
<?php
/**
* @brief Folder Model
* @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 07 July 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\cms\Media;
/* 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;
}
/**
* @brief Folder Model
*/
class _Folder extends \IPS\Node\Model
{
/**
* Munge different record types
*
*
* @return array
*/
public static function munge()
{
$rows = array();
$args = func_get_args();
foreach( $args as $arg )
{
foreach( $arg as $id => $obj )
{
$rows[ $obj->getSortableName() . '_' . $obj::$databaseTable . '_' . $obj->id ] = $obj;
}
}
ksort( $rows );
return $rows;
}
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons;
/**
* @brief [ActiveRecord] Database Table
*/
public static $databaseTable = 'cms_media_folders';
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'media_folder_';
/**
* @brief [ActiveRecord] ID Database Column
*/
public static $databaseColumnId = 'id';
/**
* @brief [ActiveRecord] Database ID Fields
*/
protected static $databaseIdFields = array('media_folder_path');
/**
* @brief [Node] Parent ID Database Column
*/
public static $databaseColumnParent = 'parent';
/**
* @brief [Node] Parent ID Root Value
* @note This normally doesn't need changing though some legacy areas use -1 to indicate a root node
*/
public static $databaseColumnParentRootValue = 0;
/**
* @brief [Node] Order Database Column
*/
public static $databaseColumnOrder = 'path';
/**
* @brief [Node] Node Title
*/
public static $nodeTitle = 'folder';
/**
* @brief [Node] Subnode class
*/
public static $subnodeClass = 'IPS\cms\Media';
/**
* @brief [Node] Show forms modally?
*/
public static $modalForms = TRUE;
protected static $restrictions = array(
'app' => 'cms',
'module' => 'pages',
'all' => 'media_manage',
'prefix' => 'media_'
);
/**
* [Node] Get Title
*
* @return string|null
*/
protected function get__title()
{
return $this->name;
}
/**
* Get sortable name
*
* @return string
*/
public function getSortableName()
{
return $this->name;
}
/**
* [Node] Get buttons to display in tree
* Example code explains return value
* @endcode
* @param string $url Base URL
* @param bool $subnode Is this a subnode?
* @return array
*/
public function getButtons( $url, $subnode=FALSE )
{
$buttons = parent::getButtons( $url, $subnode );
$return = array();
if ( isset( $buttons['copy'] ) )
{
unset( $buttons['copy'] );
}
if ( isset( $buttons['add'] ) )
{
$buttons['add']['icon'] = 'folder-open';
$buttons['add']['title'] = 'cms_add_media_folder';
$buttons['add']['data'] = array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('cms_add_media_folder') );
$buttons['add']['link'] = $url->setQueryString( array( 'subnode' => 0, 'do' => 'form', 'parent' => $this->_id ) );
$buttons['add_page'] = array(
'icon' => 'plus-circle',
'title' => 'cms_add_media',
'link' => $url->setQueryString( array( 'subnode' => 1, 'do' => 'add', 'parent' => $this->_id ) ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('cms_add_media') )
);
}
/* Re-arrange */
if ( isset( $buttons['edit'] ) )
{
$return['edit'] = $buttons['edit'];
}
if ( isset( $buttons['add_page'] ) )
{
$return['add_page'] = $buttons['add_page'];
}
if ( isset( $buttons['add'] ) )
{
$return['add'] = $buttons['add'];
}
if ( isset( $buttons['delete'] ) )
{
$return['delete'] = $buttons['delete'];
}
return $return;
}
/**
* [Node] Add/Edit Form
*
* @param \IPS\Helpers\Form $form The form
* @return void
*/
public function form( &$form )
{
/* Build form */
$form->add( new \IPS\Helpers\Form\Text( 'media_folder_name', $this->id ? $this->name : '', TRUE, array( 'maxLength' => 64 ), function( $val )
{
try
{
$test = \IPS\cms\Media\Folder::load( \IPS\Http\Url::seoTitle( $val ), 'media_folder_name' );
if ( ! empty( \IPS\Request::i()->id ) and $test->id != \IPS\Request::i()->id )
{
throw new \InvalidArgumentException('content_folder_name_in_use');
}
}
catch ( \OutOfRangeException $e )
{
}
} ) );
$form->add( new \IPS\Helpers\Form\Node( 'media_folder_parent', $this->parent ? $this->parent : 0, FALSE, array(
'class' => '\IPS\cms\Media\Folder',
'zeroVal' => 'node_no_parent',
'permissionCheck' => function( $node )
{
if ( ! isset( \IPS\Request::i()->id ) )
{
return true;
}
if ( ! isset( \IPS\Request::i()->parent ) )
{
return $node->id != \IPS\Request::i()->id;
}
}
) ) );
}
/**
* @brief Original parent ID
*/
protected $origParentId;
/**
* @brief Original parent Name
*/
protected $origName;
/**
* [Node] Format form values from add/edit form for save
*
* @param array $values Values from the form
* @return array
*/
public function formatFormValues( $values )
{
if ( ! $this->id )
{
$this->save();
}
$this->origParentId = $this->parent;
$this->origName = $this->name;
if ( isset( $values['media_folder_parent'] ) AND ( ! empty( $values['media_folder_parent'] ) OR $values['media_folder_parent'] === 0 ) )
{
$values['parent'] = ( $values['media_folder_parent'] === 0 ) ? 0 : $values['media_folder_parent']->id;
unset( $values['media_folder_parent'] );
}
if( isset( $values['media_folder_name'] ) )
{
$values['name'] = \IPS\Http\Url::seoTitle( $values['media_folder_name'] );
unset( $values['media_folder_name'] );
}
return $values;
}
/**
* [Node] Perform actions after saving the form
*
* @param array $values Values from the form
* @return void
*/
public function postSaveForm( $values )
{
if ( $this->origParentId !== $values['parent'] OR $this->origName !== $values['name'] )
{
$this->resetPath( true );
}
}
/**
* Resets the stored path
*
* @param boolean $recursivelyCheck Recursively reset up and down the tree
* @return void
*/
public function resetPath( $recursivelyCheck=true )
{
$path = array();
foreach( $this->parents() as $obj )
{
$path[] = $obj->name;
}
$this->path = ( count( $path ) ) ? implode( '/', $path ) . '/' . $this->name : $this->name;
/* Save path update */
parent::save();
/* Update media */
\IPS\cms\Media::resetPath( $this->id );
if ( $recursivelyCheck === true )
{
/* Fix children */
foreach( $this->children( NULL, NULL, FALSE ) as $child )
{
$child->resetPath( false );
$child->_recursivelyResetChildPaths();
}
/* Fix parents */
foreach( $this->parents() as $parent )
{
$parent->resetPath( false );
}
}
}
/**
* Recurse through the node tree to reset kids
*
* @return void
*/
protected function _recursivelyResetChildPaths()
{
foreach( $this->children( NULL, NULL, FALSE ) as $child )
{
$child->resetPath( false );
$child->_recursivelyResetChildPaths();
}
}
}
+568
View File
@@ -0,0 +1,568 @@
<?php
/**
* @brief Media Model
* @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 15 Jan 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\cms;
/* 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;
}
/**
* @brief Media Model
*/
class _Media extends \IPS\Node\Model
{
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons;
/**
* @brief [ActiveRecord] Database Table
*/
public static $databaseTable = 'cms_media';
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'media_';
/**
* @brief [ActiveRecord] ID Database Column
*/
public static $databaseColumnId = 'id';
/**
* @brief [ActiveRecord] Database ID Fields
*/
protected static $databaseIdFields = array('media_full_path');
/**
* @brief [Node] Parent Node ID Database Column
*/
public static $parentNodeColumnId = 'parent';
/**
* @brief [Node] Parent Node Class
*/
public static $parentNodeClass = 'IPS\cms\Media\Folder';
/**
* @brief [Node] Parent ID Database Column
*/
public static $databaseColumnOrder = 'filename';
/**
* @brief [Node] Show forms modally?
*/
public static $modalForms = TRUE;
/**
* @brief [Node] Title
*/
public static $nodeTitle = 'page';
/**
* @brief [Node] ACP Restrictions
* @code
array(
'app' => 'core', // The application key which holds the restrictrions
'module' => 'foo', // The module key which holds the restrictions
'map' => array( // [Optional] The key for each restriction - can alternatively use "prefix"
'add' => 'foo_add',
'edit' => 'foo_edit',
'permissions' => 'foo_perms',
'delete' => 'foo_delete'
),
'all' => 'foo_manage', // [Optional] The key to use for any restriction not provided in the map (only needed if not providing all 4)
'prefix' => 'foo_', // [Optional] Rather than specifying each key in the map, you can specify a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
* @endcode
*/
protected static $restrictions = array(
'app' => 'cms',
'module' => 'pages',
'prefix' => 'media_'
);
/**
* Set Default Values
*
* @return void
*/
public function setDefaultValues()
{
$this->parent = 0;
$this->full_path = '';
}
/**
* Resets a media path
*
* @param int $folderId Folder ID to reset
* @return void
*/
public static function resetPath( $folderId )
{
try
{
$path = \IPS\cms\Media\Folder::load( $folderId )->path;
}
catch ( \OutOfRangeException $ex )
{
throw new \OutOfRangeException;
}
$children = static::getChildren( $folderId );
foreach( $children as $id => $obj )
{
$obj->setFullPath( $path );
}
}
/**
* Get all children of a specific folder.
*
* @param INT $folderId Folder ID to fetch children from
* @return array
*/
public static function getChildren( $folderId=0 )
{
$children = array();
foreach( \IPS\Db::i()->select( '*', static::$databaseTable, array( 'media_parent=?', intval( $folderId ) ), 'media_filename ASC' ) as $child )
{
$children[ $child[ static::$databasePrefix . static::$databaseColumnId ] ] = static::load( $child[ static::$databasePrefix . static::$databaseColumnId ] );
}
return $children;
}
/**
* Delete media by file ids
*
* @param array $ids Array of IDs to remove
* @return void
*/
public static function deleteByFileIds( $ids=array() )
{
foreach( $ids as $id )
{
try
{
static::load( $id )->delete();
}
catch( \Exception $ex ) { }
}
}
/**
* Get URL
*
* @return \IPS\Http\Url object
*/
public function url()
{
if ( \IPS\Theme::designersModeEnabled() )
{
return \IPS\Settings::i()->base_url . 'themes/cms/media/' . $this->full_path;
}
else
{
return (string)\IPS\File::get( 'cms_Media', $this->file_object )->url;
}
}
/**
* [ActiveRecord] Delete Record
*
* @return void
*/
public function delete()
{
try
{
if ( $this->file_object )
{
\IPS\File::get( 'cms_Media', $this->file_object )->delete();
}
}
catch( \Exception $ex ) { }
parent::delete();
}
/**
* [Node] Get buttons to display in tree
* Example code explains return value
* @endcode
* @param string $url Base URL
* @param bool $subnode Is this a subnode?
* @return array
*/
public function getButtons( $url, $subnode=FALSE )
{
$buttons = parent::getButtons( $url, $subnode );
$delete = NULL;
if ( isset( $buttons['add' ] ) )
{
unset( $buttons['add'] );
}
if ( isset( $buttons['delete'] ) )
{
$delete = $buttons['delete'];
unset( $buttons['delete'] );
}
if ( isset( $buttons['copy' ] ) )
{
unset( $buttons['copy'] );
}
$buttons['key'] = array(
'icon' => 'file-code-o',
'title' => 'cms_media_key',
'link' => \IPS\Http\Url::internal( 'app=cms&module=pages&controller=media&do=key&id=' . $this->id ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('cms_media_key') )
);
if ( $this->is_image )
{
$buttons['preview'] = array(
'icon' => 'search',
'title' => 'cms_media_preview',
'link' => \IPS\Http\Url::internal( 'app=cms&module=pages&controller=media&do=preview&id=' . $this->id ),
'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('cms_media_preview') )
);
}
if ( $delete )
{
$buttons['delete'] = $delete;
}
return $buttons;
}
/**
* [Node] Add/Edit Form
*
* @note This is not used currently. See \IPS\cms\modules\admin\media.php upload()
* @param \IPS\Helpers\Form $form The form
* @return void
*/
public function form( &$form )
{
/* Build form */
$form->add( new \IPS\Helpers\Form\Upload( 'media_filename', ( ( $this->filename ) ? \IPS\File::get( 'cms_Media', $this->file_object ) : NULL ), FALSE, array( 'obscure' => FALSE, 'maxFileSize' => 5, 'storageExtension' => 'core_Theme', 'storageContainer' => 'pages_media' ), NULL, NULL, NULL, 'media_filename' ) );
$form->add( new \IPS\Helpers\Form\Node( 'media_parent', $this->parent ? $this->parent : 0, FALSE, array(
'class' => '\IPS\cms\Media\Folder',
'zeroVal' => 'node_no_parent'
) ) );
}
/**
* [Node] Format form values from add/edit form for save
*
* @note This is not used currently. See \IPS\cms\modules\admin\media.php upload()
* @param array $values Values from the form
* @return array
*/
public function formatFormValues( $values )
{
if ( isset( $values['media_parent'] ) AND ( ! empty( $values['media_parent'] ) OR $values['media_parent'] === 0 ) )
{
$values['parent'] = ( $values['media_parent'] === 0 ) ? 0 : $values['media_parent']->id;
unset( $values['media_parent'] );
}
if ( isset( $values['media_filename'] ) )
{
$filename = $values['media_filename']->originalFilename;
if ( ! $this->_new and $this->file_object )
{
$prefix = $this->parent . '_';
if ( mb_strstr( $filename, $prefix ) )
{
$filename = mb_substr( $filename, mb_strlen( $prefix ) );
}
}
$values['filename'] = $filename;
$values['filename_stored'] = $values['parent'] . '_' . $values['filename'];
$values['is_image'] = $values['media_filename']->isImage();
/* We need to rename it */
try
{
$values['media_filename']->delete();
}
catch( \Exception $ex ) { }
$values['file_object'] = (string) \IPS\File::create( 'cms_Media', $values['filename_stored'], $values['media_filename']->contents(), 'pages_media', TRUE, NULL, FALSE );
unset( $values['media_filename'] );
}
if ( $this->_new )
{
$values['added'] = time();
}
return $values;
}
/**
* [Node] Perform actions after saving the form
*
* @note This is not used currently. See \IPS\cms\modules\admin\media.php upload()
* @param array $values Values from the form
* @return void
*/
public function postSaveForm( $values )
{
$this->setFullPath( ( $this->parent ? \IPS\cms\Media\Folder::load( $this->parent )->path : '' ) );
$this->save();
}
/**
* Get sortable name
*
* @return string
*/
public function getSortableName()
{
return $this->full_path;
}
/**
* Resets a folder path
*
* @param string $path Path to reset
* @return void
*/
public function setFullPath( $path )
{
$this->full_path = trim( $path . '/' . $this->filename, '/' );
$this->save();
}
/**
* Write media to disk for designer's mode
*
* @return void
*/
public static function exportDesignersModeMedia()
{
foreach( \IPS\Db::i()->select( '*', 'cms_media' ) as $media )
{
/* We could use recursive mode but it wouldn't correctly chmod the intermediate dirs */
$bits = explode( '/', "/themes/cms/media/" . $media['media_full_path'] );
$dir = '';
$filename = array_pop( $bits );
foreach( $bits as $part )
{
$dir .= $part . '/';
if ( ! is_dir( \IPS\ROOT_PATH . '/' . trim( $dir, '/' ) ) )
{
mkdir( \IPS\ROOT_PATH . '/' . trim( $dir, '/' ), \IPS\IPS_FOLDER_PERMISSION );
chmod( \IPS\ROOT_PATH . '/' . trim( $dir, '/' ), \IPS\IPS_FOLDER_PERMISSION );
}
}
\file_put_contents( \IPS\ROOT_PATH . '/' . trim( $dir, '/' ) . '/' . $filename, \IPS\File::get( 'cms_Media', $media['media_file_object'] )->contents() );
@chmod( \IPS\ROOT_PATH . '/' . trim( $dir, '/' ) . '/' . $filename, \IPS\IPS_FILE_PERMISSION );
}
}
/**
* Removes folders that are empty
*
* @return void
*/
public static function removeEmptyFolders()
{
$folders = iterator_to_array( \IPS\Db::i()->select( 'DISTINCT(media_parent)', 'cms_media', array( 'media_parent > 0' ) ) );
$allFolders = iterator_to_array( \IPS\Db::i()->select( '*', 'cms_media_folders' )->setKeyField( 'media_folder_id' ) );
foreach( $folders as $id )
{
if ( isset( $allFolders[ $id ] ) )
{
$currentParent = $allFolders[ $id ]['media_folder_parent'];
$try = 0;
while( $currentParent )
{
if ( $try++ > 50 )
{
/* Prevent broken associations from preventing execution */
break;
}
if ( ! in_array( $currentParent, $folders ) )
{
$folders[] = $currentParent;
}
$currentParent = $allFolders[ $currentParent ]['media_folder_parent'];
}
}
}
\IPS\Db::i()->delete( 'cms_media_folders', array( \IPS\Db::i()->in( 'media_folder_id', array_values( $folders ), TRUE ) ) );
}
/**
* Import media from disk for designer's mode
*
* @return void
*/
public static function importDesignersModeMedia()
{
$path = \IPS\ROOT_PATH . '/themes/cms/media';
$seen = array();
if ( is_dir( $path ) )
{
static::importDesignersModeMediaRecurse( $seen, $path );
}
\IPS\Db::i()->delete( 'cms_media', array( \IPS\Db::i()->in( 'media_id', $seen, TRUE ) ) );
static::removeEmptyFolders();
}
/**
* Import media from disk for designer's mode recursive method
*
* @return void
*/
public static function importDesignersModeMediaRecurse( &$seen, $path )
{
if ( is_dir( $path ) )
{
foreach ( new \DirectoryIterator( $path ) as $dir )
{
if ( $dir->isDot() || mb_substr( $dir->getFilename(), 0, 1 ) === '.' )
{
continue;
}
if ( $dir->isDir() )
{
static::importDesignersModeMediaRecurse( $seen, $path . '/' . $dir->getFilename() );
}
else
{
$contents = \file_get_contents( $dir->getRealPath() );
/* Create */
$seen[] = static::createMedia( trim( str_replace( \IPS\ROOT_PATH . '/themes/cms/media', '', $dir->getRealPath() ), '/' ), $contents );
}
}
}
}
/**
* Create new media file from a disk file. If the file exists and is unchanged, it will not be updated
*
* @param string $path File path (/folder/file.txt)
* @param string $contents File contents
* @return int ID of existing media or of new media
*/
public static function createMedia( $path, $contents )
{
try
{
$test = static::load( $path, 'media_full_path' );
$test->file_object = \IPS\File::create( 'cms_Media', $test->filename_stored, $contents, 'pages_media', TRUE, NULL, FALSE );
$test->save();
return $test->id;
}
catch( \RuntimeException $ex )
{
try
{
\IPS\File::get( 'cms_Media', $path );
}
catch( \Exception $x )
{
/* File doesn't exist already */
throw $ex;
}
}
catch( \OutOfRangeException $ex )
{
/* It doesn't exist */
$exploded = explode( '/', $path );
$filename = array_pop( $exploded );
$folderId = 0;
if ( count( $exploded ) )
{
$testDir = trim( implode( '/', $exploded ), '/' );
try
{
$test = \IPS\cms\Media\Folder::load( $testDir, 'media_folder_path' );
/* Yep */
$folderId = $test->id;
}
catch( \OutOfRangeException $ex )
{
$testDir = '';
foreach( $exploded as $dir )
{
$testDir = trim( $testDir . '/' . $dir, '/' );
try
{
$test = \IPS\cms\Media\Folder::load( $testDir, 'media_folder_path' );
$folderId = $test->id;
}
catch( \OutOfRangeException $ex )
{
$folder = new \IPS\cms\Media\Folder;
$folder->parent = $folderId;
$folder->name = $dir;
$folder->path = $testDir;
$folder->save();
$folderId = $folder->id;
}
}
}
}
$media = new \IPS\cms\Media;
$media->parent = $folderId;
$media->filename = $filename;
$media->added = time();
$media->full_path = $path;
$media->filename_stored = $folderId . '_' . $filename;
$media->file_object = \IPS\File::create( 'cms_Media', $media->filename_stored, $contents, 'pages_media', TRUE, NULL, FALSE );
$media->is_image = $media->file_object->isImage();
$media->save();
return $media->id;
}
}
}
-434
View File
@@ -1,434 +0,0 @@
<?php
/**
* @brief Menu Model
* @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 15 Sept 2014
* @version SVN_VERSION_NUMBER
*/
namespace IPS\cms\Pages;
/* 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;
}
/**
* @brief Menu Model
*/
class _Menu extends \IPS\Node\Model
{
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons;
/**
* @brief [ActiveRecord] Database Table
*/
public static $databaseTable = 'cms_page_menu';
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'menu_';
/**
* @brief [ActiveRecord] ID Database Column
*/
public static $databaseColumnId = 'id';
/**
* @brief [ActiveRecord] Database ID Fields
*/
protected static $databaseIdFields = array();
/**
* @brief [Node] Parent ID Database Column
*/
public static $databaseColumnParent = 'parent_id';
/**
* @brief [Node] Parent ID Root Value
* @note This normally doesn't need changing though some legacy areas use -1 to indicate a root node
*/
public static $databaseColumnParentRootValue = 0;
/**
* @brief [Node] Order Database Column
*/
public static $databaseColumnOrder = 'position';
/**
* @brief [Node] Node Title
*/
public static $nodeTitle = 'cms_menu';
/**
* @brief [Node] Show forms modally?
*/
public static $modalForms = TRUE;
/**
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
*/
public static $titleLangPrefix = 'cms_menu_title_';
/**
* @brief [Node] ACP Restrictions
* @code
array(
'app' => 'core', // The application key which holds the restrictrions
'module' => 'foo', // The module key which holds the restrictions
'map' => array( // [Optional] The key for each restriction - can alternatively use "prefix"
'add' => 'foo_add',
'edit' => 'foo_edit',
'permissions' => 'foo_perms',
'delete' => 'foo_delete'
),
'all' => 'foo_manage', // [Optional] The key to use for any restriction not provided in the map (only needed if not providing all 4)
'prefix' => 'foo_', // [Optional] Rather than specifying each key in the map, you can specify a prefix, and it will automatically look for restrictions with the key "[prefix]_add/edit/permissions/delete"
* @endcode
*/
protected static $restrictions = array(
'app' => 'cms',
'module' => 'pages',
'all' => 'page_manage',
'prefix' => 'page_'
);
/**
* Form elements
*
* @param \IPS\cms\Pages\Menu|null $node Menu item
* @return array
*/
public static function formElements( $node=NULL, $forceType=NULL )
{
$form = array();
if ( $forceType === NULL )
{
$form['menu_type'] = new \IPS\Helpers\Form\Select( 'menu_type', ( $node !== NULL ? $node->type : 'page' ), TRUE, array(
'options' => array(
'page' => 'cms_menu_form_type_page',
'url' => 'cms_menu_form_type_url',
'folder' => 'cms_menu_form_type_folder',
#'separator' => 'cms_menu_form_type_separator'
),
'toggles' => array(
'page' => array( 'menu_content_page', 'menu_title_page', 'menu_permission_from_page'),
'url' => array( 'menu_content_url', 'menu_title_url', 'menu_permission' ),
'folder' => array( 'menu_title_folder', 'menu_permission')
)
) );
}
/* Page fields */
if ( $forceType !== 'page' )
{
$pages = array();
foreach( \IPS\cms\Pages\Page::roots() as $id => $page )
{
$pages[ $id ] = $page->_title . ' (' . $page->full_path . ')';
}
$form['menu_content_page'] = new \IPS\Helpers\Form\Select( 'menu_content_page', $node !== NULL ? ( $node->type === 'page' ? $node->content : NULL ) : 0, FALSE, array(
'options' => $pages
), NULL, NULL, NULL, 'menu_content_page' );
}
$form['menu_title_page'] = new \IPS\Helpers\Form\Translatable( 'menu_title_page', NULL, FALSE, array( 'app' => 'cms', 'key' => ( ( ! empty( $node ) and $node->type === 'page' ) ? "cms_menu_title_" . $node->id : NULL ), 'maxLength' => 64 ), NULL, NULL, NULL, 'menu_title_page' );
/* URL Fields */
if ( $forceType === NULL or $forceType === 'url' )
{
$form['menu_content_url'] = new \IPS\Helpers\Form\Text( 'menu_content_url', $node !== NULL ? ( $node->type === 'url' ? $node->content : NULL ) : '', FALSE, array(), NULL, NULL, NULL, 'menu_content_url' );
$form['menu_title_url'] = new \IPS\Helpers\Form\Translatable( 'menu_title_url', NULL, FALSE, array( 'app' => 'cms', 'key' => ( ( ! empty( $node ) and $node->type === 'url' ) ? "cms_menu_title_" . $node->id : NULL ), 'maxLength' => 64 ), NULL, NULL, NULL, 'menu_title_url' );
}
/* Folder fields */
if ( $forceType === NULL or $forceType === 'folder' )
{
$form['menu_title_folder'] = new \IPS\Helpers\Form\Translatable( 'menu_title_folder', NULL, FALSE, array( 'app' => 'cms', 'key' => ( ( ! empty( $node ) and $node->type === 'folder' ) ? "cms_menu_title_" . $node->id : NULL ), 'maxLength' => 64 ), NULL, NULL, NULL, 'menu_title_folder' );
}
/* Shared fields */
$form['menu_parent_id'] = new \IPS\Helpers\Form\Node( 'menu_parent_id', $node !== NULL ? intval( $node->parent_id ) : 0, FALSE, array(
'class' => '\IPS\cms\Pages\Menu',
'zeroVal' => 'node_no_parent',
'permissionCheck' => function( $node )
{
return $node->type === 'folder';
}
), NULL, NULL, NULL, 'menu_parent_id' );
$form['menu_permission_from_page'] = new \IPS\Helpers\Form\Radio( 'menu_permission_type', $node !== NULL ? ( $node->permission === 'page' ? 'page' : 'manual' ) : ( $forceType === 'page' ? 'page' : 'manual' ), FALSE, array(
'options' => array(
'page' => 'cms_menu_form_perm_page',
'manual' => 'cms_menu_form_perm_manual'
),
'toggles' => array(
'manual' => array( 'menu_permission' )
)
), NULL, NULL, NULL, 'menu_permission_from_page' );
$form['menu_permission'] = new \IPS\Helpers\Form\Select( 'menu_permission', ( $node !== NULL ) ? ( ( $node->permission === '*' ) ? '*' : explode( ',', $node->permission ) ) : NULL, FALSE, array(
'options' => array_combine( array_keys( \IPS\Member\Group::groups() ), array_map( function( $_group ) { return (string) $_group; }, \IPS\Member\Group::groups() ) ),
'multiple' => true,
'unlimited' => '*',
'unlimitedLang' => 'cms_menu_perm_any'
), NULL, NULL, NULL, 'menu_permission' );
return $form;
}
/**
* Clear caches
*
* @return void
*/
public static function clearCaches()
{
unset( \IPS\Data\Store::i()->cms_menu );
}
/**
* [Node] Set Title
*
* @param string $title Title
* @return string|null
*/
protected function set__title( $title )
{
$this->title = $title;
}
/**
* [Node] Get Title
*
* @return string|null
*/
protected function get__title()
{
if ( ! $this->title AND $this->type === 'page' )
{
try
{
$this->title = \IPS\cms\Pages\Page::load( $this->content )->_title;
}
catch( \OutOfRangeException $ex )
{
$this->title = '';
}
}
else if ( ! $this->title )
{
/* This is stored in a separate \Data\Store cache, so we can't return the hash */
$this->title = \IPS\Member::loggedIn()->language()->get( 'cms_menu_title_' . $this->id );
}
return $this->title;
}
/**
* [Node] Get URL
*
* @return string|null
*/
protected function get__url()
{
if ( $this->type === 'page' )
{
try
{
return \IPS\cms\Pages\Page::load( $this->content )->url();
}
catch( \OutOfRangeException $ex )
{
return '';
}
}
return $this->content;
}
/**
* [Node] Return the custom badge for each row
*
* @return NULL|array Null for no badge, or an array of badge data (0 => CSS class type, 1 => language string, 2 => optional raw HTML to show instead of language string)
*/
protected function get__badge()
{
if ( ! $this->permission )
{
return array( 'ipsBadge ipsBadge_negative', 'cms_menu_no_item_perm' );
}
return ( $this->type === 'folder' ) ? NULL : array( 'ipsBadge ipsBadge_intermediary ipsPos_right', 'cms_menu_form_type_' . $this->type );
}
/**
* [Node] Get buttons to display in tree
* Example code explains return value
*
* @code
array(
array(
'icon' => 'plus-circle', // Name of FontAwesome icon to use
'title' => 'foo', // Language key to use for button's title parameter
'link' => \IPS\Http\Url::internal( 'app=foo...' ) // URI to link to
'class' => 'modalLink' // CSS Class to use on link (Optional)
),
... // Additional buttons
);
* @endcode
* @param string $url Base URL
* @param bool $subnode Is this a subnode?
* @return array
*/
public function getButtons( $url, $subnode=FALSE )
{
$buttons = parent::getButtons( $url, $subnode );
if ( isset( $buttons['copy'] ) and $this->type === 'folder' )
{
unset( $buttons['copy'] );
}
return $buttons;
}
/**
* Get sortable name
*
* @return string
*/
public function getSortableName()
{
return $this->name;
}
/**
* [Node] Add/Edit Form
*
* @param \IPS\Helpers\Form $form The form
* @return void
*/
public function form( &$form )
{
/* Build form */
foreach( static::formElements( $this ) as $element )
{
$form->add( $element );
}
if ( $this->id )
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('cms_menu_edit', FALSE, array( 'sprintf' => array( $this->_title ) ) );
}
else
{
\IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack('cms_menu_adding');
}
}
/**
* [Node] Format form values from add/edit form for save
*
* @param array $values Values from the form
* @return array
*/
public function formatFormValues( $values )
{
if ( ! $this->id )
{
$this->parent_id = 0;
$this->save();
}
if( isset( $values['menu_type'] ) )
{
$title = '';
$content = NULL;
switch ( $values['menu_type'] )
{
case 'page':
$title = $values['menu_title_page'];
$content = $values['menu_content_page'];
break;
case 'url':
$title = $values['menu_title_url'];
$content = $values['menu_content_url'];
break;
case 'folder':
$title = $values['menu_title_folder'];
break;
}
/* We need to store something in menu_title field in the database as we can leave this blank to get the current page title. We can't examine an addToStack to see if any data was returned */
$values['title'] = current( $title );
$values['content'] = $content;
\IPS\Lang::saveCustom( 'cms', "cms_menu_title_" . $this->id, $title );
unset( $values['menu_title_folder'], $values['menu_title_url'], $values['menu_title_page'], $values['menu_content_page'], $values['menu_content_url'] );
}
if( isset( $values['menu_permission'] ) )
{
$values['menu_permission'] = ( is_array( $values['menu_permission'] ) ) ? implode( ',', $values['menu_permission'] ) : $values['menu_permission'];
}
if ( isset( $values['menu_type'] ) AND $values['menu_type'] === 'page' and $values['menu_permission_type'] === 'page' )
{
$values['menu_permission'] = 'page';
}
if ( isset( $values['menu_parent_id'] ) AND ( ! empty( $values['menu_parent_id'] ) OR $values['menu_parent_id'] === 0 ) )
{
$values['menu_parent_id'] = ( $values['menu_parent_id'] === 0 ) ? 0 : $values['menu_parent_id']->id;
}
if( isset( $values['menu_permission_type'] ) )
{
unset( $values['menu_permission_type'] );
}
return $values;
}
/**
* [Node] Does the currently logged in user have permission to add a child node to this node?
*
* @return bool
*/
public function canAdd()
{
if ( parent::canAdd() )
{
return $this->type === 'folder';
}
return FALSE;
}
/**
* Save
*
* @return void
*/
public function save()
{
static::clearCaches();
parent::save();
}
}
+360 -82
View File
@@ -51,7 +51,7 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
/**
* @brief [Node] Parent ID Database Column
*/
public static $databaseColumnParent = null;
public static $databaseColumnParent = 'folder_id';
/**
* @brief [Node] Parent Node ID Database Column
@@ -367,7 +367,6 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
{
$url->data['query'] = $queryString;
}
return \IPS\Http\Url::createFromArray( $url->data );
}
@@ -384,7 +383,7 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
/* Do we have a page with this path? */
try
{
return static::load( $newPath, 'page_full_path' )->url();
return static::load( $newPath, 'page_full_path' );
}
catch( \OutOfRangeException $ex )
{
@@ -499,6 +498,33 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
}
}
/**
* Show a custom error page
*
* @param string $title Title of the page
* @param string $message language key for error message
* @param mixed $code Error code
* @param int $httpStatusCode HTTP Status Code
* @param array $httpHeaders Additional HTTP Headers
* @return void
*/
static public function errorPage( $title, $message, $code, $httpStatusCode, $httpHeaders )
{
try
{
$page = static::load( \IPS\Settings::i()->cms_error_page );
$page->content = str_replace( '{error_message}', $message, $page->content );
$page->content = str_replace( '{error_code}', $code, $page->content );
$page->output( $title, $httpStatusCode, $httpHeaders );
}
catch( \Exception $ex )
{
\IPS\Output::i()->sidebar['enabled'] = FALSE;
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->globalTemplate( $title, \IPS\Theme::i()->getTemplate( 'global', 'core' )->error( $title, $message, $code, NULL ), array( 'app' => \IPS\Dispatcher::i()->application ? \IPS\Dispatcher::i()->application->directory : NULL, 'module' => \IPS\Dispatcher::i()->module ? \IPS\Dispatcher::i()->module->key : NULL, 'controller' => \IPS\Dispatcher::i()->controller ) ), $httpStatusCode, 'text/html', $httpHeaders, FALSE, FALSE );
}
}
/**
* Form elements
*
@@ -562,54 +588,50 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
'subnodes' => false
), NULL, NULL, NULL, 'page_folder_id' );
if ( $pageType === 'html' )
$return['page_ipb_wrapper'] = new \IPS\Helpers\Form\YesNo( 'page_ipb_wrapper', $item AND $item->id ? $item->ipb_wrapper : 1, TRUE, array(
'togglesOn' => array( 'page_show_sidebar' ),
'togglesOff' => array( 'page_wrapper_template' )
), NULL, NULL, NULL, 'page_ipb_wrapper' );
$return['page_show_sidebar'] = new \IPS\Helpers\Form\YesNo( 'page_show_sidebar', $item ? $item->show_sidebar : TRUE, FALSE, array(), NULL, NULL, NULL, 'page_show_sidebar' );
$wrapperTemplates = array( '_none_' => \IPS\Member::loggedIn()->language()->addToStack('cms_page_wrapper_template_none') );
foreach( \IPS\cms\Templates::getTemplates( \IPS\cms\Templates::RETURN_PAGE + \IPS\cms\Templates::RETURN_DATABASE_AND_IN_DEV ) as $id => $obj )
{
$return['page_ipb_wrapper'] = new \IPS\Helpers\Form\YesNo( 'page_ipb_wrapper', $item AND $item->id ? $item->ipb_wrapper : 1, TRUE, array(
'togglesOn' => array( 'page_show_sidebar' ),
'togglesOff' => array( 'page_wrapper_template' )
), NULL, NULL, NULL, 'page_ipb_wrapper' );
$return['page_show_sidebar'] = new \IPS\Helpers\Form\YesNo( 'page_show_sidebar', $item ? $item->show_sidebar : TRUE, FALSE, array(), NULL, NULL, NULL, 'page_show_sidebar' );
$wrapperTemplates = array( '_none_' => \IPS\Member::loggedIn()->language()->addToStack('cms_page_wrapper_template_none') );
foreach( \IPS\cms\Templates::getTemplates( \IPS\cms\Templates::RETURN_PAGE + \IPS\cms\Templates::RETURN_DATABASE_AND_IN_DEV ) as $id => $obj )
if ( $obj->isSuitableForCustomWrapper() )
{
if ( $obj->isSuitableForCustomWrapper() )
{
$wrapperTemplates[ \IPS\cms\Templates::readableGroupName( $obj->group ) ][ $obj->group . '__' . $obj->title . '__' . $obj->key ] = \IPS\cms\Templates::readableGroupName( $obj->title );
}
$wrapperTemplates[ \IPS\cms\Templates::readableGroupName( $obj->group ) ][ $obj->group . '__' . $obj->title . '__' . $obj->key ] = \IPS\cms\Templates::readableGroupName( $obj->title );
}
/* List of templates */
$return['page_wrapper_template'] = new \IPS\Helpers\Form\Select( 'page_wrapper_template', ( $item ? $item->wrapper_template : NULL ), FALSE, array(
'options' => $wrapperTemplates
), NULL, NULL, \IPS\Theme::i()->getTemplate( 'pages', 'cms', 'admin' )->previewTemplateLink(), 'page_wrapper_template' );
}
else
/* List of templates */
$return['page_wrapper_template'] = new \IPS\Helpers\Form\Select( 'page_wrapper_template', ( $item ? $item->wrapper_template : NULL ), FALSE, array(
'options' => $wrapperTemplates
), NULL, NULL, \IPS\Theme::i()->getTemplate( 'pages', 'cms', 'admin' )->previewTemplateLink(), 'page_wrapper_template' );
if ( count( \IPS\Theme::themes() ) > 1 )
{
if ( count( \IPS\Theme::themes() ) > 1 )
$themes = array( 0 => 'cms_page_theme_id_default' );
foreach ( \IPS\Theme::themes() as $theme )
{
$themes = array( 0 => 'cms_page_theme_id_default' );
foreach ( \IPS\Theme::themes() as $theme )
{
$themes[ $theme->id ] = $theme->_title;
}
$return['page_theme'] = new \IPS\Helpers\Form\Select( 'page_theme', $item ? $item->theme : 0, FALSE, array( 'options' => $themes ), NULL, NULL, NULL, 'page_theme' );
$themes[ $theme->id ] = $theme->_title;
}
$builderTemplates = array();
foreach( \IPS\cms\Templates::getTemplates( \IPS\cms\Templates::RETURN_PAGE + \IPS\cms\Templates::RETURN_DATABASE_AND_IN_DEV ) as $id => $obj )
{
if ( $obj->isSuitableForBuilderWrapper() )
{
$builderTemplates[ \IPS\cms\Templates::readableGroupName( $obj->group ) ][ $obj->group . '__' . $obj->title . '__' . $obj->key ] = \IPS\cms\Templates::readableGroupName( $obj->title );
}
}
$return['page_template'] = new \IPS\Helpers\Form\Select( 'page_template', $item->template ? $item->template : FALSE, FALSE, array( 'options' => $builderTemplates ), NULL, NULL, NULL, 'page_template' );
$return['page_theme'] = new \IPS\Helpers\Form\Select( 'page_theme', $item ? $item->theme : 0, FALSE, array( 'options' => $themes ), NULL, NULL, NULL, 'page_theme' );
}
$builderTemplates = array();
foreach( \IPS\cms\Templates::getTemplates( \IPS\cms\Templates::RETURN_PAGE + \IPS\cms\Templates::RETURN_DATABASE_AND_IN_DEV ) as $id => $obj )
{
if ( $obj->isSuitableForBuilderWrapper() )
{
$builderTemplates[ \IPS\cms\Templates::readableGroupName( $obj->group ) ][ $obj->group . '__' . $obj->title . '__' . $obj->key ] = \IPS\cms\Templates::readableGroupName( $obj->title );
}
}
$return['page_template'] = new \IPS\Helpers\Form\Select( 'page_template', ( $item and $item->template ) ? $item->template : FALSE, FALSE, array( 'options' => $builderTemplates ), NULL, NULL, NULL, 'page_template' );
/* Page CSS and JS */
$js = \IPS\cms\Templates::getTemplates( \IPS\cms\Templates::RETURN_ONLY_JS + \IPS\cms\Templates::RETURN_DATABASE_ONLY );
$css = \IPS\cms\Templates::getTemplates( \IPS\cms\Templates::RETURN_ONLY_CSS + \IPS\cms\Templates::RETURN_DATABASE_ONLY );
@@ -647,21 +669,32 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
$return['tab_content'] = array( 'content_page_form_tab__content', NULL, NULL, 'ipsForm_vertical' );
$tags = array();
if ( $item and $item->id == \IPS\Settings::i()->cms_error_page )
{
$tags['cms_error_page']['{error_message}'] = 'cms_error_page_message';
$tags['cms_error_page']['{error_code}'] = 'cms_error_page_code';
}
foreach( \IPS\cms\Databases::roots( NULL, NULL ) as $id => $db )
{
if ( ! $db->page_id )
{
$tags['{database="' . $db->_id . '" title="' . $db->_title . '"}'] = $db->_title;
$tags['cms_tag_databases']['{database="' . $db->key . '"}'] = $db->_title;
}
}
foreach( \IPS\cms\Blocks\Block::roots( NULL, NULL ) as $id => $block )
{
$tags['{block="' . $block->_id . '" title="' . $block->_title . '"}'] = $block->_title;
$tags['cms_tag_blocks']['{block="' . $block->key . '"}'] = $block->_title;
}
$return['page_content'] = new \IPS\Helpers\Form\Codemirror( 'page_content', $item ? $item->content : NULL, FALSE, array( 'tags' => $tags ), function( $val )
foreach( \IPS\Db::i()->select( '*', 'cms_pages', NULL, 'page_full_path ASC', array( 0, 50 ) ) as $page )
{
$tags['cms_tag_pages']['{pageurl="' . $page['page_full_path'] . '"}' ] = \IPS\Member::loggedIn()->language()->addToStack( static::$titleLangPrefix . $page['page_id'] );
}
$return['page_content'] = new \IPS\Helpers\Form\Codemirror( 'page_content', $item ? htmlentities( $item->content, \IPS\HTMLENTITIES, 'UTF-8', TRUE ) : NULL, FALSE, array( 'tags' => $tags, 'height' => 600 ), function( $val )
{
/* Test */
try
@@ -702,12 +735,7 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
$page->saveForm( $page->formatFormValues( $values ), $pageType );
/* Set permissions */
\IPS\Db::i()->insert( 'core_permission_index', array(
'app' => 'cms',
'perm_type' => 'pages',
'perm_type_id' => $page->id,
'perm_view' => '*'
) );
\IPS\Db::i()->update( 'core_permission_index', array( 'perm_view' => '*' ), array( 'app=? and perm_type=? and perm_type_id=?', 'cms', 'pages', $page->id ) );
return $page;
}
@@ -778,7 +806,40 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
\IPS\Db::i()->update( 'cms_pages', array( 'page_js_css_objects' => NULL ) );
\IPS\cms\Templates::deleteCompiledFiles();
}
/**
* Create a datastore object of page IDs and URLs.
*
* @return void
*/
public static function buildPageUrlStore()
{
$store = array();
foreach( new \IPS\Patterns\ActiveRecordIterator( \IPS\Db::i()->select( '*', 'cms_pages' ), 'IPS\cms\Pages\Page' ) as $page )
{
$perms = $page->permissions();
$store[ $page->id ] = array( 'url' => (string) $page->url(), 'perm' => $perms['perm_view'] );
}
\IPS\Data\Store::i()->pages_page_urls = $store;
}
/**
* Returns (and builds if required) the pages id => url datastore
*
* @return array
*/
public static function getPageUrlStore()
{
if ( ! isset( \IPS\Data\Store::i()->pages_page_urls ) )
{
static::buildPageUrlStore();
}
return \IPS\Data\Store::i()->pages_page_urls;
}
/**
* Set JS/CSS include keys
*
@@ -991,7 +1052,7 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
$return = array();
$dbWidgets = array();
$areas = array();
foreach( \IPS\Db::i()->select( '*', 'cms_page_widget_areas', array( 'area_page_id=?', $this->id ) ) as $k => $widgetMain )
{
$widgets[ $widgetMain['area_area'] ] = json_decode( $widgetMain['area_widgets'], TRUE );
@@ -1000,7 +1061,8 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
/* We need to execute database widgets first as this sets up the Database dispatcher correctly */
foreach( $widgets[ $widgetMain['area_area'] ] as $widget )
{
if ( $widget['key'] === 'Database' )
/* Do not attempt to re-parse database widgets if we already have */
if ( ! \IPS\cms\Databases\Dispatcher::i()->databaseId AND $widget['key'] === 'Database' )
{
$orientation = ( ( $widgetMain['area_area'] == 'sidebar' ) ? 'vertical' : ( ( $widgetMain['area_area'] === 'header' OR $widgetMain['area_area'] === 'footer' ) ? 'horizontal' : $widgetMain['area_orientation'] ) );
$dbWidgets[ $widget['unique'] ] = \IPS\Widget::load( \IPS\Application::load( $widget['app'] ), $widget['key'], $widget['unique'], ( isset( $widget['configuration'] ) ) ? $widget['configuration'] : array(), ( isset( $widget['restrict'] ) ? $widget['restrict'] : null ), $orientation );
@@ -1017,7 +1079,7 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
{
try
{
if ( $widget['key'] == 'Database' )
if ( $widget['key'] == 'Database' and array_key_exists( $widget['unique'], $dbWidgets ) )
{
$_widget = $dbWidgets[ $widget['unique'] ];
}
@@ -1156,9 +1218,19 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
{
$pageType = $this->type;
}
foreach( static::formElements( $this ) as $name => $field )
{
if ( $pageType !== 'html' and in_array( $name, array( 'page_ipb_wrapper', 'page_show_sidebar', 'page_wrapper_template' ) ) )
{
continue;
}
if ( $pageType === 'html' and in_array( $name, array( 'page_template' ) ) )
{
continue;
}
if ( is_array( $field ) )
{
if ( mb_substr( $name, 0, 4 ) === 'tab_' )
@@ -1179,20 +1251,42 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
if ( ! $this->id )
{
$form->addTab( 'content_page_form_tab__menu' );
$toggles = array();
$toggles = array( 'menu_manager_access_type', 'menu_parent' );
$formFields = array();
foreach( \IPS\cms\Pages\Menu::formElements( NULL, 'page' ) as $name => $field )
foreach( \IPS\cms\extensions\core\FrontNavigation\Pages::configuration( array() ) as $field )
{
$toggles[] = $name;
$formFields[ $name ] = $field;
if ( $field->name !== 'menu_content_page' )
{
$toggles[] = $field->name;
$formFields[ $field->name ] = $field;
}
}
$form->add( new \IPS\Helpers\Form\YesNo( 'page_add_to_menu', FALSE, FALSE, array( 'togglesOn' => $toggles ) ) );
$roots = array();
foreach ( \IPS\core\FrontNavigation::i()->roots( FALSE ) as $item )
{
$roots[ $item->id ] = $item->title();
}
$form->add( new \IPS\Helpers\Form\Select( 'menu_parent', '*', NULL, array( 'options' => $roots ), NULL, NULL, NULL, 'menu_parent' ) );
foreach( $formFields as $name => $field )
{
$form->add( $field );
}
$groups = array();
foreach ( \IPS\Member\Group::groups() as $group )
{
$groups[ $group->g_id ] = $group->name;
}
$form->add( new \IPS\Helpers\Form\Radio( 'menu_manager_access_type', 0, TRUE, array(
'options' => array( 0 => 'menu_manager_access_type_inherit', 1 => 'menu_manager_access_type_override' ),
'toggles' => array( 1 => array( 'menu_manager_access' ) )
), NULL, NULL, NULL, 'menu_manager_access_type' ) );
$form->add( new \IPS\Helpers\Form\Select( 'menu_manager_access', '*', NULL, array( 'multiple' => TRUE, 'options' => $groups, 'unlimited' => '*', 'unlimitedLang' => 'everyone' ), NULL, NULL, NULL, 'menu_manager_access' ) );
}
if ( $pageType === 'builder' )
@@ -1296,20 +1390,39 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
{
if( $values['page_add_to_menu'] )
{
$menuValues = array(
'menu_type' => 'page',
'menu_title_page' => $values['menu_title_page'],
'menu_content_page' => $this->id,
'menu_permission' => $values['menu_permission'],
'menu_permission_type' => $values['menu_permission_type'],
'menu_parent_id' => $values['menu_parent_id']
$values = \IPS\cms\extensions\core\FrontNavigation\Pages::parseConfiguration( $values, $this->id );
$config = array( 'menu_content_page' => $this->id );
foreach( array( 'menu_title_page_type', 'menu_title_page' ) as $field )
{
if ( isset( $values[ $field ] ) )
{
$config[ $field ] = $values[ $field ];
}
}
$save = array(
'app' => 'cms',
'extension' => 'Pages',
'config' => json_encode( $config ),
'parent' => $values['menu_parent'],
'permissions' => $values['menu_manager_access'] == '*' ? '*' : implode( ',', $values['menu_manager_access'] )
);
$menu = new \IPS\cms\Pages\Menu();
$menu->saveForm( $menu->formatFormValues( $menuValues ) );
try
{
$save['position'] = \IPS\Db::i()->select( 'MAX(position)', 'core_menu', array( 'parent=?', \IPS\Request::i()->parent ) )->first() + 1;
}
catch ( \UnderflowException $e )
{
$save['position'] = 1;
}
\IPS\Db::i()->insert( 'core_menu', $save );
unset( \IPS\Data\Store::i()->frontNavigation );
}
unset( $values['page_add_to_menu'], $values['menu_title_page'], $values['menu_permission'], $values['menu_permission_type'], $values['menu_parent_id'] );
unset( $values['page_add_to_menu'], $values['menu_title_page_type'], $values['menu_title_page'], $values['menu_parent'], $values['menu_manager_access'], $values['menu_manager_access_type'] );
}
return $values;
@@ -1683,13 +1796,42 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
{
}
\IPS\Db::i()->delete( 'cms_page_menu', array( 'menu_type=? AND menu_content=?', 'page', $this->id ) );
unset( \IPS\Data\Store::i()->cms_menu );
$delete = $this->getMenuItemIds();
if ( count( $delete ) )
{
\IPS\Db::i()->delete( 'core_menu', \IPS\Db::i()->in( 'id', $delete ) );
}
unset( \IPS\Data\Store::i()->frontNavigation );
return parent::delete();
}
/**
* Returns core_menu ids for all menu items associated with this page
*
* @return array
*/
public function getMenuItemIds()
{
$items = array();
foreach( \IPS\Db::i()->select( '*', 'core_menu', array( 'app=? AND extension=?', 'cms', 'Pages' ) ) as $item )
{
$json = json_decode( $item['config'], TRUE );
if ( isset( $json['menu_content_page'] ) )
{
if ( $json['menu_content_page'] == $this->id )
{
$items[] = $item['id'];
}
}
}
return $items;
}
/**
* Set the permission index permissions
@@ -1700,9 +1842,9 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
*/
public function setPermissions( $insert, \IPS\Helpers\Form\Matrix $matrix )
{
\IPS\cms\Pages\Menu::clearCaches();
parent::setPermissions( $insert, $matrix );
static::buildPageUrlStore();
/* Update perms if we have a child database */
try
{
@@ -1732,10 +1874,10 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
{
static::deleteCompiled( $this->id );
}
\IPS\cms\Pages\Menu::clearCaches();
parent::save();
static::buildPageUrlStore();
}
/**
@@ -1758,7 +1900,7 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
\IPS\DB::i()->update( 'cms_pages', array( 'page_default' => 0 ), array( 'page_folder_id=?', $this->folder_id ) );
\IPS\DB::i()->update( 'cms_pages', array( 'page_default' => 1 ), array( 'page_id=?', $this->id ) );
\IPS\cms\Pages\Menu::clearCaches();
static::buildPageUrlStore();
}
/**
@@ -1772,4 +1914,140 @@ class _Page extends \IPS\Node\Model implements \IPS\Node\Permissions
$this->full_path = trim( $path . '/' . $this->seo_name, '/' );
$this->save();
}
/**
* Displays a page
*
* @param int $httpStatusCode HTTP Status Code
* @param array $httpHeaders Additional HTTP Headers
* @throws \ErrorException
* @return void
*/
public function output( $title=NULL, $httpStatusCode=NULL, $httpHeaders=NULL )
{
$includes = $this->getIncludes();
if ( isset( $includes['js'] ) and is_array( $includes['js'] ) )
{
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, array_values( $includes['js'] ) );
}
/* Display */
if ( $this->ipb_wrapper or $this->type === 'builder' )
{
$this->setTheme();
$nav = array();
\IPS\Output::i()->title = $this->getHtmlTitle();
/* This has to be done after setTheme(), otherwise \IPS\Theme::switchTheme() can wipe out CSS includes */
if ( isset( $includes['css'] ) and is_array( $includes['css'] ) )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, array_values( $includes['css'] ) );
}
if ( $this->type === 'builder' )
{
list( $group, $name, $key ) = explode( '__', $this->template );
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('pages')->globalWrap( $nav, \IPS\cms\Theme::i()->getTemplate($group, 'cms', 'page')->$name( $this, $this->getWidgets() ), $this );
}
else
{
/* Populate \IPS\Output::i()->sidebar['widgets'] sidebar/header/footer widgets */
$this->getWidgets();
\IPS\Output::i()->output = \IPS\Theme::i()->getTemplate('pages')->globalWrap( $nav, $this->getHtmlContent(), $this );
}
\IPS\Output::i()->sidebar['enabled'] = true;
/* Set the meta tags, but do not reset them if they are already set - articles can define custom meta tags and this code
overwrites the ones set by articles if we don't verify they aren't set first */
if ( $this->meta_keywords AND ( !isset( \IPS\Output::i()->metaTags['keywords'] ) OR !\IPS\Output::i()->metaTags['keywords'] ) )
{
\IPS\Output::i()->metaTags['keywords'] = $this->meta_keywords;
}
if ( $this->meta_description AND ( !isset( \IPS\Output::i()->metaTags['description'] ) OR !\IPS\Output::i()->metaTags['description'] ) )
{
\IPS\Output::i()->metaTags['description'] = $this->meta_description;
}
/* Can only disable sidebar if HTML page */
if ( ! $this->show_sidebar and $this->type === 'html' )
{
\IPS\Output::i()->sidebar['enabled'] = false;
}
if ( isset( \IPS\Settings::i()->cms_error_page ) and \IPS\Settings::i()->cms_error_page and \IPS\Settings::i()->cms_error_page == $this->id )
{
\IPS\Output::i()->sidebar['enabled'] = false;
}
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'pages/page.css', 'cms', 'front' ) );
if ( ! ( \IPS\Application::load('cms')->default AND ! $this->folder_id AND $this->default ) )
{
\IPS\Output::i()->breadcrumb['module'] = array( $this->url(), $this->_title );
}
if ( isset( \IPS\Settings::i()->cms_error_page ) and \IPS\Settings::i()->cms_error_page and \IPS\Settings::i()->cms_error_page == $this->id )
{
/* Set the title */
\IPS\Output::i()->title = ( $title ) ? $title : $this->getHtmlTitle();
\IPS\Output::i()->output = $this->getHtmlContent();
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( \IPS\Output::i()->title );
/* Send straight to the output engine */
\IPS\Output::i()->sendOutput( \IPS\Theme::i()->getTemplate( 'global', 'core' )->globalTemplate( \IPS\Output::i()->title, \IPS\Output::i()->output, array( 'app' => \IPS\Dispatcher::i()->application->directory, 'module' => \IPS\Dispatcher::i()->module->key, 'controller' => \IPS\Dispatcher::i()->controller ) ), ( $httpStatusCode ? $httpStatusCode : 200 ), 'text/html', ( $httpHeaders ? $httpHeaders : \IPS\Output::i()->httpHeaders ) );
}
else
{
\IPS\Output::i()->allowDefaultWidgets = FALSE;
/* Let the dispatcher finish off and show page */
return;
}
}
else
{
if ( isset( $includes['css'] ) and is_array( $includes['css'] ) )
{
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, array_values( $includes['css'] ) );
}
if ( $this->meta_keywords AND ( !isset( \IPS\Output::i()->metaTags['keywords'] ) OR !\IPS\Output::i()->metaTags['keywords'] ) )
{
\IPS\Output::i()->metaTags['keywords'] = $this->meta_keywords;
}
if ( $this->meta_description AND ( !isset( \IPS\Output::i()->metaTags['description'] ) OR !\IPS\Output::i()->metaTags['description'] ) )
{
\IPS\Output::i()->metaTags['description'] = $this->meta_description;
}
/* Meta tags */
\IPS\Output::i()->buildMetaTags();
if ( $this->wrapper_template and $this->wrapper_template !== '_none_' and ! \IPS\Request::i()->isAjax() )
{
try
{
list( $group, $name, $key ) = explode( '__', $this->wrapper_template );
\IPS\Output::i()->sendOutput( \IPS\cms\Theme::i()->getTemplate($group, 'cms', 'page')->$name( $this->getHtmlContent(), $this->getHtmlTitle() ), 200, $this->getContentType(), \IPS\Output::i()->httpHeaders );
}
catch( \OutOfRangeException $e )
{
}
}
/* Set the title */
\IPS\Output::i()->title = ( $title ) ? $title : $this->getHtmlTitle();
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( \IPS\Output::i()->title );
/* Send straight to the output engine */
\IPS\Output::i()->sendOutput( $this->getHtmlContent(), ( $httpStatusCode ? $httpStatusCode : 200 ), $this->getContentType(), ( $httpHeaders ? $httpHeaders : \IPS\Output::i()->httpHeaders ) );
}
}
}
@@ -135,6 +135,7 @@ class _Comment extends \IPS\Content\Comment implements \IPS\Content\ReportCenter
if ( isset( $item::$databaseColumnMap['num_comments'] ) )
{
$item->resyncCommentCounts();
$item->save();
}
if ( $item->containerWrapper() AND $item->container()->_comments !== NULL )
@@ -100,7 +100,18 @@ class _CommentTopicSync extends \IPS\cms\Records\Comment
public function item()
{
$itemClass = static::$itemClass;
return $itemClass::load( \IPS\Request::i()->id );
$lookFor = 'IPS\cms\Records\RecordsTopicSync';
if ( mb_substr( $itemClass, 0, mb_strlen( $lookFor ) ) === $lookFor )
{
$id = $this->topic_id;
}
else
{
$id = \IPS\Request::i()->id;
}
return $itemClass::load( $id );
}
/**
@@ -110,19 +121,24 @@ class _CommentTopicSync extends \IPS\cms\Records\Comment
*/
public function delete()
{
parent::delete();
try
{
$topic = \IPS\forums\Topic::load( $this->topic_id );
$topic->resyncCommentCounts();
$topic->resyncLastComment();
}
catch( \OutOfRangeException $ex )
{
}
/* We need the classname to be \IPS\forums\Topic\Post so topic/forum sync occur and to ensure post is removed from search index */
$comment = \IPS\forums\Topic\Post::load( $this->pid );
$comment->delete();
}
/**
* Edit Comment Contents - Note: does not add edit log
*
* @param string $newContent New content
* @return string|NULL
*/
public function editContents( $newContent )
{
$comment = \IPS\forums\Topic\Post::load( $this->pid );
$comment->editContents( $newContent );
}
/**
* Addition where needed for fetching comments
*
+136 -10
View File
@@ -124,7 +124,7 @@ class _Records extends \IPS\Content\Item implements
/**
* @brief Icon
*/
public static $icon = 'file-text-o';
public static $icon = 'file-text';
/**
* @brief Reputation Type
@@ -177,8 +177,17 @@ class _Records extends \IPS\Content\Item implements
*/
public static function getCommentsPerPage()
{
/* Normally we check if we are using the forums at the record level, however this is a static method called so we can only try to do our best to guess */
if( static::database()->forum_record and static::database()->forum_comments and \IPS\Application::appIsEnabled('forums') )
if ( ! empty( \IPS\cms\Databases\Dispatcher::i()->recordId ) )
{
$class = 'IPS\cms\Records' . static::$customDatabaseId;
$record = $class::load( \IPS\cms\Databases\Dispatcher::i()->recordId );
if ( $record->_forum_record and $record->_forum_comments and \IPS\Application::appIsEnabled('forums') )
{
return \IPS\forums\Topic::getCommentsPerPage();
}
}
else if( static::database()->forum_record and static::database()->forum_comments and \IPS\Application::appIsEnabled('forums') )
{
return \IPS\forums\Topic::getCommentsPerPage();
}
@@ -215,9 +224,12 @@ class _Records extends \IPS\Content\Item implements
if ( isset( $qs['path'] ) )
{
$bits = explode( '/', trim( $qs['path'], '/' ) );
$path = array_pop( $bits );
try
{
return static::loadFromSlug( $qs['path'], FALSE );
return static::loadFromSlug( $path, FALSE );
}
catch ( \Exception $e ) { }
}
@@ -320,6 +332,18 @@ class _Records extends \IPS\Content\Item implements
return $lang->addToStack( 'content_db_lang_ia_' . static::$customDatabaseId, FALSE );
}
/**
* Indefinite Article
*
* @param \IPS\Lang|NULL $language The language to use, or NULL for the language of the currently logged in member
* @return string
*/
public static function _indefiniteArticle( array $containerData = NULL, \IPS\Lang $lang = NULL )
{
$lang = $lang ?: \IPS\Member::loggedIn()->language();
return $lang->addToStack( 'content_db_lang_ia_' . static::$customDatabaseId, FALSE );
}
/**
* Get elements for add/edit form
*
@@ -774,6 +798,10 @@ class _Records extends \IPS\Content\Item implements
$thumb = $values['record_image']->thumbnail( 'cms_Records', $fixedFieldSettings['record_image']['thumb_dims'][0], $fixedFieldSettings['record_image']['thumb_dims'][1] );
}
else
{
$thumb = $values['record_image'];
}
$this->record_image = (string)$values['record_image'];
$this->record_image_thumb = (string)$thumb;
@@ -1003,6 +1031,82 @@ class _Records extends \IPS\Content\Item implements
return $url;
}
/**
* Columns needed to query for search result / stream view
*
* @return array
*/
public static function basicDataColumns()
{
$return = parent::basicDataColumns();
$return[] = 'category_id';
$return[] = 'record_static_furl';
$return[] = 'record_dynamic_furl';
return $return;
}
/**
* Query to get additional data for search result / stream view
*
* @param array $items Item data (will be an array containing values from basicDataColumns())
* @return array
*/
public static function searchResultExtraData( $items )
{
$categoryIds = array();
foreach ( $items as $item )
{
if ( $item['category_id'] )
{
$categoryIds[ $item['category_id'] ] = $item['category_id'];
}
}
if ( count( $categoryIds ) )
{
$categoryPaths = iterator_to_array( \IPS\Db::i()->select( array( 'category_id', 'category_full_path' ), 'cms_database_categories', \IPS\Db::i()->in( 'category_id', $categoryIds ) )->setKeyField('category_id')->setValueField('category_full_path') );
$return = array();
foreach ( $items as $item )
{
if ( $item['category_id'] )
{
$return[ $item['primary_id_field'] ] = $categoryPaths[ $item['category_id'] ];
}
}
return $return;
}
return array();
}
/**
* Get URL from index data
*
* @param array $indexData Data from the search index
* @param array $itemData Basic data about the item. Only includes columns returned by item::basicDataColumns()
* @return \IPS\Http\Url
*/
public static function urlFromIndexData( $indexData, $itemData )
{
if ( static::$pagePath === NULL )
{
static::$pagePath = \IPS\Db::i()->select( array( 'page_full_path' ), 'cms_pages', array( 'page_id=?', static::database()->page_id ) )->first();
}
$recordSlug = !$itemData['record_static_furl'] ? $itemData['record_dynamic_furl'] . '-r' . $itemData['primary_id_field'] : $itemData['record_static_furl'];
if ( static::database()->use_categories )
{
return \IPS\Http\Url::internal( "app=cms&module=pages&controller=page&path=" . static::$pagePath . '/' . $itemData['extra'] . '/' . $recordSlug, 'front', 'content_page_path', $recordSlug );
}
else
{
return \IPS\Http\Url::internal( "app=cms&module=pages&controller=page&path=" . static::$pagePath . '/' . $recordSlug, 'front', 'content_page_path', $recordSlug );
}
}
/**
* Template helper method to fetch custom fields to display
@@ -1263,7 +1367,7 @@ class _Records extends \IPS\Content\Item implements
*/
public function editLine()
{
if ( static::database()->revisions and $this->record_edit_time and ( $this->record_edit_show or \IPS\Member::loggedIn()->modPermission('can_view_editlog') ) )
if ( $this->record_edit_time and ( $this->record_edit_show or \IPS\Member::loggedIn()->modPermission('can_view_editlog') ) and \IPS\Settings::i()->edit_log )
{
return \IPS\cms\Theme::i()->getTemplate( static::database()->template_display, 'cms', 'database' )->recordEditLine( $this );
}
@@ -1387,7 +1491,7 @@ class _Records extends \IPS\Content\Item implements
/**
* Resync the comments/unapproved comment counts
*
* @param string $commentClass
* @param string $commentClass Override comment class to use
* @return void
*/
public function resyncCommentCounts( $commentClass=NULL )
@@ -1409,6 +1513,28 @@ class _Records extends \IPS\Content\Item implements
parent::resyncCommentCounts( $commentClass );
}
}
/**
* Are comments supported by this class?
*
* @param \IPS\Member\NULL $member The member to check for or NULL fto not check permission
* @return int
*/
public static function supportsComments( \IPS\Member $member = NULL )
{
return parent::supportsComments() and static::database()->options['comments'];
}
/**
* Are reviews supported by this class?
*
* @param \IPS\Member\NULL $member The member to check for or NULL to not check permission
* @return int
*/
public static function supportsReviews( \IPS\Member $member = NULL )
{
return parent::supportsReviews() and static::database()->options['reviews'];
}
/* !IP.Board Integration */
@@ -1606,6 +1732,7 @@ class _Records extends \IPS\Content\Item implements
}
catch( \Exception $ex ) { }
}
return $record;
}
@@ -1617,7 +1744,7 @@ class _Records extends \IPS\Content\Item implements
*/
public function processAfterEdit( $values )
{
if ( \IPS\Application::appIsEnabled('forums') and $this->topic() )
if ( \IPS\Application::appIsEnabled('forums') and $this->_forum_record and $this->_forum_forum and ! $this->hidden() and ! $this->record_future_date )
{
try
{
@@ -1684,7 +1811,7 @@ class _Records extends \IPS\Content\Item implements
$topic->unhide();
}
}
else if ( $this->_forum_forum )
else if ( $this->_forum_forum and $this->_forum_comments )
{
$this->syncTopic();
}
@@ -1720,7 +1847,7 @@ class _Records extends \IPS\Content\Item implements
{
$topic->unhide();
}
elseif ( $this->_forum_forum )
elseif ( $this->_forum_forum and $this->_forum_comments )
{
$this->syncTopic();
}
@@ -2370,7 +2497,6 @@ class _Records extends \IPS\Content\Item implements
{
try
{
$url = $this->url();
return parent::searchIndexPermissions();
}
catch ( \LogicException $e )
@@ -0,0 +1,185 @@
<?php
/**
* @brief Categories Selector Model
* @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 20 July 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\cms\Selector;
/* 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;
}
/**
* @brief Categories Model
*/
class _Categories extends \IPS\Node\Model implements \IPS\Node\Permissions
{
/**
* @brief Multiton Store
*/
protected static $multitons = array();
/**
* @brief [Records] Custom Database Id
*/
public static $customDatabaseId = NULL;
/**
* @brief [Records] Content item class
*/
public static $contentItemClass = NULL;
/**
* @brief [ActiveRecord] Database Table
*/
public static $databaseTable = 'cms_database_categories';
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'category_';
/**
* @brief [ActiveRecord] ID Database Column
*/
public static $databaseColumnId = 'id';
/**
* @brief [ActiveRecord] Database ID Fields
*/
protected static $databaseIdFields = array('category_furl_name', 'category_full_path');
/**
* @brief [Node] Parent ID Database Column
*/
public static $databaseColumnParent = 'parent_id';
/**
* @brief [Node] Parent ID Database Column
*/
public static $databaseColumnOrder = 'position';
/**
* @brief [Node] Parent Node ID Database Column
*/
public static $parentNodeColumnId = 'database_id';
/**
* @brief [Node] Parent Node Class
*/
public static $parentNodeClass = 'IPS\cms\Selector\Databases';
/**
* @brief [Node] Show forms modally?
*/
public static $modalForms = FALSE;
/**
* @brief [Node] Sortable?
*/
public static $nodeSortable = TRUE;
/**
* @brief [Node] Node Title
*/
public static $nodeTitle = 'r__categories';
/**
* @brief [Node] Title prefix. If specified, will look for a language key with "{$key}_title" as the key
*/
public static $titleLangPrefix = 'content_cat_name_';
/**
* @brief [Node] Description suffix. If specified, will look for a language key with "{$titleLangPrefix}_{$id}_{$descriptionLangSuffix}" as the key
*/
public static $descriptionLangSuffix = '_desc';
/**
* @brief [Node] App for permission index
*/
public static $permApp = 'cms';
/**
* @brief [Node] Type for permission index
*/
public static $permType = 'categories';
/**
* @brief The map of permission columns
*/
public static $permissionMap = array(
'view' => 'view',
'read' => 2,
'add' => 3,
'edit' => 4,
'reply' => 5,
'review' => 7,
'rate' => 6
);
/**
* @brief [Node] Moderator Permission
*/
public static $modPerm = 'cms';
/**
* @brief [Node] Prefix string that is automatically prepended to permission matrix language strings
*/
public static $permissionLangPrefix = 'perm_content_';
/**
* Get title of category
*
* @return string
*/
protected function get__title()
{
/* If the DB is in a page, and we're not using categories, then return the page title, not the category title for continuity */
if ( ! \IPS\cms\Databases::load( $this->database_id )->use_categories )
{
if ( ! $this->_catTitle )
{
try
{
$page = \IPS\cms\Pages\Page::loadByDatabaseId( $this->database_id );
$this->_catTitle = $page->_title;
}
catch( \OutOfRangeException $e )
{
$this->_catTitle = parent::get__title();
}
}
return $this->_catTitle;
}
else
{
return parent::get__title();
}
}
/**
* [Node] Get Description
*
* @return string|null
*/
protected function get__description()
{
if ( ! static::database()->use_categories )
{
return static::database()->_description;
}
return ( \IPS\Member::loggedIn()->language()->addToStack('content_cat_name_' . $this->id . '_desc') === 'content_cat_name_' . $this->id . '_desc' ) ? $this->description : \IPS\Member::loggedIn()->language()->addToStack('content_cat_name_' . $this->id . '_desc');
}
}
@@ -0,0 +1,108 @@
<?php
/**
* @brief Databases Selector Model
* @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 20 July 2015
* @version SVN_VERSION_NUMBER
*/
namespace IPS\cms\Selector;
/* 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;
}
/**
* @brief Databases Model
*/
class _Databases extends \IPS\Node\Model implements \IPS\Node\Permissions
{
/**
* @brief [ActiveRecord] Multiton Store
*/
protected static $multitons = array();
/**
* @brief [ActiveRecord] Database Prefix
*/
public static $databasePrefix = 'database_';
/**
* @brief [ActiveRecord] ID Database Table
*/
public static $databaseTable = 'cms_databases';
/**
* @brief [ActiveRecord] ID Database Column
*/
public static $databaseColumnId = 'id';
/**
* @brief [ActiveRecord] Database ID Fields
*/
protected static $databaseIdFields = array( 'database_key', 'database_page_id' );
/**
* @brief [Node] Parent ID Database Column
*/
public static $databaseColumnOrder = 'id';
/**
* @brief [Node] Sortable?
*/
public static $nodeSortable = FALSE;
/**
* @brief [Node] Node Title
*/
public static $nodeTitle = '';
/**
* @brief [Node] Subnode class
*/
public static $subnodeClass = 'IPS\cms\Selector\Categories';
/**
* @brief The map of permission columns
*/
public static $permissionMap = array(
'view' => 'view',
'read' => 2,
'add' => 3,
'edit' => 4,
'reply' => 5,
'review' => 7,
'rate' => 6
);
/**
* @brief [Node] App for permission index
*/
public static $permApp = 'cms';
/**
* @brief [Node] Type for permission index
*/
public static $permType = 'databases';
/**
* @brief [Node] Prefix string that is automatically prepended to permission matrix language strings
*/
public static $permissionLangPrefix = 'perm_content_';
/**
* @brief [Node] Title prefix. If specified, will look for a language key with "{$titleLangPrefix}_{$id}" as the key
*/
public static $titleLangPrefix = 'content_db_';
/**
* @brief [Node] Description suffix. If specified, will look for a language key with "{$titleLangPrefix}_{$id}_{$descriptionLangSuffix}" as the key
*/
public static $descriptionLangSuffix = 'desc';
}
@@ -91,7 +91,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
/**
* @brief Return both IN_DEV and database templates
*/
const RETURN_DATABASE_AND_IN_DEV = 128;
const RETURN_DATABASE_AND_IN_DEV = 256;
/**
* Load Record
@@ -235,7 +235,7 @@ class _Templates extends \IPS\Patterns\ActiveRecord
$return = array();
$locations = NULL;
if ( ( \IPS\IN_DEV or \IPS\Theme::designersModeEnabled() ) AND ! ( $returnType & self::RETURN_DATABASE_ONLY ) )
if ( ( \IPS\IN_DEV or \IPS\Theme::designersModeEnabled() ) AND ( $returnType & self::RETURN_DATABASE_AND_IN_DEV ) AND ! ( $returnType & self::RETURN_DATABASE_ONLY ) )
{
$flags = \IPS\cms\Theme::RETURN_AS_OBJECT;
@@ -99,7 +99,7 @@ class _Theme extends \IPS\cms\Theme
foreach( new \DirectoryIterator( $path . '/' . $group->getFilename() ) as $file )
{
if ( $file->isDot() || mb_substr( $file->getFilename(), -6 ) !== '.phtml')
if ( $file->isDot() || ( mb_substr( $file->getFilename(), -6 ) !== '.phtml' and mb_substr( $file->getFilename(), -3 ) !== '.js' and mb_substr( $file->getFilename(), -4 ) !== '.css' ) )
{
continue;
}
@@ -108,7 +108,7 @@ class _Theme extends \IPS\cms\Theme
$html = file_get_contents( $path . '/' . $group->getFilename() . '/' . $file->getFilename() );
/* Parse the header tag */
preg_match( '/^<ips:template parameters="(.+?)?"([^>]+?)>(\r\n?|\n)/', $html, $params );
preg_match( '/^<ips:template parameters="([^"]+?)?"([^>]+?)>(\r\n?|\n)/', $html, $params );
/* Strip it */
$html = ( isset($params[0]) ) ? str_replace( $params[0], '', $html ) : $html;
@@ -117,7 +117,7 @@ class _Theme extends \IPS\cms\Theme
if ( isset( $params[2] ) and mb_stristr( $params[2], 'original_group' ) )
{
preg_match( '#original_group="(.+?)"#', $params[2], $submatches );
preg_match( '#original_group="(.+?)?"#', $params[2], $submatches );
if ( isset( $submatches[1] ) )
{
@@ -133,7 +133,7 @@ class _Theme extends \IPS\cms\Theme
if ( isset( $templates[ $key ] ) )
{
if ( md5( trim( $templates[ $key ]['template_content'] ) ) == md5( trim( $html ) ) )
if ( md5( trim( $templates[ $key ]['template_content'] ) ) == md5( trim( $html ) ) and 1==2 )
{
continue;
}
@@ -144,8 +144,9 @@ class _Theme extends \IPS\cms\Theme
{
$added = TRUE;
\IPS\Db::i()->update( 'cms_templates', array(
'template_content' => $html,
'template_params' => ( isset($params[1]) ) ? $params[1] : '',
'template_content' => $html,
'template_params' => ( isset($params[1]) ) ? $params[1] : '',
'template_file_object' => NULL
), array( 'template_id=?', $templates[ $key ]['template_id'] ) );
}
}
+3 -3
View File
@@ -256,7 +256,7 @@ class _Theme extends \IPS\Theme
}
else
{
@chmod( $path . '/' . $template['template_location'] . '/' . $template['template_group'] . '/' . $fileName, 0777 );
@chmod( $path . '/' . $template['template_location'] . '/' . $template['template_group'] . '/' . $fileName, \IPS\IPS_FILE_PERMISSION );
}
}
}
@@ -280,7 +280,7 @@ class _Theme extends \IPS\Theme
$where = array();
$templates = array();
if ( ( \IPS\IN_DEV or \IPS\Theme::designersModeEnabled() ) AND ! ( $returnType & static::RETURN_DATABASE_ONLY ) )
if ( ( \IPS\IN_DEV or \IPS\Theme::designersModeEnabled() ) AND ! ( $returnType ^ static::RETURN_DATABASE_ONLY ) )
{
$fixedLocations = array( 'admin', 'front', 'global' );
$results = array();
@@ -342,7 +342,7 @@ class _Theme extends \IPS\Theme
$contents = file_get_contents( static::_getHtmlPath( 'cms', $location->getFilename(), $file->getFilename() ) . '/' . $template->getFilename() );
$key = \IPS\cms\Theme\Template::extractDataFromTag( $contents, 'key' );
$key = $key ? $key : \IPS\Http\Url::seoTitle( $title );
$key = $key ? $key : \IPS\Http\Url::seoTitle( $file->getFilename() . '_' . $title );
$ogroup = \IPS\cms\Theme\Template::extractDataFromTag( $contents, 'original_group' );
$params = \IPS\cms\Theme\Template::extractParamsFromTag( $contents );
$container = NULL;