From 37843f447ef4b558170a0ba851ae349a5c413028 Mon Sep 17 00:00:00 2001 From: Naomi Guyer Date: Thu, 22 Aug 2013 13:02:46 +1200 Subject: [PATCH] API: Subsite support for menu of cms (hide admins that don't declare support) (fixes #101 and #89 ) * Hide admins without subsite support from subsites menu * Add subsite support to default site areas * Enable reloading of subsites switcher dropdown when navigating the site, and when editing subsite areas API Fix parallel pjax menu fetching for subsites. - thanks Mateusz! Delint LeftAndMain_Subsites.js --- _config.php | 9 ++ code/SubsiteAdmin.php | 14 +++ code/extensions/FileSubsites.php | 12 ++- code/extensions/LeftAndMainSubsites.php | 129 ++++++++++++----------- code/extensions/SubsiteMenuExtension.php | 19 ++++ code/model/Subsite.php | 4 +- css/LeftAndMain_Subsites.css | 8 ++ javascript/LeftAndMain_Subsites.js | 96 +++++++++++++++-- templates/Includes/SubsiteList.ss | 9 ++ templates/LeftAndMain_Menu.ss | 23 ++-- 10 files changed, 237 insertions(+), 86 deletions(-) create mode 100644 code/extensions/SubsiteMenuExtension.php create mode 100644 templates/Includes/SubsiteList.ss diff --git a/_config.php b/_config.php index 817e1b8..0cbece5 100644 --- a/_config.php +++ b/_config.php @@ -17,3 +17,12 @@ ErrorPage::add_extension('ErrorPageSubsite'); SiteConfig::add_extension('SiteConfigSubsites'); SS_Report::add_excluded_reports('SubsiteReportWrapper'); + +//Display in cms menu +AssetAdmin::add_extension('SubsiteMenuExtension'); +SecurityAdmin::add_extension('SubsiteMenuExtension'); +CMSMain::add_extension('SubsiteMenuExtension'); +CMSPagesController::add_extension('SubsiteMenuExtension'); +SubsiteAdmin::add_extension('SubsiteMenuExtension'); +CMSSettingsController::add_extension('SubsiteMenuExtension'); + diff --git a/code/SubsiteAdmin.php b/code/SubsiteAdmin.php index 11a9465..7ed122c 100644 --- a/code/SubsiteAdmin.php +++ b/code/SubsiteAdmin.php @@ -29,4 +29,18 @@ class SubsiteAdmin extends ModelAdmin { return $form; } + + public function getResponseNegotiator() { + $negotiator = parent::getResponseNegotiator(); + $self = $this; + // Register a new callback + $negotiator->setCallback('SubsiteList', function() use(&$self) { + return $self->SubsiteList(); + }); + return $negotiator; + } + + public function SubsiteList() { + return $this->renderWith('SubsiteList'); + } } diff --git a/code/extensions/FileSubsites.php b/code/extensions/FileSubsites.php index cdc480a..85e0d26 100644 --- a/code/extensions/FileSubsites.php +++ b/code/extensions/FileSubsites.php @@ -35,7 +35,17 @@ class FileSubsites extends DataExtension { $values[$site->ID] = $site->Title; } ksort($values); - if($sites)$fields->push(new DropdownField('SubsiteID', 'Subsite', $values)); + if($sites){ + //Dropdown needed to move folders between subsites + $fields->push($dropdown = new DropdownField('SubsiteID', 'Subsite', $values)); + $fields->push(new LiteralField( + 'Message', + '

'. + _t('ASSETADMIN.SUBSITENOTICE', 'Folders and files created in the main site are accessible by all subsites.') + .'

' + )); + $dropdown->addExtraClass('subsites-move-dropdown'); + } } } diff --git a/code/extensions/LeftAndMainSubsites.php b/code/extensions/LeftAndMainSubsites.php index 5950914..5177e53 100644 --- a/code/extensions/LeftAndMainSubsites.php +++ b/code/extensions/LeftAndMainSubsites.php @@ -51,6 +51,9 @@ class LeftAndMainSubsites extends Extension { $fields->push(new HiddenField('SubsiteID', 'SubsiteID', Subsite::currentSubsiteID())); } + /* + * Returns a list of the subsites accessible to the current user + */ public function Subsites() { // figure out what permission the controller needs // Subsite::accessible_sites() expects something, so if there's no permission @@ -64,76 +67,74 @@ class LeftAndMainSubsites extends Extension { } } - switch($this->owner->class) { - case "AssetAdmin": - $subsites = Subsite::accessible_sites($permission, true, "Shared files & images"); - break; - - case "SecurityAdmin": - $subsites = Subsite::accessible_sites($permission, true, "Groups accessing all sites"); - if($subsites->find('ID',0)) { - $subsites->push(new ArrayData(array('Title' => 'All groups', 'ID' => -1))); - } - break; - - case "CMSMain": - case "CMSPagesController": - // If there's a default site then main site has no meaning - $showMainSite = !DataObject::get_one('Subsite',"\"DefaultSite\"=1"); - $subsites = Subsite::accessible_sites($permission, $showMainSite); - break; - - case "SubsiteAdmin": - $subsites = Subsite::accessible_sites('ADMIN', true); - break; - - default: - $subsites = Subsite::accessible_sites($permission); - break; - } - - return $subsites; + return Subsite::accessible_sites($permission); } - - public function SubsiteList() { + + /* + * Generates a list of subsites with the data needed to + * produce a dropdown site switcher + * @return ArrayList + */ + + public function ListSubsites(){ $list = $this->Subsites(); $currentSubsiteID = Subsite::currentSubsiteID(); - if($list->Count() > 1) { - $output = ''; - - Requirements::javascript('subsites/javascript/LeftAndMain_Subsites.js'); - return $output; - } elseif($list->Count() == 1) { - if($list->First()->DefaultSite==false) { - $output = ''; - - Requirements::javascript('subsites/javascript/LeftAndMain_Subsites.js'); - return $output; - } else { - return ''.$list->First()->Title.''; - } + if($list == null || $list->Count() == 1 && $list->First()->DefaultSite == true){ + return false; } - } + + Requirements::javascript('subsites/javascript/LeftAndMain_Subsites.js'); + + $output = new ArrayList(); + + foreach($list as $subsite) { + $CurrentState = $subsite->ID == $currentSubsiteID ? 'selected' : ''; + $output->push(new ArrayData(array( + 'CurrentState' => $CurrentState, + 'ID' => $subsite->ID, + 'Title' => Convert::raw2xml($subsite->Title) + ))); + } + + return $output; + } + + /* + * Returns a subset of the main menu, filtered by admins that have + * a subsiteCMSShowInMenu method returning true + * + * @return ArrayList + */ + public function SubsiteMainMenu(){ + if(Subsite::currentSubsiteID() == 0){ + return $this->owner->MainMenu(); + } + // loop main menu items, add all items that have subsite support + $mainMenu = $this->owner->MainMenu(); + $subsitesMenu = new ArrayList(); + + foreach($mainMenu as $menuItem){ + + $controllerName = $menuItem->MenuItem->controller; + + if(class_exists($controllerName)){ + $controller = singleton($controllerName); + + if($controller->hasMethod('subsiteCMSShowInMenu') && $controller->subsiteCMSShowInMenu()){ + $subsitesMenu->push($menuItem); + } + } + + if($menuItem->Code == 'Help'){ + $subsitesMenu->push($menuItem); + } + + } + return $subsitesMenu; + } + public function CanAddSubsites() { return Permission::check("ADMIN", "any", null, "all"); } diff --git a/code/extensions/SubsiteMenuExtension.php b/code/extensions/SubsiteMenuExtension.php new file mode 100644 index 0000000..aab9af2 --- /dev/null +++ b/code/extensions/SubsiteMenuExtension.php @@ -0,0 +1,19 @@ +getClassName() . ' configuration', 2), new TextField('Title', 'Name of subsite:', $this->Title), @@ -252,6 +252,8 @@ class Subsite extends DataObject implements PermissionProvider { new HiddenField('IsSubsite', '', 1) ); + $subsiteTabs->addExtraClass('subsite-model'); + $this->extend('updateCMSFields', $fields); return $fields; } diff --git a/css/LeftAndMain_Subsites.css b/css/LeftAndMain_Subsites.css index a986ff7..1fa6a38 100644 --- a/css/LeftAndMain_Subsites.css +++ b/css/LeftAndMain_Subsites.css @@ -81,3 +81,11 @@ body.SubsiteAdmin .right form #URL .fieldgroup * { .cms-add-form #PageType li .class-SubsitesVirtualPage, .class-SubsitesVirtualPage a .jstree-pageicon { background-position: 0 -32px !important; } + +.subsites-move-dropdown{ + display:none; +} + +#Root_DetailsView .subsites-move-dropdown{ + display:block; +} diff --git a/javascript/LeftAndMain_Subsites.js b/javascript/LeftAndMain_Subsites.js index d52e9af..5966440 100644 --- a/javascript/LeftAndMain_Subsites.js +++ b/javascript/LeftAndMain_Subsites.js @@ -1,7 +1,89 @@ +/*jslint browser: true, nomen: true*/ +/*global $, window, jQuery*/ + (function($) { + 'use strict'; $.entwine('ss', function($) { - $('#SubsitesSelect').live('change', function() { - window.location.search=$.query.set('SubsiteID', $(this).val()); + + $('#SubsitesSelect').entwine({ + onadd:function(){ + this.on('change', function(){ + window.location.search=$.query.set('SubsiteID', $(this).val()); + }); + } + }); + + $('.cms-container').entwine({ + + SubsiteCurrentXHR: null, + + /** + * LeftAndMain does not give us possibility to parallel-fetch a PJAX fragment. + * We provide our own fetcher that bypasses the history - that's because we + * don't want to load a panel, but rather just a subsite dropdown. + */ + subsiteFetchPjaxFragment: function(url, pjaxFragment) { + + // Make sure only one subsite XHR request is ongoing. + if(this.getSubsiteCurrentXHR()){ + this.getSubsiteCurrentXHR().abort(); + } + + var self = this, + xhr, + headers = {}, + baseUrl = $('base').attr('href'); + + url = $.path.isAbsoluteUrl(url) ? url : $.path.makeUrlAbsolute(url, baseUrl); + headers['X-Pjax'] = pjaxFragment; + + xhr = $.ajax({ + headers: headers, + url: url, + complete: function() { + self.setSubsiteCurrentXHR(null); + }, + success: function(data, status, xhr) { + self.handleAjaxResponse(data, status, xhr, null); + } + }); + + this.setSubsiteCurrentXHR(xhr); + } + + }); + + /* + * Reload subsites dropdown when links are processed + */ + $('.cms-container .cms-menu-list li a').entwine({ + onclick: function(e) { + $('.cms-container').subsiteFetchPjaxFragment('admin/subsites/', 'SubsiteList'); + this._super(e); + } + }); + + /* + * Reload subsites dropdown when the admin area reloads (for deleting sites) + */ + $('.cms-container .SubsiteAdmin .cms-edit-form fieldset.ss-gridfield').entwine({ + onreload: function(e) { + $('.cms-container').subsiteFetchPjaxFragment('admin/subsites/', 'SubsiteList'); + this._super(e); + } + }); + + + + + /* + * Reload subsites dropdown when subsites are added or names are modified + */ + $('.cms-container .cms-content-fields .subsite-model').entwine({ + onadd: function(e) { + $('.cms-container').subsiteFetchPjaxFragment('admin/subsites/', 'SubsiteList'); + this._super(e); + } }); // Subsite tab of Group editor @@ -72,7 +154,9 @@ onafterIframeAdjustedForPreview: function(event, doc) { var subsiteId = $(doc).find('meta[name=x-subsite-id]').attr('content'); - if (!subsiteId) return; + if (!subsiteId) { + return; + } // Inject the SubsiteID into internal links. $(doc).find('a').each(function() { @@ -95,11 +179,7 @@ } }); - } - }); - }); - -})(jQuery); +}(jQuery)); diff --git a/templates/Includes/SubsiteList.ss b/templates/Includes/SubsiteList.ss new file mode 100644 index 0000000..3b3960f --- /dev/null +++ b/templates/Includes/SubsiteList.ss @@ -0,0 +1,9 @@ +
+ +
diff --git a/templates/LeftAndMain_Menu.ss b/templates/LeftAndMain_Menu.ss index 2d34b0b..f531f37 100644 --- a/templates/LeftAndMain_Menu.ss +++ b/templates/LeftAndMain_Menu.ss @@ -2,33 +2,32 @@
- -
- $SubsiteList -
+ <% if $ListSubsites %> + <% include SubsiteList %> + <% end_if %>