diff --git a/code/controllers/CMSMain.php b/code/controllers/CMSMain.php index 9cfdc8cf..cb5fb7cf 100644 --- a/code/controllers/CMSMain.php +++ b/code/controllers/CMSMain.php @@ -137,13 +137,23 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr * Return the entire site tree as a nested set of ULs */ public function SiteTreeAsUL() { - $this->generateTreeStylingJS(); + $html = ''; + + // Include custom CSS for tree icons inline, as the tree might be loaded + // via Ajax, in which case we can't inject it into the HTML header easily through the HTTP response. + $css = $this->generateTreeStylingCSS(); + if($this->isAjax()) { + $html .= "\n"; + } else { + Requirements::customCSS($css); + } // Pre-cache sitetree version numbers for querying efficiency Versioned::prepopulate_versionnumber_cache("SiteTree", "Stage"); Versioned::prepopulate_versionnumber_cache("SiteTree", "Live"); + $html .= $this->getSiteTreeFor($this->stat('tree_class')); - return $this->getSiteTreeFor($this->stat('tree_class')); + return $html; } function SearchForm() { @@ -257,43 +267,52 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr return Convert::raw2xml(Convert::raw2json($def)); } - - public function generateTreeStylingJS() { - $classes = ClassInfo::subclassesFor($this->stat('tree_class')); + + /** + * Include CSS for page icons. We're not using the JSTree 'types' option + * because it causes too much performance overhead just to add some icons. + * + * @return String CSS + */ + function generateTreeStylingCSS() { + $css = ''; + + $classes = ClassInfo::subclassesFor('SiteTree'); foreach($classes as $class) { - $obj = singleton($class); - if($obj instanceof HiddenClass) continue; - if($icon = $obj->stat('icon')) $iconInfo[$class] = $icon; - } - $iconInfo['BrokenLink'] = 'cms/images/treeicons/brokenlink'; + $obj = singleton($class); + $iconSpec = $obj->stat('icon'); + if(!$iconSpec) continue; - $js = "var _TREE_ICONS = [];\n"; + // Legacy support: We no longer need separate icon definitions for folders etc. + $iconFile = (is_array($iconSpec)) ? $iconSpec[0] : $iconSpec; + // Legacy support: Add file extension if none exists + if(!pathinfo($iconFile, PATHINFO_EXTENSION)) $iconFile .= '-file.gif'; - foreach($iconInfo as $class => $icon) { - // SiteTree::$icon can be set to array($icon, $option) - // $option can be "file" or "folder" to force the icon to always be the file or the folder form - $option = null; - if(is_array($icon)) list($icon, $option) = $icon; + $iconPathInfo = pathinfo($iconFile); + + // Base filename + $baseFilename = $iconPathInfo['dirname'] . '/' . $iconPathInfo['filename']; + $fileExtension = $iconPathInfo['extension']; - $fileImage = ($option == "folder") ? $icon . '-openfolder.gif' : $icon . '-file.gif'; - $openFolderImage = $icon . '-openfolder.gif'; - if(!Director::fileExists($openFolderImage) || $option == "file") $openFolderImage = $fileImage; - $closedFolderImage = $icon . '-closedfolder.gif'; - if(!Director::fileExists($closedFolderImage) || $option == "file") $closedFolderImage = $fileImage; + if(Director::fileExists($iconFile)) { + $css .= sprintf( + "li.class-%s > a .jstree-pageicon { background: transparent url('%s') 0 0 no-repeat; }\n", + $class, $iconFile + ); + } else { + // Support for more sophisticated rules, e.g. sprited icons + $css .= sprintf( + "li.class-%s > a .jstree-pageicon { %s }\n", + $class, $iconFile + ); + } + - $js .= << 0 ); - static $icon = array("sapphire/javascript/tree/images/page", "file"); - static $description = 'Custom content for different error cases (e.g. "Page not found")'; protected static $static_filepath = ASSETS_PATH; diff --git a/code/model/RedirectorPage.php b/code/model/RedirectorPage.php index 0cdfb3b3..1fe2082e 100644 --- a/code/model/RedirectorPage.php +++ b/code/model/RedirectorPage.php @@ -7,7 +7,7 @@ */ class RedirectorPage extends Page { - static $icon = array("cms/images/treeicons/page-shortcut","file"); + static $icon = "cms/images/treeicons/page-shortcut-file.gif"; static $description = 'Redirects to a different internal page'; diff --git a/code/model/SiteTree.php b/code/model/SiteTree.php index 81d983ba..4e787023 100644 --- a/code/model/SiteTree.php +++ b/code/model/SiteTree.php @@ -128,21 +128,20 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid */ static $can_create = true; + /** + * @see CMSMain::generateTreeStylingCSS() + */ + static $page_states = array('readonly'); /** - * Icon to use in the CMS - * - * This should be the base filename. The suffixes -file.gif, - * -openfolder.gif and -closedfolder.gif will be appended to the base name - * that you provide there. - * If you prefer, you can pass an array: - * array("sapphire\javascript\tree\images\page", $option). - * $option can be either "file" or "folder" to force the icon to always - * be a file or folder, regardless of whether the page has children or not - * - * @var string|array + * Icon to use in the CMS page tree. This should be the full filename, relative to the webroot. + * Also supports custom CSS rule contents (applied to the correct selector for the tree UI implementation). + * + * @see CMSMain::generateTreeStylingCSS() + * + * @var string */ - static $icon = array("sapphire/javascript/tree/images/page", "file"); + static $icon = null; /** * @var String Description of the class functionality, typically shown to a user @@ -150,7 +149,6 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid */ static $description = 'Generic content page'; - static $extensions = array( "Hierarchy", "Versioned('Stage', 'Live')", diff --git a/code/model/VirtualPage.php b/code/model/VirtualPage.php index 32bf0d71..3ebc77e8 100644 --- a/code/model/VirtualPage.php +++ b/code/model/VirtualPage.php @@ -7,7 +7,7 @@ */ class VirtualPage extends Page { - static $icon = array("cms/images/treeicons/page-shortcut-gold","file"); + static $icon = "cms/images/treeicons/page-shortcut-gold-file.gif"; static $description = 'Displays the content of another page';