2007-07-19 12:40:05 +02:00
< ? php
/**
* LeftAndMain is the parent class of all the two - pane views in the CMS .
* If you are wanting to add more areas to the CMS , you can do it by subclassing LeftAndMain .
2008-04-05 05:43:58 +02:00
*
* This is essentially an abstract class which should be subclassed .
* See { @ link CMSMain } for a good example .
*
2008-02-25 03:10:37 +01:00
* @ package cms
* @ subpackage core
2007-07-19 12:40:05 +02:00
*/
2008-04-05 05:43:58 +02:00
class LeftAndMain extends Controller {
/**
2008-11-02 22:27:55 +01:00
* The 'base' url for CMS administration areas .
* Note that if this is changed , many javascript
* behaviours need to be updated with the correct url
2008-04-05 05:43:58 +02:00
*
2008-11-02 22:27:55 +01:00
* @ var string $url_base
2008-04-05 05:43:58 +02:00
*/
2009-01-05 07:17:59 +01:00
static $url_base = " admin " ;
2008-11-02 22:27:55 +01:00
static $url_segment ;
2008-12-04 23:38:58 +01:00
static $url_rule = '/$Action/$ID/$OtherID' ;
2008-11-02 22:27:55 +01:00
static $menu_title ;
static $menu_priority = 0 ;
static $url_priority = 50 ;
static $tree_class = null ;
2008-04-05 05:43:58 +02:00
2007-07-19 12:40:05 +02:00
static $ForceReload ;
2007-09-14 21:26:56 +02:00
2008-02-25 03:10:37 +01:00
static $allowed_actions = array (
2009-09-10 03:38:29 +02:00
'index' ,
2008-02-25 03:10:37 +01:00
'ajaxupdateparent' ,
'ajaxupdatesort' ,
'callPageMethod' ,
'deleteitems' ,
'getitem' ,
'getsubtree' ,
'myprofile' ,
'printable' ,
'save' ,
'show' ,
2008-08-09 07:57:44 +02:00
'Member_ProfileForm' ,
'EditorToolbar' ,
2008-08-11 02:03:57 +02:00
'EditForm' ,
2008-02-25 03:10:37 +01:00
);
2008-07-17 23:08:35 +02:00
/**
* Register additional requirements through the { @ link Requirements class } .
* Used mainly to work around the missing " lazy loading " functionality
* for getting css / javascript required after an ajax - call ( e . g . loading the editform ) .
*
* @ var array $extra_requirements
*/
protected static $extra_requirements = array (
'javascript' => array (),
'css' => array (),
'themedcss' => array (),
);
2009-01-05 07:17:59 +01:00
/**
* @ param Member $member
* @ return boolean
*/
function canView ( $member = null ) {
if ( ! $member && $member !== FALSE ) {
$member = Member :: currentUser ();
}
// cms menus only for logged-in members
if ( ! $member ) return false ;
// alternative decorated checks
if ( $this -> hasMethod ( 'alternateAccessCheck' )) {
$alternateAllowed = $this -> alternateAccessCheck ();
if ( $alternateAllowed === FALSE ) return false ;
}
// Default security check for LeftAndMain sub-class permissions
2009-12-17 22:53:03 +01:00
if ( ! Permission :: checkMember ( $member , " CMS_ACCESS_ $this->class " ) &&
! Permission :: checkMember ( $member , " CMS_ACCESS_LeftAndMain " )) {
2009-01-05 07:17:59 +01:00
return false ;
}
return true ;
}
2008-11-07 13:21:10 +01:00
/**
* @ uses LeftAndMainDecorator -> init ()
* @ uses LeftAndMainDecorator -> accessedCMS ()
2009-01-05 07:17:59 +01:00
* @ uses CMSMenu
2008-11-07 13:21:10 +01:00
*/
2007-07-19 12:40:05 +02:00
function init () {
2009-01-05 07:17:59 +01:00
parent :: init ();
2007-09-27 22:56:55 +02:00
// set language
$member = Member :: currentUser ();
2007-10-21 21:53:57 +02:00
if ( ! empty ( $member -> Locale )) {
i18n :: set_locale ( $member -> Locale );
2007-09-27 22:56:55 +02:00
}
2007-11-13 01:14:15 +01:00
2009-01-05 07:17:59 +01:00
// can't be done in cms/_config.php as locale is not set yet
CMSMenu :: add_link (
'Help' ,
_t ( 'LeftAndMain.HELP' , 'Help' , PR_HIGH , 'Menu title' ),
2009-11-05 04:08:41 +01:00
'http://userhelp.silverstripe.org'
2009-01-05 07:17:59 +01:00
);
2007-11-13 01:14:15 +01:00
// set reading lang
2009-11-26 23:38:04 +01:00
if ( Object :: has_extension ( 'SiteTree' , 'Translatable' ) && ! Director :: is_ajax ()) {
2009-04-03 23:26:51 +02:00
Translatable :: choose_site_locale ( array_keys ( Translatable :: get_existing_content_languages ( 'SiteTree' )));
2007-11-13 01:14:15 +01:00
}
2007-09-14 21:26:56 +02:00
2007-08-31 02:31:49 +02:00
// Allow customisation of the access check by a decorator
2010-01-13 01:03:18 +01:00
// Also all the canView() check to execute Director::redirect()
if ( ! $this -> canView () && ! $this -> response -> isFinished ()) {
2009-01-05 07:17:59 +01:00
// When access /admin/, we should try a redirect to another part of the admin rather than be locked out
$menu = $this -> MainMenu ();
foreach ( $menu as $candidate ) {
if (
$candidate -> Link &&
$candidate -> Link != $this -> Link ()
&& $candidate -> MenuItem -> controller
&& singleton ( $candidate -> MenuItem -> controller ) -> canView ()
) {
return Director :: redirect ( $candidate -> Link );
2007-07-19 12:40:05 +02:00
}
}
2009-01-05 07:17:59 +01:00
if ( Member :: currentUser ()) {
Session :: set ( " BackURL " , null );
}
// if no alternate menu items have matched, return a permission error
2007-07-19 12:40:05 +02:00
$messageSet = array (
2007-09-15 22:21:13 +02:00
'default' => _t ( 'LeftAndMain.PERMDEFAULT' , " Please choose an authentication method and enter your credentials to access the CMS. " ),
'alreadyLoggedIn' => _t ( 'LeftAndMain.PERMALREADY' , " I'm sorry, but you can't access that part of the CMS. If you want to log in as someone else, do so below " ),
'logInAgain' => _t ( 'LeftAndMain.PERMAGAIN' , " You have been logged out of the CMS. If you would like to log in again, enter a username and password below. " ),
2007-07-19 12:40:05 +02:00
);
2009-01-05 07:17:59 +01:00
return Security :: permissionFailure ( $this , $messageSet );
2007-07-19 12:40:05 +02:00
}
2010-01-13 01:03:18 +01:00
2009-01-05 07:17:59 +01:00
// Don't continue if there's already been a redirection request.
if ( Director :: redirected_to ()) return ;
2008-08-13 02:14:31 +02:00
// Audit logging hook
if ( empty ( $_REQUEST [ 'executeForm' ]) && ! Director :: is_ajax ()) $this -> extend ( 'accessedCMS' );
2009-05-14 08:11:18 +02:00
2009-08-10 06:34:17 +02:00
// Set the members html editor config
HtmlEditorConfig :: set_active ( Member :: currentUser () -> getHtmlEditorConfigForCMS ());
2009-12-03 04:53:40 +01:00
// Set default values in the config if missing. These things can't be defined in the config
// file because insufficient information exists when that is being processed
$htmlEditorConfig = HtmlEditorConfig :: get_active ();
if ( ! $htmlEditorConfig -> getOption ( 'content_css' )) {
$cssFiles = 'cms/css/editor.css' ;
if ( SSViewer :: current_theme ()) $cssFiles .= ', ' . THEMES_DIR . " / " . SSViewer :: current_theme () . '/css/editor.css' ;
else if ( project ()) $cssFiles .= ', ' . project () . '/css/editor.css' ;
$htmlEditorConfig -> setOption ( 'content_css' , $cssFiles );
}
2009-08-10 06:34:17 +02:00
ENHANCEMENT Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@63154 467b73ca-7a2a-4603-9d3b-597d59a354a9
2008-09-27 18:02:38 +02:00
Requirements :: css ( CMS_DIR . '/css/typography.css' );
Requirements :: css ( CMS_DIR . '/css/layout.css' );
Requirements :: css ( CMS_DIR . '/css/cms_left.css' );
Requirements :: css ( CMS_DIR . '/css/cms_right.css' );
2008-11-12 05:31:53 +01:00
Requirements :: css ( SAPPHIRE_DIR . '/css/Form.css' );
2008-08-11 07:29:12 +02:00
2008-09-16 23:46:08 +02:00
if ( isset ( $_REQUEST [ 'debug_firebug' ])) {
// Firebug is a useful console for debugging javascript
// Its available as a Firefox extension or a javascript library
// for easy inclusion in other browsers (just append ?debug_firebug=1 to the URL)
2009-11-26 06:08:34 +01:00
Requirements :: javascript ( THIRDPARTY_DIR . '/firebug-lite/firebug.js' );
2008-09-16 23:46:08 +02:00
} else {
// By default, we include fake-objects for all firebug calls
// to avoid javascript errors when referencing console.log() etc in javascript code
2009-11-26 06:08:34 +01:00
Requirements :: javascript ( THIRDPARTY_DIR . '/firebug-lite/firebugx.js' );
2008-09-16 23:46:08 +02:00
}
2009-11-26 06:08:34 +01:00
Requirements :: javascript ( SAPPHIRE_DIR . '/thirdparty/prototype/prototype.js' );
2008-10-16 04:09:46 +02:00
Requirements :: javascript ( THIRDPARTY_DIR . '/jquery/jquery.js' );
2009-11-26 06:08:34 +01:00
Requirements :: javascript ( SAPPHIRE_DIR . '/javascript/jquery_improvements.js' );
Requirements :: javascript ( THIRDPARTY_DIR . '/behaviour/behaviour.js' );
Requirements :: javascript ( THIRDPARTY_DIR . '/jquery-livequery/jquery.livequery.js' );
2008-11-12 05:31:53 +01:00
Requirements :: javascript ( SAPPHIRE_DIR . '/javascript/core/jquery.ondemand.js' );
2009-11-26 06:08:34 +01:00
Requirements :: javascript ( SAPPHIRE_DIR . '/javascript/prototype_improvements.js' );
Requirements :: javascript ( SAPPHIRE_DIR . '/javascript/loader.js' );
Requirements :: javascript ( CMS_DIR . '/javascript/hover.js' );
Requirements :: javascript ( SAPPHIRE_DIR . '/javascript/layout_helpers.js' );
2009-03-10 22:59:19 +01:00
Requirements :: add_i18n_javascript ( SAPPHIRE_DIR . '/javascript/lang' );
2009-04-29 03:44:28 +02:00
Requirements :: add_i18n_javascript ( CMS_DIR . '/javascript/lang' );
2008-09-16 23:46:08 +02:00
ENHANCEMENT Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@63154 467b73ca-7a2a-4603-9d3b-597d59a354a9
2008-09-27 18:02:38 +02:00
Requirements :: javascript ( THIRDPARTY_DIR . '/scriptaculous/effects.js' );
Requirements :: javascript ( THIRDPARTY_DIR . '/scriptaculous/dragdrop.js' );
Requirements :: javascript ( THIRDPARTY_DIR . '/scriptaculous/controls.js' );
2007-09-27 22:56:55 +02:00
ENHANCEMENT Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@63154 467b73ca-7a2a-4603-9d3b-597d59a354a9
2008-09-27 18:02:38 +02:00
Requirements :: css ( THIRDPARTY_DIR . '/greybox/greybox.css' );
Requirements :: javascript ( THIRDPARTY_DIR . '/greybox/AmiJS.js' );
Requirements :: javascript ( THIRDPARTY_DIR . '/greybox/greybox.js' );
2007-09-27 22:56:55 +02:00
2009-11-26 06:08:34 +01:00
Requirements :: javascript ( SAPPHIRE_DIR . '/javascript/tree/tree.js' );
ENHANCEMENT Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@63154 467b73ca-7a2a-4603-9d3b-597d59a354a9
2008-09-27 18:02:38 +02:00
Requirements :: css ( THIRDPARTY_DIR . '/tree/tree.css' );
2007-11-15 23:31:22 +01:00
ENHANCEMENT Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@63154 467b73ca-7a2a-4603-9d3b-597d59a354a9
2008-09-27 18:02:38 +02:00
Requirements :: javascript ( CMS_DIR . '/javascript/LeftAndMain.js' );
Requirements :: javascript ( CMS_DIR . '/javascript/LeftAndMain_left.js' );
Requirements :: javascript ( CMS_DIR . '/javascript/LeftAndMain_right.js' );
2007-09-27 22:56:55 +02:00
ENHANCEMENT Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@63154 467b73ca-7a2a-4603-9d3b-597d59a354a9
2008-09-27 18:02:38 +02:00
Requirements :: javascript ( CMS_DIR . '/javascript/SideTabs.js' );
Requirements :: javascript ( CMS_DIR . '/javascript/SideReports.js' );
Requirements :: javascript ( CMS_DIR . '/javascript/LangSelector.js' );
Requirements :: javascript ( CMS_DIR . '/javascript/TranslationTab.js' );
2008-02-25 03:10:37 +01:00
2010-02-16 04:01:30 +01:00
// navigator
Requirements :: css ( SAPPHIRE_DIR . '/css/SilverStripeNavigator.css' );
Requirements :: javascript ( SAPPHIRE_DIR . '/javascript/SilverStripeNavigator.js' );
2007-09-27 22:56:55 +02:00
Requirements :: themedCSS ( 'typography' );
2008-11-12 05:31:53 +01:00
2008-07-17 23:08:35 +02:00
foreach ( self :: $extra_requirements [ 'javascript' ] as $file ) {
Requirements :: javascript ( $file [ 0 ]);
}
foreach ( self :: $extra_requirements [ 'css' ] as $file ) {
Requirements :: css ( $file [ 0 ], $file [ 1 ]);
}
foreach ( self :: $extra_requirements [ 'themedcss' ] as $file ) {
Requirements :: css ( $file [ 0 ], $file [ 1 ]);
}
2008-08-11 07:29:12 +02:00
Requirements :: customScript ( 'Behaviour.addLoader(hideLoading);' );
2007-09-16 04:21:47 +02:00
2008-12-04 23:38:58 +01:00
// Javascript combined files
Requirements :: combine_files (
'assets/base.js' ,
array (
2009-11-26 06:08:34 +01:00
THIRDPARTY_DIR . '/prototype/prototype.js' ,
THIRDPARTY_DIR . '/behaviour/behaviour.js' ,
SAPPHIRE_DIR . '/javascript/prototype_improvements.js' ,
THIRDPARTY_DIR . '/jquery/jquery.js' ,
THIRDPARTY_DIR . '/jquery-livequery/jquery.livequery.js' ,
THIRDPARTY_DIR . '/jquery-effen/jquery.fn.js' ,
SAPPHIRE_DIR . '/javascript/core/jquery.ondemand.js' ,
SAPPHIRE_DIR . '/javascript/jquery_improvements.js' ,
THIRDPARTY_DIR . '/firebug-lite/firebugx.js' ,
SAPPHIRE_DIR . '/javascript/i18n.js' ,
2008-12-04 23:38:58 +01:00
)
);
Requirements :: combine_files (
'assets/leftandmain.js' ,
array (
2009-11-26 06:08:34 +01:00
SAPPHIRE_DIR . '/javascript/loader.js' ,
CMS_DIR . '/javascript/hover.js' ,
SAPPHIRE_DIR . '/javascript/layout_helpers.js' ,
THIRDPARTY_DIR . '/scriptaculous/effects.js' ,
THIRDPARTY_DIR . '/scriptaculous/dragdrop.js' ,
THIRDPARTY_DIR . '/scriptaculous/controls.js' ,
THIRDPARTY_DIR . '/greybox/AmiJS.js' ,
THIRDPARTY_DIR . '/greybox/greybox.js' ,
CMS_DIR . '/javascript/LeftAndMain.js' ,
CMS_DIR . '/javascript/LeftAndMain_left.js' ,
CMS_DIR . '/javascript/LeftAndMain_right.js' ,
SAPPHIRE_DIR . '/javascript/tree/tree.js' ,
THIRDPARTY_DIR . '/tabstrip/tabstrip.js' ,
SAPPHIRE_DIR . '/javascript/TreeSelectorField.js' ,
CMS_DIR . '/javascript/ThumbnailStripField.js' ,
2008-12-04 23:38:58 +01:00
)
);
Requirements :: combine_files (
'assets/cmsmain.js' ,
array (
2009-11-26 06:08:34 +01:00
CMS_DIR . '/javascript/CMSMain.js' ,
CMS_DIR . '/javascript/CMSMain_left.js' ,
CMS_DIR . '/javascript/CMSMain_right.js' ,
CMS_DIR . '/javascript/SideTabs.js' ,
CMS_DIR . '/javascript/SideReports.js' ,
CMS_DIR . '/javascript/LangSelector.js' ,
CMS_DIR . '/javascript/TranslationTab.js' ,
THIRDPARTY_DIR . '/calendar/calendar.js' ,
THIRDPARTY_DIR . '/calendar/lang/calendar-en.js' ,
THIRDPARTY_DIR . '/calendar/calendar-setup.js' ,
2008-12-04 23:38:58 +01:00
)
);
2008-11-07 13:21:10 +01:00
$dummy = null ;
$this -> extend ( 'init' , $dummy );
2010-02-05 01:28:16 +01:00
// The user's theme shouldn't affect the CMS, if, for example, they have replaced
// TableListField.ss or Form.ss.
SSViewer :: set_theme ( null );
2007-07-19 12:40:05 +02:00
}
2007-09-14 21:26:56 +02:00
2010-02-16 04:45:39 +01:00
/**
* If this is set to true , the " switchView " context in the
* template is shown , with links to the staging and publish site .
*
* @ return boolean
*/
function ShowSwitchView () {
return false ;
}
2007-07-19 12:40:05 +02:00
//------------------------------------------------------------------------------------------//
// Main controllers
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
/**
* You should implement a Link () function in your subclass of LeftAndMain ,
* to point to the URL of that particular controller .
2008-04-05 05:43:58 +02:00
*
* @ return string
2007-07-19 12:40:05 +02:00
*/
2008-11-02 22:27:55 +01:00
public function Link ( $action = null ) {
2008-11-18 02:48:50 +01:00
// Handle missing url_segments
if ( ! $this -> stat ( 'url_segment' , true ))
self :: $url_segment = $this -> class ;
2008-11-02 22:27:55 +01:00
return Controller :: join_links (
$this -> stat ( 'url_base' , true ),
$this -> stat ( 'url_segment' , true ),
'/' , // trailing slash needed if $action is null!
" $action "
);
}
2009-01-05 07:17:59 +01:00
/**
* Returns the menu title for the given LeftAndMain subclass .
* Implemented static so that we can get this value without instantiating an object .
* Menu title is * not * internationalised .
*/
static function menu_title_for_class ( $class ) {
$title = eval ( " return $class :: \$ menu_title; " );
if ( ! $title ) $title = preg_replace ( '/Admin$/' , '' , $class );
return $title ;
}
2007-09-14 21:26:56 +02:00
2010-01-13 00:52:10 +01:00
public function show () {
$params = $this -> getURLParams ();
2007-07-19 12:40:05 +02:00
if ( $params [ 'ID' ]) $this -> setCurrentPageID ( $params [ 'ID' ]);
2010-01-13 00:52:10 +01:00
if ( isset ( $params [ 'OtherID' ])) {
2007-07-19 12:40:05 +02:00
Session :: set ( 'currentMember' , $params [ 'OtherID' ]);
2010-01-13 00:52:10 +01:00
}
2007-07-19 12:40:05 +02:00
if ( Director :: is_ajax ()) {
SSViewer :: setOption ( 'rewriteHashlinks' , false );
return $this -> EditForm () -> formHtmlContent ();
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
} else {
return array ();
}
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
public function getitem () {
$this -> setCurrentPageID ( $_REQUEST [ 'ID' ]);
SSViewer :: setOption ( 'rewriteHashlinks' , false );
2008-11-03 15:56:36 +01:00
2008-11-04 14:53:11 +01:00
if ( isset ( $_REQUEST [ 'ID' ]) && is_numeric ( $_REQUEST [ 'ID' ])) {
2008-11-03 15:56:36 +01:00
$record = DataObject :: get_by_id ( $this -> stat ( 'tree_class' ), $_REQUEST [ 'ID' ]);
if ( $record && ! $record -> canView ()) return Security :: permissionFailure ( $this );
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
$form = $this -> EditForm ();
2010-02-16 04:45:20 +01:00
if ( $form ) {
$content = $form -> formHtmlContent ();
if ( $this -> ShowSwitchView ()) {
$content .= '<div id="AjaxSwitchView">' . $this -> SwitchView () . '</div>' ;
}
return $content ;
}
2007-07-19 12:40:05 +02:00
else return " " ;
}
public function getLastFormIn ( $html ) {
$parts = split ( '</?form[^>]*>' , $html );
return $parts [ sizeof ( $parts ) - 2 ];
}
//------------------------------------------------------------------------------------------//
// Main UI components
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
/**
* Returns the main menu of the CMS . This is also used by init () to work out which sections the user
* has access to .
2008-04-05 05:43:58 +02:00
*
* @ return DataObjectSet
2007-07-19 12:40:05 +02:00
*/
public function MainMenu () {
// Don't accidentally return a menu if you're not logged in - it's used to determine access.
2008-12-04 23:38:58 +01:00
if ( ! Member :: currentUser ()) return new DataObjectSet ();
2007-07-19 12:40:05 +02:00
// Encode into DO set
2007-09-14 21:26:56 +02:00
$menu = new DataObjectSet ();
2009-01-05 07:17:59 +01:00
$menuItems = CMSMenu :: get_viewable_menu_items ();
if ( $menuItems ) foreach ( $menuItems as $code => $menuItem ) {
// alternate permission checks (in addition to LeftAndMain->canView())
if (
isset ( $menuItem -> controller )
&& $this -> hasMethod ( 'alternateMenuDisplayCheck' )
&& ! $this -> alternateMenuDisplayCheck ( $menuItem -> controller )
) {
continue ;
2007-08-31 02:31:49 +02:00
}
2008-04-05 05:43:58 +02:00
$linkingmode = " " ;
2008-11-02 22:27:55 +01:00
2008-11-18 02:48:50 +01:00
if ( strpos ( $this -> Link (), $menuItem -> url ) !== false ) {
if ( $this -> Link () == $menuItem -> url ) {
$linkingmode = " current " ;
2008-11-02 22:27:55 +01:00
// default menu is the one with a blank {@link url_segment}
2008-11-18 02:48:50 +01:00
} else if ( singleton ( $menuItem -> controller ) -> stat ( 'url_segment' ) == '' ) {
if ( $this -> Link () == $this -> stat ( 'url_base' ) . '/' ) $linkingmode = " current " ;
2008-04-05 05:43:58 +02:00
} else {
$linkingmode = " current " ;
2007-07-19 12:40:05 +02:00
}
}
2008-04-05 05:43:58 +02:00
2008-11-02 23:45:49 +01:00
// already set in CMSMenu::populate_menu(), but from a static pre-controller
// context, so doesn't respect the current user locale in _t() calls - as a workaround,
2009-02-03 03:50:25 +01:00
// we simply call LeftAndMain::menu_title_for_class() again if we're dealing with a controller
2008-11-02 23:45:49 +01:00
if ( $menuItem -> controller ) {
2009-01-05 07:17:59 +01:00
$defaultTitle = LeftAndMain :: menu_title_for_class ( $menuItem -> controller );
$title = _t ( " { $menuItem -> controller } .MENUTITLE " , $defaultTitle );
2008-11-02 23:45:49 +01:00
} else {
$title = $menuItem -> title ;
}
2008-04-05 05:43:58 +02:00
$menu -> push ( new ArrayData ( array (
2009-01-05 07:17:59 +01:00
" MenuItem " => $menuItem ,
2008-11-02 23:45:49 +01:00
" Title " => Convert :: raw2xml ( $title ),
2008-04-05 05:43:58 +02:00
" Code " => $code ,
2008-11-02 22:27:55 +01:00
" Link " => $menuItem -> url ,
2008-04-05 05:43:58 +02:00
" LinkingMode " => $linkingmode
)));
2007-07-19 12:40:05 +02:00
}
2008-04-05 05:43:58 +02:00
// if no current item is found, assume that first item is shown
//if(!isset($foundCurrent))
return $menu ;
2007-07-19 12:40:05 +02:00
}
2008-09-23 04:24:23 +02:00
2009-02-03 03:50:25 +01:00
public function CMSTopMenu () {
return $this -> renderWith ( array ( 'CMSTopMenu_alternative' , 'CMSTopMenu' ));
}
2007-07-19 12:40:05 +02:00
/**
* Return a list of appropriate templates for this class , with the given suffix
2007-09-14 21:26:56 +02:00
*/
2007-07-19 12:40:05 +02:00
protected function getTemplatesWithSuffix ( $suffix ) {
$classes = array_reverse ( ClassInfo :: ancestry ( $this -> class ));
foreach ( $classes as $class ) {
$templates [] = $class . $suffix ;
if ( $class == 'LeftAndMain' ) break ;
}
return $templates ;
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
public function Left () {
return $this -> renderWith ( $this -> getTemplatesWithSuffix ( '_left' ));
}
2008-12-04 23:38:58 +01:00
2007-07-19 12:40:05 +02:00
public function Right () {
return $this -> renderWith ( $this -> getTemplatesWithSuffix ( '_right' ));
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
public function getRecord ( $id , $className = null ) {
2009-05-01 00:47:28 +02:00
if ( $id && is_numeric ( $id )) {
if ( ! $className ) $className = $this -> stat ( 'tree_class' );
return DataObject :: get_by_id ( $className , $id );
}
2007-07-19 12:40:05 +02:00
}
2009-05-01 00:47:28 +02:00
/**
* Get a site tree displaying the nodes under the given objects
* @ param $className The class of the root object
* @ param $rootID The ID of the root object . If this is null then a complete tree will be
* shown
* @ param $childrenMethod The method to call to get the children of the tree . For example ,
* Children , AllChildrenIncludingDeleted , or AllHistoricalChildren
*/
2010-01-13 01:06:28 +01:00
function getSiteTreeFor ( $className , $rootID = null , $childrenMethod = null , $numChildrenMethod = null , $filterFunction = null , $minNodeCount = 30 ) {
// Default childrenMethod and numChildrenMethod
2009-05-14 08:11:18 +02:00
if ( ! $childrenMethod ) $childrenMethod = 'AllChildrenIncludingDeleted' ;
2010-01-13 01:06:28 +01:00
if ( ! $numChildrenMethod ) $numChildrenMethod = 'numChildren' ;
2009-05-14 08:11:18 +02:00
// Get the tree root
2007-07-19 12:40:05 +02:00
$obj = $rootID ? $this -> getRecord ( $rootID ) : singleton ( $className );
2009-05-14 08:11:18 +02:00
// Mark the nodes of the tree to return
if ( $filterFunction ) $obj -> setMarkingFilterFunction ( $filterFunction );
2009-07-09 07:36:47 +02:00
2010-01-13 01:06:28 +01:00
$obj -> markPartialTree ( $minNodeCount , $this , $childrenMethod , $numChildrenMethod );
2009-05-14 08:11:18 +02:00
// Ensure current page is exposed
2007-07-19 12:40:05 +02:00
if ( $p = $this -> currentPage ()) $obj -> markToExpose ( $p );
2009-07-31 07:43:47 +02:00
// NOTE: SiteTree/CMSMain coupling :-(
2010-02-16 05:07:21 +01:00
SiteTree :: prepopuplate_permission_cache ( 'CanEditType' , $obj -> markedNodeIDs (), 'SiteTree::can_edit_multiple' );
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
// getChildrenAsUL is a flexible and complex way of traversing the tree
2009-07-09 07:36:47 +02:00
$titleEval = '
2007-07-19 12:40:05 +02:00
" <li id= \" record- $child->ID\ " class = \ " " . $child -> CMSTreeClasses ( $extraArg ) . " \" > " .
2009-11-27 03:11:34 +01:00
" <a href= \" " . Controller :: join_links ( substr ( $extraArg -> Link (), 0 , - 1 ), " show " , $child -> ID ) . " \" class= \" " . $child -> CMSTreeClasses ( $extraArg ) . " \" title= \" ' . _t('LeftAndMain.PAGETYPE','Page type: ') . ' " . $child -> class . " \" > " .
2008-02-25 03:10:37 +01:00
( $child -> TreeTitle ()) .
2007-07-19 12:40:05 +02:00
" </a> "
2009-07-09 07:36:47 +02:00
' ;
$siteTree = $obj -> getChildrenAsUL (
" " ,
$titleEval ,
$this ,
true ,
$childrenMethod ,
2010-01-13 01:06:28 +01:00
$numChildrenMethod ,
2009-07-09 07:36:47 +02:00
$minNodeCount
);
2007-07-19 12:40:05 +02:00
2007-09-14 21:26:56 +02:00
// Wrap the root if needs be.
2007-07-19 12:40:05 +02:00
if ( ! $rootID ) {
2010-02-11 02:02:34 +01:00
$rootLink = $this -> Link ( 'show' ) . '/root' ;
2007-08-16 08:25:17 +02:00
// This lets us override the tree title with an extension
2010-01-26 21:42:11 +01:00
if ( $this -> hasMethod ( 'getCMSTreeTitle' ) && $customTreeTitle = $this -> getCMSTreeTitle ()) {
$treeTitle = $customTreeTitle ;
} else {
$siteConfig = SiteConfig :: current_site_config ();
$treeTitle = $siteConfig -> Title ;
}
2007-08-16 08:25:17 +02:00
2007-10-29 02:45:36 +01:00
$siteTree = " <ul id= \" sitetree \" class= \" tree unformatted \" ><li id= \" record-0 \" class= \" Root nodelete \" ><a href= \" $rootLink\ " >< strong > $treeTitle </ strong ></ a > "
2007-07-19 12:40:05 +02:00
. $siteTree . " </li></ul> " ;
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
return $siteTree ;
}
2007-09-14 21:26:56 +02:00
2009-05-01 00:47:28 +02:00
/**
* Get a subtree underneath the request param 'ID' .
* If ID = 0 , then get the whole tree .
*/
2009-07-09 07:36:47 +02:00
public function getsubtree ( $request ) {
2009-05-01 00:47:28 +02:00
// Get the tree
2009-07-09 07:36:47 +02:00
$minNodeCount = ( is_numeric ( $request -> getVar ( 'minNodeCount' ))) ? $request -> getVar ( 'minNodeCount' ) : NULL ;
$tree = $this -> getSiteTreeFor (
$this -> stat ( 'tree_class' ),
$request -> getVar ( 'ID' ),
null ,
null ,
2010-01-13 01:06:28 +01:00
null ,
2009-07-09 07:36:47 +02:00
$minNodeCount
);
2009-05-01 00:47:28 +02:00
// Trim off the outer tag
$tree = ereg_replace ( '^[ \t\r\n]*<ul[^>]*>' , '' , $tree );
$tree = ereg_replace ( '</ul[^>]*>[ \t\r\n]*$' , '' , $tree );
return $tree ;
2007-07-19 12:40:05 +02:00
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
/**
2007-09-14 21:26:56 +02:00
* Allows you to returns a new data object to the tree ( subclass of sitetree )
* and updates the tree via javascript .
2007-07-19 12:40:05 +02:00
*/
public function returnItemToUser ( $p ) {
if ( Director :: is_ajax ()) {
// Prepare the object for insertion.
2009-04-29 03:44:28 +02:00
$parentID = ( int ) $p -> ParentID ;
2007-09-14 21:26:56 +02:00
$id = $p -> ID ? $p -> ID : " new- $p->class - $p->ParentID " ;
2007-07-19 12:40:05 +02:00
$treeTitle = Convert :: raw2js ( $p -> TreeTitle ());
2009-01-19 01:11:08 +01:00
$hasChildren = ( is_numeric ( $id ) && $p -> AllChildren () && $p -> AllChildren () -> Count ()) ? ' unexpanded' : '' ;
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
// Ensure there is definitly a node avaliable. if not, append to the home tree.
$response = <<< JS
var tree = $ ( 'sitetree' );
2010-01-19 03:49:01 +01:00
var newNode = tree . createTreeNode ( " $id " , " $treeTitle " , " { $p -> class } { $hasChildren } " );
2007-07-19 12:40:05 +02:00
node = tree . getTreeNodeByIdx ( $parentID );
2009-04-29 03:44:28 +02:00
if ( ! node ) {
node = tree . getTreeNodeByIdx ( 0 );
}
2007-07-19 12:40:05 +02:00
node . open ();
node . appendTreeNode ( newNode );
2010-01-19 03:49:01 +01:00
newNode . selectTreeNode ();
2007-07-19 12:40:05 +02:00
JS ;
FormResponse :: add ( $response );
2010-01-19 03:49:01 +01:00
2008-11-18 02:48:50 +01:00
return FormResponse :: respond ();
} else {
2009-04-29 03:44:28 +02:00
Director :: redirect ( 'admin/' . self :: $url_segment . '/show/' . $p -> ID );
2007-07-19 12:40:05 +02:00
}
}
/**
2007-09-15 03:00:03 +02:00
* Save and Publish page handler
2007-07-19 12:40:05 +02:00
*/
public function save ( $urlParams , $form ) {
$className = $this -> stat ( 'tree_class' );
$result = '' ;
2007-09-14 21:26:56 +02:00
2007-09-25 23:58:42 +02:00
$SQL_id = Convert :: raw2sql ( $_REQUEST [ 'ID' ]);
if ( substr ( $SQL_id , 0 , 3 ) != 'new' ) {
2008-11-23 23:58:18 +01:00
$record = DataObject :: get_one ( $className , " \" $className\ " . \ " ID \" = { $SQL_id } " );
2008-11-03 15:56:36 +01:00
if ( $record && ! $record -> canEdit ()) return Security :: permissionFailure ( $this );
2007-07-19 12:40:05 +02:00
} else {
2008-11-03 15:56:36 +01:00
if ( ! singleton ( $this -> stat ( 'tree_class' )) -> canCreate ()) return Security :: permissionFailure ( $this );
2007-09-25 23:58:42 +02:00
$record = $this -> getNewItem ( $SQL_id , false );
2007-07-19 12:40:05 +02:00
}
2007-09-14 21:26:56 +02:00
// We don't want to save a new version if there are no changes
2007-07-19 12:40:05 +02:00
$dataFields_new = $form -> Fields () -> dataFields ();
$dataFields_old = $record -> getAllFields ();
$changed = false ;
$hasNonRecordFields = false ;
foreach ( $dataFields_new as $datafield ) {
// if the form has fields not belonging to the record
if ( ! isset ( $dataFields_old [ $datafield -> Name ()])) {
2007-09-14 21:26:56 +02:00
$hasNonRecordFields = true ;
2007-07-19 12:40:05 +02:00
}
// if field-values have changed
if ( ! isset ( $dataFields_old [ $datafield -> Name ()]) || $dataFields_old [ $datafield -> Name ()] != $datafield -> dataValue ()) {
$changed = true ;
}
}
if ( ! $changed && ! $hasNonRecordFields ) {
// Tell the user we have saved even though we haven't, as not to confuse them
if ( is_a ( $record , " Page " )) {
$record -> Status = " Saved (update) " ;
}
2007-09-15 22:21:13 +02:00
FormResponse :: status_message ( _t ( 'LeftAndMain.SAVEDUP' , " Saved " ), " good " );
2007-07-19 12:40:05 +02:00
FormResponse :: update_status ( $record -> Status );
return FormResponse :: respond ();
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
$form -> dataFieldByName ( 'ID' ) -> Value = 0 ;
if ( isset ( $urlParams [ 'Sort' ]) && is_numeric ( $urlParams [ 'Sort' ])) {
$record -> Sort = $urlParams [ 'Sort' ];
}
// HACK: This should be turned into something more general
$originalClass = $record -> ClassName ;
$originalStatus = $record -> Status ;
2009-05-04 03:27:35 +02:00
$originalParentID = $record -> ParentID ;
2007-07-19 12:40:05 +02:00
$record -> HasBrokenLink = 0 ;
$record -> HasBrokenFile = 0 ;
$record -> writeWithoutVersion ();
// HACK: This should be turned into something more general
$originalURLSegment = $record -> URLSegment ;
$form -> saveInto ( $record , true );
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
if ( is_a ( $record , " Page " )) {
$record -> Status = ( $record -> Status == " New page " || $record -> Status == " Saved (new) " ) ? " Saved (new) " : " Saved (update) " ;
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
if ( Director :: is_ajax ()) {
2007-09-25 23:58:42 +02:00
if ( $SQL_id != $record -> ID ) {
FormResponse :: add ( " $ ('sitetree').setNodeIdx( \" { $SQL_id } \" , \" $record->ID\ " ); " );
2007-07-19 12:40:05 +02:00
FormResponse :: add ( " $ ('Form_EditForm').elements.ID.value = \" $record->ID\ " ; " );
}
if ( $added = DataObjectLog :: getAdded ( 'SiteTree' )) {
foreach ( $added as $page ) {
if ( $page -> ID != $record -> ID ) $result .= $this -> addTreeNodeJS ( $page );
}
}
if ( $deleted = DataObjectLog :: getDeleted ( 'SiteTree' )) {
foreach ( $deleted as $page ) {
if ( $page -> ID != $record -> ID ) $result .= $this -> deleteTreeNodeJS ( $page );
}
}
if ( $changed = DataObjectLog :: getChanged ( 'SiteTree' )) {
foreach ( $changed as $page ) {
if ( $page -> ID != $record -> ID ) {
$title = Convert :: raw2js ( $page -> TreeTitle ());
2008-07-18 05:40:32 +02:00
FormResponse :: add ( " $ ('sitetree').setNodeTitle( $page->ID , \" $title\ " ); " );
2007-07-19 12:40:05 +02:00
}
}
}
2007-09-14 21:26:56 +02:00
2007-09-15 22:21:13 +02:00
$message = _t ( 'LeftAndMain.SAVEDUP' );
2007-07-19 12:40:05 +02:00
2009-04-27 07:58:54 +02:00
// Update the class instance if necessary
2007-07-19 12:40:05 +02:00
if ( $originalClass != $record -> ClassName ) {
2009-04-27 07:58:54 +02:00
$newClassName = $record -> ClassName ;
// The records originally saved attribute was overwritten by $form->saveInto($record) before.
// This is necessary for newClassInstance() to work as expected, and trigger change detection
// on the ClassName attribute
$record -> setClassName ( $originalClass );
// Replace $record with a new instance
$record = $record -> newClassInstance ( $newClassName );
// update the tree icon
2007-07-19 12:40:05 +02:00
FormResponse :: add ( " if( \$ ('sitetree').setNodeIcon) \$ ('sitetree').setNodeIcon( $record->ID , ' $originalClass ', ' $record->ClassName '); " );
}
// HACK: This should be turned into somethign more general
2010-02-16 05:06:42 +01:00
// Removed virtualpage test as we need to draft/published links when url is changed
if ( ( /*$record->class == 'VirtualPage' &&*/ $originalURLSegment != $record -> URLSegment ) ||
2007-07-19 12:40:05 +02:00
( $originalClass != $record -> ClassName ) || self :: $ForceReload == true ) {
FormResponse :: add ( " $ ('Form_EditForm').getPageFromServer( $record->ID ); " );
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
// After reloading action
if ( $originalStatus != $record -> Status ) {
2007-09-15 22:21:13 +02:00
$message .= sprintf ( _t ( 'LeftAndMain.STATUSTO' , " Status changed to '%s' " ), $record -> Status );
2007-07-19 12:40:05 +02:00
}
2009-05-04 03:27:35 +02:00
if ( $originalParentID != $record -> ParentID ) {
FormResponse :: add ( " if( \$ ('sitetree').setNodeParentID) \$ ('sitetree').setNodeParentID( $record->ID , $record->ParentID ); " );
}
2007-09-14 21:26:56 +02:00
$record -> write ();
2010-01-19 03:49:01 +01:00
2008-02-25 03:10:37 +01:00
if ( ( $record -> class != 'VirtualPage' ) && $originalURLSegment != $record -> URLSegment ) {
$message .= sprintf ( _t ( 'LeftAndMain.CHANGEDURL' , " Changed URL to '%s' " ), $record -> URLSegment );
FormResponse :: add ( " \$ ('Form_EditForm').elements.URLSegment.value = \" $record->URLSegment\ " ; " );
2010-01-13 00:53:43 +01:00
FormResponse :: add ( " \$ ('Form_EditForm_StageURLSegment').value = \" " . $record -> AbsoluteLink () . " \" ; " );
2008-02-25 03:10:37 +01:00
}
2010-02-04 05:39:25 +01:00
2010-02-10 22:59:57 +01:00
if ( $virtualPages = DataObject :: get ( " VirtualPage " , " \" CopyContentFromID \" = $record->ID " )) {
2010-02-04 05:39:25 +01:00
foreach ( $virtualPages as $page ) {
if ( $page -> ID != $record -> ID ) {
$title = Convert :: raw2js ( $page -> TreeTitle ());
FormResponse :: add ( " $ ('sitetree').setNodeTitle( $page->ID , \" $title\ " ); " );
}
}
}
2008-02-25 03:10:37 +01:00
2007-09-16 17:02:57 +02:00
// If the 'Save & Publish' button was clicked, also publish the page
if ( isset ( $urlParams [ 'publish' ]) && $urlParams [ 'publish' ] == 1 ) {
2009-10-16 00:44:29 +02:00
$this -> extend ( 'onAfterSave' , $record );
2008-08-12 04:59:27 +02:00
$record -> doPublish ();
2007-09-25 23:58:42 +02:00
2009-04-27 07:58:54 +02:00
// Update classname with original and get new instance (see above for explanation)
$record -> setClassName ( $originalClass );
$publishedRecord = $record -> newClassInstance ( $record -> ClassName );
2007-09-25 23:58:42 +02:00
2009-01-05 07:17:59 +01:00
return $this -> tellBrowserAboutPublicationChange (
$publishedRecord ,
sprintf (
_t (
'LeftAndMain.STATUSPUBLISHEDSUCCESS' ,
" Published '%s' successfully " ,
PR_MEDIUM ,
'Status message after publishing a page, showing the page title'
),
$record -> Title
)
);
2007-09-16 17:02:57 +02:00
} else {
// BUGFIX: Changed icon only shows after Save button is clicked twice http://support.silverstripe.com/gsoc/ticket/76
$title = Convert :: raw2js ( $record -> TreeTitle ());
FormResponse :: add ( " $ ('sitetree').setNodeTitle( \" $record->ID\ " , \ " $title\ " ); " );
$result .= $this -> getActionUpdateJS ( $record );
FormResponse :: status_message ( $message , " good " );
FormResponse :: update_status ( $record -> Status );
2009-11-10 22:37:11 +01:00
2009-10-16 00:44:29 +02:00
$this -> extend ( 'onAfterSave' , $record );
2010-01-19 03:49:01 +01:00
2007-09-16 17:02:57 +02:00
return FormResponse :: respond ();
}
2007-09-15 03:00:03 +02:00
}
2007-07-19 12:40:05 +02:00
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
/**
* Return a piece of javascript that will update the actions of the main form
*/
public function getActionUpdateJS ( $record ) {
// Get the new action buttons
2008-10-03 02:48:34 +02:00
2007-07-19 12:40:05 +02:00
$tempForm = $this -> getEditForm ( $record -> ID );
$actionList = '' ;
foreach ( $tempForm -> Actions () as $action ) {
$actionList .= $action -> Field () . ' ' ;
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
FormResponse :: add ( " $ ('Form_EditForm').loadActionsFromString(' " . Convert :: raw2js ( $actionList ) . " '); " );
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
return FormResponse :: respond ();
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
/**
* Return JavaScript code to generate a tree node for the given page , if visible
*/
2007-10-01 07:23:04 +02:00
public function addTreeNodeJS ( $page , $select = false ) {
2007-07-19 12:40:05 +02:00
$parentID = ( int ) $page -> ParentID ;
$title = Convert :: raw2js ( $page -> TreeTitle ());
$response = <<< JS
2007-10-01 07:23:04 +02:00
var newNode = $ ( 'sitetree' ) . createTreeNode ( $page -> ID , " $title " , " $page->class " );
var parentNode = $ ( 'sitetree' ) . getTreeNodeByIdx ( $parentID );
if ( parentNode ) parentNode . appendTreeNode ( newNode );
2007-07-19 12:40:05 +02:00
JS ;
2007-10-01 07:23:04 +02:00
$response .= ( $select ? " newNode.selectTreeNode(); \n " : " " ) ;
2007-07-19 12:40:05 +02:00
FormResponse :: add ( $response );
return FormResponse :: respond ();
}
/**
* Return JavaScript code to remove a tree node for the given page , if it exists .
*/
public function deleteTreeNodeJS ( $page ) {
2007-09-14 21:26:56 +02:00
$id = $page -> ID ? $page -> ID : $page -> OldID ;
2007-07-19 12:40:05 +02:00
$response = <<< JS
2007-09-14 21:26:56 +02:00
var node = $ ( 'sitetree' ) . getTreeNodeByIdx ( $id );
if ( node && node . parentTreeNode ) node . parentTreeNode . removeTreeNode ( node );
2007-07-19 12:40:05 +02:00
$ ( 'Form_EditForm' ) . closeIfSetTo ( $id );
JS ;
FormResponse :: add ( $response );
2010-01-13 01:08:13 +01:00
// If we have that page selected currently, then clear that info from the session
if ( Session :: get ( " { $this -> class } .currentPage " ) == $id ) {
$this -> setCurrentPageID ( null );
}
2009-07-23 02:54:40 +02:00
2007-07-19 12:40:05 +02:00
return FormResponse :: respond ();
}
2007-09-14 21:26:56 +02:00
/**
2007-07-19 12:40:05 +02:00
* Sets a static variable on this class which means the panel will be reloaded .
*/
static function ForceReload (){
self :: $ForceReload = true ;
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
/**
* Ajax handler for updating the parent of a tree node
*/
public function ajaxupdateparent () {
$id = $_REQUEST [ 'ID' ];
$parentID = $_REQUEST [ 'ParentID' ];
if ( $parentID == 'root' ){
2007-09-14 21:26:56 +02:00
$parentID = 0 ;
2007-07-19 12:40:05 +02:00
}
$_REQUEST [ 'ajax' ] = 1 ;
2009-05-18 01:19:51 +02:00
$cleanupJS = '' ;
2009-08-10 00:29:45 +02:00
if ( ! Permission :: check ( 'SITETREE_REORGANISE' ) && ! Permission :: check ( 'ADMIN' )) {
FormResponse :: status_message ( _t ( 'LeftAndMain.CANT_REORGANISE' , " You do not have permission to rearange the site tree. Your change was not saved. " ), " bad " );
return FormResponse :: respond ();
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
if ( is_numeric ( $id ) && is_numeric ( $parentID ) && $id != $parentID ) {
$node = DataObject :: get_by_id ( $this -> stat ( 'tree_class' ), $id );
if ( $node ){
2008-11-03 15:56:36 +01:00
if ( $node && ! $node -> canEdit ()) return Security :: permissionFailure ( $this );
2007-07-19 12:40:05 +02:00
$node -> ParentID = $parentID ;
$node -> Status = " Saved (update) " ;
$node -> write ();
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
if ( is_numeric ( $_REQUEST [ 'CurrentlyOpenPageID' ])) {
$currentPage = DataObject :: get_by_id ( $this -> stat ( 'tree_class' ), $_REQUEST [ 'CurrentlyOpenPageID' ]);
if ( $currentPage ) {
$cleanupJS = $currentPage -> cmsCleanup_parentChanged ();
}
}
2007-09-14 21:26:56 +02:00
2007-09-15 22:21:13 +02:00
FormResponse :: status_message ( _t ( 'LeftAndMain.SAVED' , 'saved' ), 'good' );
2008-11-05 05:20:35 +01:00
if ( $cleanupJS ) FormResponse :: add ( $cleanupJS );
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
} else {
2007-09-15 22:21:13 +02:00
FormResponse :: status_message ( _t ( 'LeftAndMain.PLEASESAVE' , " Please Save Page: This page could not be upated because it hasn't been saved yet. " ), " good " );
2007-07-19 12:40:05 +02:00
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
return FormResponse :: respond ();
} else {
user_error ( " Error in ajaxupdateparent request; id= $id , parentID= $parentID " , E_USER_ERROR );
}
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
/**
* Ajax handler for updating the order of a number of tree nodes
* $_GET [ ID ] : An array of node ids in the correct order
* $_GET [ MovedNodeID ] : The node that actually got moved
*/
public function ajaxupdatesort () {
$className = $this -> stat ( 'tree_class' );
$counter = 0 ;
$js = '' ;
$_REQUEST [ 'ajax' ] = 1 ;
2009-08-10 00:29:45 +02:00
if ( ! Permission :: check ( 'SITETREE_REORGANISE' ) && ! Permission :: check ( 'ADMIN' )) {
FormResponse :: status_message ( _t ( 'LeftAndMain.CANT_REORGANISE' , " You do not have permission to rearange the site tree. Your change was not saved. " ), " bad " );
return FormResponse :: respond ();
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
if ( is_array ( $_REQUEST [ 'ID' ])) {
2007-10-02 07:10:35 +02:00
if ( $_REQUEST [ 'MovedNodeID' ] == 0 ){ //Sorting root
2008-11-23 01:31:13 +01:00
$movedNode = DataObject :: get ( $className , " \" ParentID \" =0 " );
2007-10-02 07:10:35 +02:00
} else {
$movedNode = DataObject :: get_by_id ( $className , $_REQUEST [ 'MovedNodeID' ]);
}
2007-07-19 12:40:05 +02:00
foreach ( $_REQUEST [ 'ID' ] as $id ) {
if ( $id == $movedNode -> ID ) {
$movedNode -> Sort = ++ $counter ;
$movedNode -> Status = " Saved (update) " ;
$movedNode -> write ();
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
$title = Convert :: raw2js ( $movedNode -> TreeTitle ());
2008-07-18 05:40:32 +02:00
$js .= " $ ('sitetree').setNodeTitle( $movedNode->ID , \" $title\ " ); \n " ;
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
// Nodes that weren't "actually moved" shouldn't be registered as having been edited; do a direct SQL update instead
} else if ( is_numeric ( $id )) {
++ $counter ;
2008-11-23 01:31:13 +01:00
DB :: query ( " UPDATE \" $className\ " SET \ " Sort \" = $counter WHERE \" ID \" = ' $id ' " );
2007-07-19 12:40:05 +02:00
}
}
// Virtual pages require selected to be null if the page is the same.
FormResponse :: add (
" if( $ ('sitetree').selected && $ ('sitetree').selected[0]) {
var idx = $ ( 'sitetree' ) . selected [ 0 ] . getIdx ();
if ( idx ){
$ ( 'Form_EditForm' ) . getPageFromServer ( idx );
}
} \n " . $js
);
2007-09-15 22:21:13 +02:00
FormResponse :: status_message ( _t ( 'LeftAndMain.SAVED' ), 'good' );
2007-07-19 12:40:05 +02:00
} else {
2007-09-15 22:21:13 +02:00
FormResponse :: error ( _t ( 'LeftAndMain.REQUESTERROR' , " Error in request " ));
2007-07-19 12:40:05 +02:00
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
return FormResponse :: respond ();
}
2009-08-10 00:29:45 +02:00
public function CanOrganiseSitetree () {
return ! Permission :: check ( 'SITETREE_REORGANISE' ) && ! Permission :: check ( 'ADMIN' ) ? false : true ;
}
2007-07-19 12:40:05 +02:00
/**
* Delete a number of items
*/
public function deleteitems () {
$ids = split ( ' *, *' , $_REQUEST [ 'csvIDs' ]);
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
$script = " st = \$ ('sitetree'); \n " ;
foreach ( $ids as $id ) {
if ( is_numeric ( $id )) {
2008-11-18 02:48:50 +01:00
$record = DataObject :: get_by_id ( $this -> stat ( 'tree_class' ), $id );
2008-11-03 15:56:36 +01:00
if ( $record && ! $record -> canDelete ()) return Security :: permissionFailure ( $this );
2007-07-19 12:40:05 +02:00
DataObject :: delete_by_id ( $this -> stat ( 'tree_class' ), $id );
$script .= " node = st.getTreeNodeByIdx( $id ); if(node) node.parentTreeNode.removeTreeNode(node); $ ('Form_EditForm').closeIfSetTo( $id ); \n " ;
2009-08-12 23:19:04 +02:00
2007-07-19 12:40:05 +02:00
}
}
2010-02-11 02:02:34 +01:00
2007-07-19 12:40:05 +02:00
FormResponse :: add ( $script );
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
return FormResponse :: respond ();
}
2010-02-11 02:02:34 +01:00
/**
* Returns a placeholder form , used by { @ link getEditForm ()} if no record is selected .
* Our javascript logic always requires a form to be present in the CMS interface .
*
* @ return Form
*/
function EmptyForm () {
$form = new Form (
$this ,
" EditForm " ,
new FieldSet (
new HeaderField (
'WelcomeHeader' ,
$this -> getApplicationName ()
),
new LiteralField (
'WelcomeText' ,
sprintf ( '<p id="WelcomeMessage">%s %s. %s</p>' ,
_t ( 'LeftAndMain_right.ss.WELCOMETO' , 'Welcome to' ),
$this -> getApplicationName (),
_t ( 'CHOOSEPAGE' , 'Please choose an item from the left.' )
)
)
),
new FieldSet ()
);
$form -> unsetValidator ();
return $form ;
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
public function EditForm () {
2009-05-18 02:23:52 +02:00
// Include JavaScript to ensure HtmlEditorField works.
HtmlEditorField :: include_js ();
2009-10-16 00:33:14 +02:00
if ( $this -> currentPageID () != 0 ) {
$record = $this -> currentPage ();
if ( ! $record ) return false ;
if ( $record && ! $record -> canView ()) return Security :: permissionFailure ( $this );
}
if ( $this -> hasMethod ( 'getEditForm' )) {
return $this -> getEditForm ( $this -> currentPageID ());
}
2008-11-04 14:53:11 +01:00
2009-10-16 00:33:14 +02:00
return false ;
2007-07-19 12:40:05 +02:00
}
2007-09-27 22:56:55 +02:00
public function myprofile () {
$form = $this -> Member_ProfileForm ();
return $this -> customise ( array (
'Form' => $form
)) -> renderWith ( 'BlankPage' );
}
public function Member_ProfileForm () {
return new Member_ProfileForm ( $this , 'Member_ProfileForm' , Member :: currentUser ());
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
public function printable () {
$id = $_REQUEST [ 'ID' ] ? $_REQUEST [ 'ID' ] : $this -> currentPageID ();
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
if ( $id ) $form = $this -> getEditForm ( $id );
$form -> transform ( new PrintableTransformation ());
$form -> actions = null ;
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
Requirements :: clear ();
ENHANCEMENT Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@63154 467b73ca-7a2a-4603-9d3b-597d59a354a9
2008-09-27 18:02:38 +02:00
Requirements :: css ( CMS_DIR . '/css/LeftAndMain_printable.css' );
2007-07-19 12:40:05 +02:00
return array (
" PrintForm " => $form
);
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
public function currentPageID () {
if ( isset ( $_REQUEST [ 'ID' ]) && is_numeric ( $_REQUEST [ 'ID' ])) {
return $_REQUEST [ 'ID' ];
2007-08-08 03:16:02 +02:00
} elseif ( isset ( $this -> urlParams [ 'ID' ]) && is_numeric ( $this -> urlParams [ 'ID' ])) {
2007-07-19 12:40:05 +02:00
return $this -> urlParams [ 'ID' ];
} elseif ( Session :: get ( " { $this -> class } .currentPage " )) {
return Session :: get ( " { $this -> class } .currentPage " );
} else {
return null ;
}
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
public function setCurrentPageID ( $id ) {
Session :: set ( " { $this -> class } .currentPage " , $id );
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
public function currentPage () {
2009-05-01 00:47:28 +02:00
return $this -> getRecord ( $this -> currentPageID ());
2007-07-19 12:40:05 +02:00
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
public function isCurrentPage ( DataObject $page ) {
return $page -> ID == Session :: get ( " { $this -> class } .currentPage " );
}
2009-08-12 23:19:04 +02:00
/**
* Get the staus of a certain page and version .
*
* This function is used for concurrent editing , and providing alerts
* when multiple users are editing a single page . It echoes a json
* encoded string to the UA .
*/
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
/**
* Return the CMS ' s HTML - editor toolbar
*/
public function EditorToolbar () {
2008-04-26 08:23:41 +02:00
return Object :: create ( 'HtmlEditorField_Toolbar' , $this , " EditorToolbar " );
2007-07-19 12:40:05 +02:00
}
2007-09-14 21:26:56 +02:00
2007-07-19 12:40:05 +02:00
/**
2009-02-03 03:50:25 +01:00
* Return the version number of this application .
* Uses the subversion path information in < mymodule >/ silverstripe_version
* ( automacially replaced $URL $ placeholder ) .
*
* @ return string
2007-07-19 12:40:05 +02:00
*/
public function CMSVersion () {
2010-01-28 06:09:47 +01:00
$sapphireVersionFile = file_get_contents ( BASE_PATH . '/sapphire/silverstripe_version' );
$cmsVersionFile = file_get_contents ( BASE_PATH . '/cms/silverstripe_version' );
2010-02-24 03:50:47 +01:00
$sapphireVersion = $this -> versionFromVersionFile ( $sapphireVersionFile );
$cmsVersion = $this -> versionFromVersionFile ( $cmsVersionFile );
2007-09-14 21:26:56 +02:00
2009-11-26 06:08:34 +01:00
if ( $sapphireVersion == $cmsVersion ) {
2007-07-19 12:40:05 +02:00
return $sapphireVersion ;
} else {
2009-11-26 06:08:34 +01:00
return " cms: $cmsVersion , sapphire: $sapphireVersion " ;
2007-07-19 12:40:05 +02:00
}
}
2010-02-16 04:01:30 +01:00
2010-02-24 03:50:47 +01:00
/**
* Return the version from the content of a silverstripe_version file
*/
public function versionFromVersionFile ( $fileContent ) {
if ( preg_match ( '/\/trunk\/silverstripe_version/' , $fileContent )) {
return " trunk " ;
} else {
preg_match ( " / \ /(?:branches|tags \ /rc|tags \ /beta|tags \ /alpha|tags) \ /([A-Za-z0-9._-]+) \ /silverstripe_version/ " , $fileContent , $matches );
return ( $matches ) ? $matches [ 1 ] : null ;
}
}
2010-02-16 04:01:30 +01:00
/**
* @ return array
*/
function SwitchView () {
if ( $page = $this -> currentPage ()) {
$nav = SilverStripeNavigator :: get_for_record ( $page );
return $nav [ 'items' ];
}
}
2007-07-19 12:40:05 +02:00
/**
2008-04-26 08:42:10 +02:00
* The application name . Customisable by calling
* LeftAndMain :: setApplicationName () - the first parameter .
*
* @ var String
*/
static $application_name = 'SilverStripe CMS' ;
/**
* The application logo text . Customisable by calling
* LeftAndMain :: setApplicationName () - the second parameter .
*
* @ var String
*/
static $application_logo_text = 'SilverStripe' ;
/**
* Set the application name , and the logo text .
*
* @ param String $name The application name
* @ param String $logoText The logo text
2007-09-14 21:26:56 +02:00
*/
2009-03-10 22:59:19 +01:00
static $application_link = " http://www.silverstripe.org/ " ;
2008-04-22 05:19:53 +02:00
static function setApplicationName ( $name , $logoText = null , $link = null ) {
2007-07-19 12:40:05 +02:00
self :: $application_name = $name ;
self :: $application_logo_text = $logoText ? $logoText : $name ;
2008-04-22 05:19:53 +02:00
if ( $link ) self :: $application_link = $link ;
2007-07-19 12:40:05 +02:00
}
2008-04-26 08:42:10 +02:00
/**
* Get the application name .
* @ return String
*/
function getApplicationName () {
2007-07-19 12:40:05 +02:00
return self :: $application_name ;
}
2008-04-26 08:42:10 +02:00
/**
* Get the application logo text .
* @ return String
*/
function getApplicationLogoText () {
2007-07-19 12:40:05 +02:00
return self :: $application_logo_text ;
}
2008-04-22 05:19:53 +02:00
function ApplicationLink () {
return self :: $application_link ;
}
2007-07-19 12:40:05 +02:00
2008-09-23 04:24:23 +02:00
/**
* Return the title of the current section , as shown on the main menu
*/
function SectionTitle () {
// Get menu - use obj() to cache it in the same place as the template engine
$menu = $this -> obj ( 'MainMenu' );
foreach ( $menu as $menuItem ) {
if ( $menuItem -> LinkingMode == 'current' ) return $menuItem -> Title ;
}
}
2008-04-26 08:42:10 +02:00
/**
* The application logo path . Customisable by calling
* LeftAndMain :: setLogo () - the first parameter .
*
* @ var unknown_type
*/
static $application_logo = 'cms/images/mainmenu/logo.gif' ;
2007-09-14 21:26:56 +02:00
2008-04-26 08:42:10 +02:00
/**
* The application logo style . Customisable by calling
* LeftAndMain :: setLogo () - the second parameter .
*
* @ var String
*/
static $application_logo_style = '' ;
/**
* Set the CMS application logo .
*
* @ param String $logo Relative path to the logo
* @ param String $logoStyle Custom CSS styles for the logo
* e . g . " border: 1px solid red; padding: 5px; "
*/
2007-07-19 12:40:05 +02:00
static function setLogo ( $logo , $logoStyle ) {
self :: $application_logo = $logo ;
self :: $application_logo_style = $logoStyle ;
2008-04-26 08:42:10 +02:00
self :: $application_logo_text = '' ;
2007-07-19 12:40:05 +02:00
}
2008-04-26 08:39:00 +02:00
protected static $loading_image = 'cms/images/loading.gif' ;
/**
* Set the image shown when the CMS is loading .
*/
static function set_loading_image ( $loadingImage ) {
self :: $loading_image = $loadingImage ;
}
function LoadingImage () {
return self :: $loading_image ;
}
2007-07-19 12:40:05 +02:00
function LogoStyle () {
2008-02-25 03:10:37 +01:00
return " background: url( " . self :: $application_logo . " ) no-repeat; " . self :: $application_logo_style ;
2007-07-19 12:40:05 +02:00
}
/**
* Return the base directory of the tiny_mce codebase
*/
function MceRoot () {
return MCE_ROOT ;
}
2007-08-27 07:06:57 +02:00
/**
* Use this as an action handler for custom CMS buttons .
*/
function callPageMethod ( $data , $form ) {
$methodName = $form -> buttonClicked () -> extraData ();
2009-05-18 01:19:51 +02:00
$record = $this -> currentPage ();
if ( ! $record ) return false ;
return $record -> $methodName ( $data , $form );
2007-08-27 07:06:57 +02:00
}
2008-04-05 03:40:36 +02:00
2008-07-17 23:08:35 +02:00
/**
* Register the given javascript file as required in the CMS .
ENHANCEMENT Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@63154 467b73ca-7a2a-4603-9d3b-597d59a354a9
2008-09-27 18:02:38 +02:00
* Filenames should be relative to the base , eg , SAPPHIRE_DIR . '/javascript/loader.js'
2008-07-17 23:08:35 +02:00
*/
public static function require_javascript ( $file ) {
self :: $extra_requirements [ 'javascript' ][] = array ( $file );
}
/**
* Register the given stylesheet file as required .
*
ENHANCEMENT Introduced constants for system paths like /sapphire in preparation for a more flexible directory reorganisation. Instead of hardcoding your path, please use the following constants: BASE_PATH, BASE_URL, SAPPHIRE_DIR, SAPPHIRE_PATH, CMS_DIR, CMS_PATH, THIRDPARTY_DIR, THIRDPARTY_PATH, ASSETS_DIR, ASSETS_PATH, THEMES_DIR, THEMES_PATH
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/cms/trunk@63154 467b73ca-7a2a-4603-9d3b-597d59a354a9
2008-09-27 18:02:38 +02:00
* @ param $file String Filenames should be relative to the base , eg , THIRDPARTY_DIR . '/tree/tree.css'
2008-07-17 23:08:35 +02:00
* @ param $media String Comma - separated list of media - types ( e . g . " screen,projector " )
* @ see http :// www . w3 . org / TR / REC - CSS2 / media . html
*/
public static function require_css ( $file , $media = null ) {
self :: $extra_requirements [ 'css' ][] = array ( $file , $media );
}
/**
* Register the given " themeable stylesheet " as required .
* Themeable stylesheets have globally unique names , just like templates and PHP files .
* Because of this , they can be replaced by similarly named CSS files in the theme directory .
*
* @ param $name String The identifier of the file . For example , css / MyFile . css would have the identifier " MyFile "
* @ param $media String Comma - separated list of media - types ( e . g . " screen,projector " )
*/
static function require_themed_css ( $name , $media = null ) {
self :: $extra_requirements [ 'themedcss' ][] = array ( $name , $media );
}
2007-07-19 12:40:05 +02:00
}
2009-03-10 22:59:19 +01:00
?>