Permalink
Browse files

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
  • Loading branch information...
1 parent 2d41dc6 commit 37843f447ef4b558170a0ba851ae349a5c413028 @adrexia adrexia committed Aug 22, 2013
View
9 _config.php
@@ -17,3 +17,12 @@
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');
+
View
14 code/SubsiteAdmin.php
@@ -29,4 +29,18 @@ public function getEditForm($id = null, $fields = null) {
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');
+ }
}
View
12 code/extensions/FileSubsites.php
@@ -35,7 +35,17 @@ function updateCMSFields(FieldList $fields) {
$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',
+ '<p class="message notice">'.
+ _t('ASSETADMIN.SUBSITENOTICE', 'Folders and files created in the main site are accessible by all subsites.')
+ .'</p>'
+ ));
+ $dropdown->addExtraClass('subsites-move-dropdown');
+ }
}
}
View
121 code/extensions/LeftAndMainSubsites.php
@@ -51,6 +51,9 @@ function updatePageOptions(&$fields) {
$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 @@ public function Subsites() {
}
}
- 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;
+ return Subsite::accessible_sites($permission);
+ }
- default:
- $subsites = Subsite::accessible_sites($permission);
- break;
- }
+ /*
+ * Generates a list of subsites with the data needed to
+ * produce a dropdown site switcher
+ * @return ArrayList
+ */
- return $subsites;
- }
-
- public function SubsiteList() {
+ public function ListSubsites(){
$list = $this->Subsites();
$currentSubsiteID = Subsite::currentSubsiteID();
- if($list->Count() > 1) {
- $output = '<div class="field dropdown">';
- $output .= '<select id="SubsitesSelect">';
-
- foreach($list as $subsite) {
- $selected = $subsite->ID == $currentSubsiteID ? ' selected="selected"' : '';
-
- $output .= "\n<option value=\"{$subsite->ID}\"$selected>". Convert::raw2xml($subsite->Title) . "</option>";
- }
-
- $output .= '</select></div>';
-
- Requirements::javascript('subsites/javascript/LeftAndMain_Subsites.js');
- return $output;
- } elseif($list->Count() == 1) {
- if($list->First()->DefaultSite==false) {
- $output = '<div class="field dropdown">';
- $output .= '<select id="SubsitesSelect">';
- $output .= "\n<option value=\"0\">". _t('LeftAndMainSubsites.DEFAULT_SITE', 'Default site') . "</option>";
- foreach($list as $subsite) {
- $selected = $subsite->ID == $currentSubsiteID ? ' selected="selected"' : '';
-
- $output .= "\n<option value=\"{$subsite->ID}\"$selected>". Convert::raw2xml($subsite->Title) . "</option>";
- }
+ if($list == null || $list->Count() == 1 && $list->First()->DefaultSite == true){
+ return false;
+ }
- $output .= '</select></div>';
+ Requirements::javascript('subsites/javascript/LeftAndMain_Subsites.js');
- Requirements::javascript('subsites/javascript/LeftAndMain_Subsites.js');
- return $output;
- } else {
- return '<span>'.$list->First()->Title.'</span>';
+ $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");
}
View
19 code/extensions/SubsiteMenuExtension.php
@@ -0,0 +1,19 @@
+<?php
+
+/*
+ * Simple extension to show admins in the menu of subsites.
+ * If an admin area should be available to a subsite, you can attach
+ * this class to your admin in config. eg:
+ *
+ * MyAdmin::add_extension('SubsiteMenuExtension');
+ *
+ * Or you can include the subsiteCMSShowInMenu function in your admin class and have it return true
+ */
+
+class SubsiteMenuExtension extends Extension{
+
+ public function subsiteCMSShowInMenu(){
+ return true;
+ }
+
+}
View
4 code/model/Subsite.php
@@ -219,7 +219,7 @@ function getCMSFields() {
asort($pageTypeMap);
$fields = new FieldList(
- new TabSet('Root',
+ $subsiteTabs = new TabSet('Root',
new Tab('Configuration',
new HeaderField($this->getClassName() . ' configuration', 2),
new TextField('Title', 'Name of subsite:', $this->Title),
@@ -252,6 +252,8 @@ function getCMSFields() {
new HiddenField('IsSubsite', '', 1)
);
+ $subsiteTabs->addExtraClass('subsite-model');
+
$this->extend('updateCMSFields', $fields);
return $fields;
}
View
8 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;
+}
View
96 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));
View
9 templates/Includes/SubsiteList.ss
@@ -0,0 +1,9 @@
+<div class="cms-subsites" data-pjax-fragment="SubsiteList">
+ <div class="field dropdown">
+ <select id="SubsitesSelect">
+ <% loop $ListSubsites %>
+ <option value="$ID" $CurrentState>$Title</option>
+ <% end_loop %>
+ </select>
+ </div>
+</div>
View
23 templates/LeftAndMain_Menu.ss
@@ -2,33 +2,32 @@
<div class="cms-logo-header north">
<div class="cms-logo">
<a href="$ApplicationLink" target="_blank" title="$ApplicationName (Version - $CMSVersion)">
- $ApplicationName <% if CMSVersion %><abbr class="version">$CMSVersion</abbr><% end_if %>
+ $ApplicationName <% if $CMSVersion %><abbr class="version">$CMSVersion</abbr><% end_if %>
</a>
- <span><% if SiteConfig %>$SiteConfig.Title<% else %>$ApplicationName<% end_if %></span>
+ <span><% if $SiteConfig %>$SiteConfig.Title<% else %>$ApplicationName<% end_if %></span>
</div>
<div class="cms-login-status">
<a href="Security/logout" class="logout-link" title="<% _t('LeftAndMain_Menu.ss.LOGOUT','Log out') %>"><% _t('LeftAndMain_Menu.ss.LOGOUT','Log out') %></a>
- <% with CurrentMember %>
+ <% with $CurrentMember %>
<span>
<% _t('LeftAndMain_Menu.ss.Hello','Hi') %>
- <a href="{$AbsoluteBaseURL}admin/myprofile" class="profile-link ss-ui-dialog-link" data-popupclass="edit-profile-popup">
- <% if FirstName && Surname %>$FirstName $Surname<% else_if FirstName %>$FirstName<% else %>$Email<% end_if %>
+ <a href="{$AbsoluteBaseURL}admin/myprofile" class="profile-link">
+ <% if $FirstName && $Surname %>$FirstName $Surname<% else_if $FirstName %>$FirstName<% else %>$Email<% end_if %>
</a>
</span>
<% end_with %>
</div>
-
- <div class="cms-subsites">
- $SubsiteList
- </div>
+ <% if $ListSubsites %>
+ <% include SubsiteList %>
+ <% end_if %>
</div>
<div class="cms-panel-content center">
<ul class="cms-menu-list">
- <% loop MainMenu %>
- <li class="$LinkingMode $FirstLast <% if LinkingMode == 'link' %><% else %>opened<% end_if %>" id="Menu-$Code" title="$Title.ATT">
- <a href="$Link" <% if Code == 'Help' %>target="_blank"<% end_if%>>
+ <% loop $SubsiteMainMenu %>
+ <li class="$LinkingMode $FirstLast <% if $LinkingMode == 'link' %><% else %>opened<% end_if %>" id="Menu-$Code" title="$Title.ATT">
+ <a href="$Link" <% if $Code == 'Help' %>target="_blank"<% end_if %>>
<span class="icon icon-16 icon-{$Code.LowerCase}">&nbsp;</span>
<span class="text">$Title</span>
</a>

3 comments on commit 37843f4

@spronkey

This patch does more than it claims. If you've got custom ModelAdmins, you now need to explicitly enable their menu items in subsites views by adding an extension e.g. YourModelAdmin::add_extension('SubsiteMenuExtension') in your _config.php.

By updating subsites codebase to this patch, the uninformed will see their subsite menu entries disappear in all but the main site, and wonder what on earth has happened.

Needs more documentation or needs a changelog feature, because this is one of those hidden bugs that takes a long time to find if you don't know it's there.

@adrexia

This was intentional, but you are right. Currently no changelogs for subsites though. Feel free to add it to the docs.

There are two ways to enable menu's for subsite supported ModelAdmins, adding an extension or adding the method straight into your ModelAdmin. i.e.

 public function subsiteCMSShowInMenu(){
     return true;
 }

It was decided to hide admins from MenuItems by default in subsites as it has proven confusing to users. There is a common assumption that everything edited whilst in a subsite is unique to that subsite. This assumption is a fair one to make, but out of the box most ModelAdmins are global. Since ModelAdmins need to be made aware of subsites to support it at the subsite level, it also made sense that the menu should have to be explicitly told that the admin was subsites aware.

@adrexia

Added some docs:

#108

Please sign in to comment.