Merge remote-tracking branch 'origin/3.1'

This commit is contained in:
Ingo Schommer 2013-08-22 13:56:28 +02:00
commit c62f992dc3
7 changed files with 124 additions and 70 deletions

View File

@ -41,7 +41,8 @@ class CMSSettingsController extends LeftAndMain {
$this, 'EditForm', $fields, $actions
)->setHTMLID('Form_EditForm');
$form->setResponseNegotiator($this->getResponseNegotiator());
$form->addExtraClass('cms-add-form cms-content center cms-edit-form');
$form->addExtraClass('root-form');
$form->addExtraClass('cms-edit-form cms-panel-padded center');
// don't add data-pjax-fragment=CurrentForm, its added in the content template instead
if($form->Fields()->hasTabset()) $form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet');

View File

@ -103,13 +103,28 @@ class ContentController extends Controller {
// Check page permissions
if($this->dataRecord && $this->URLSegment != 'Security' && !$this->dataRecord->canView()) {
$permissionMessage = null;
return Security::permissionFailure($this);
}
// Check if we could view the live version, offer redirect if so
if($this->canViewStage('Live')) {
// Draft/Archive security check - only CMS users should be able to look at stage/archived content
if(
$this->URLSegment != 'Security'
&& !Session::get('unsecuredDraftSite')
&& (
Versioned::current_archived_date()
|| (Versioned::current_stage() && Versioned::current_stage() != 'Live')
)
) {
if(!$this->dataRecord->canViewStage(Versioned::current_archived_date() ? 'Stage' : Versioned::current_stage())) {
$link = $this->Link();
$message = _t(
"ContentController.DRAFT_SITE_ACCESS_RESTRICTION",
'You must log in with your CMS password in order to view the draft or archived content. ' .
'<a href="%s">Click here to go back to the published site.</a>'
);
Session::clear('currentStage');
Session::clear('archiveDate');
$permissionMessage = sprintf(
_t(
"ContentController.DRAFT_SITE_ACCESS_RESTRICTION",
@ -118,9 +133,10 @@ class ContentController extends Controller {
),
Controller::join_links($this->Link(), "?stage=Live")
);
return Security::permissionFailure($this, $permissionMessage);
}
return Security::permissionFailure($this, $permissionMessage);
}
// Use theme from the site config
@ -215,7 +231,7 @@ class ContentController extends Controller {
$response = $this->request->isMedia() ? null : ErrorPage::response_for($code);
// Failover to $message if the HTML response is unavailable / inappropriate
parent::httpError($code, $response ? $response : $message);
}
}
/**
* Get the project name

View File

@ -218,7 +218,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* Determines if the system should avoid orphaned pages
* by deleting all children when the their parent is deleted (TRUE),
* or rather preserve this data even if its not reachable through any navigation path (FALSE).
*
*
* @deprecated 3.2 Use the "SiteTree.enforce_strict_hierarchy" config setting instead
* @param boolean
*/
@ -409,7 +409,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
) {
return; // There were no suitable matches at all.
}
$link = Convert::raw2att($page->Link());
if($content) {
@ -445,7 +445,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return Director::absoluteURL($this->Link($action));
}
}
/**
* Base link used for previewing. Defaults to absolute URL,
* in order to account for domain changes, e.g. on multi site setups.
@ -841,8 +841,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
}
if(!$fromLive
&& !Session::get('unsecuredDraftSite')
&& !Permission::checkMember($member, array('CMS_ACCESS_CMSMain', 'VIEW_DRAFT_CONTENT'))) {
&& !Session::get('unsecuredDraftSite')
&& !Permission::checkMember($member, array('CMS_ACCESS_CMSMain', 'VIEW_DRAFT_CONTENT'))) {
// If we weren't definitely loaded from live, and we can't view non-live content, we need to
// check to make sure this version is the live version and so can be viewed
if (Versioned::get_versionnumber_by_stage($this->class, 'Live', $this->ID) != $this->Version) return false;
@ -876,11 +876,11 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
return false;
}
/**
* Determines canView permissions for the latest version of this Page on a specific stage (see {@link Versioned}).
* Usually the stage is read from {@link Versioned::current_stage()}.
*
*
* @todo Implement in CMS UI.
*
* @param String $stage
@ -892,7 +892,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
Versioned::reading_stage($stage);
$versionFromStage = DataObject::get($this->class)->byID($this->ID);
Versioned::set_reading_mode($oldMode);
return $versionFromStage ? $versionFromStage->canView($member) : false;
}
@ -1335,7 +1335,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
if($this->ExtraMeta) {
$tags .= $this->ExtraMeta . "\n";
}
if(Permission::check('CMS_ACCESS_CMSMain') && in_array('CMSPreviewable', class_implements($this)) && !$this instanceof ErrorPage) {
$tags .= "<meta name=\"x-page-id\" content=\"{$this->ID}\" />\n";
$tags .= "<meta name=\"x-cms-edit-link\" content=\"" . $this->CMSEditLink() . "\" />\n";
@ -1605,10 +1605,10 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
'SiteTree',
"\"URLSegment\" = '$this->URLSegment' $IDFilter $parentFilter"
);
return !($existingPage);
}
}
/**
* Generate a URL segment based on the title provided.
*
@ -1712,7 +1712,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
foreach($contentLinks as $item) {
$item->DependentLinkType = 'Content link';
$linkList->push($item);
}
}
$items->merge($linkList);
}
@ -1724,9 +1724,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
foreach($virtuals as $item) {
$item->DependentLinkType = 'Virtual page';
$virtualList->push($item);
}
$items->merge($virtualList);
}
$items->merge($virtualList);
}
}
// Redirector pages
@ -1736,7 +1736,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
foreach($redirectors as $item) {
$item->DependentLinkType = 'Redirector page';
$redirectorList->push($item);
}
}
$items->merge($redirectorList);
}
@ -1999,9 +1999,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
->setAttribute(
'data-placeholder',
_t('SiteTree.GroupPlaceholder', 'Click to select group')
)
)
)
)
);
$visibility->setTitle($this->fieldLabel('Visibility'));
@ -2226,14 +2226,14 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
// Set up the initial state of the button to reflect the state of the underlying SiteTree object.
if($this->stagesDiffer('Stage', 'Live')) {
$publish->addExtraClass('ss-ui-alternate');
}
}
}
$actions = new FieldList(array($majorActions, $rootTabSet));
// Hook for extensions to add/remove actions.
$this->extend('updateCMSActions', $actions);
return $actions;
}
@ -2666,7 +2666,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
if(!$this->canEdit() && !$this->canAddChildren()) {
if (!$this->canView()) {
$classes .= " disabled";
$classes .= " disabled";
} else {
$classes .= " edit-disabled";
}

View File

@ -2,6 +2,37 @@
$.entwine('ss.tree', function($){
$('.cms-tree').entwine({
fromDocument: {
'oncontext_show.vakata': function(e){
this.adjustContextClass();
}
},
/*
* Add and remove classes from context menus to allow for
* adjusting the display
*/
adjustContextClass: function(){
var menus = $('#vakata-contextmenu').find("ul ul");
menus.each(function(i){
var col = "1",
count = $(menus[i]).find('li').length;
//Assign columns to menus over 10 items long
if(count > 20){
col = "3";
}else if(count > 10){
col = "2";
}
$(menus[i]).addClass('col-' + col).removeClass('right');
//Remove "right" class that jstree adds on mouseenter
$(menus[i]).find('li').on("mouseenter", function (e) {
$(this).parent('ul').removeClass("right");
});
});
},
getTreeConfig: function() {
var self = this, config = this._super(), hints = this.getHints();
config.plugins.push('contextmenu');
@ -101,7 +132,7 @@
);
}
}
]
]
};
return menuitems;
@ -110,6 +141,18 @@
return config;
}
});
// Scroll tree down to context of the current page
$('.cms-tree a.jstree-clicked').entwine({
onmatch: function(){
var self = this,
panel = self.parents('.cms-panel-content');
panel.animate({
scrollTop: self.offset().top - (panel.height() / 2)
}, 'slow');
}
});
});
}(jQuery));

View File

@ -1,4 +1,4 @@
<div id="settings-controller-cms-content" class="cms-content cms-edit-form center cms-tabset $BaseCSSClasses" data-layout-type="border" data-pjax-fragment="Content CurrentForm">
<div id="settings-controller-cms-content" class="cms-content center cms-tabset $BaseCSSClasses" data-layout-type="border" data-pjax-fragment="Content CurrentForm">
<div class="cms-content-header north">
<% with $EditForm %>
@ -7,10 +7,9 @@
<% include CMSBreadcrumbs %>
<% end_with %>
</div>
<% if $Fields.hasTabset %>
<% with $Fields.fieldByName('Root') %>
<div class="cms-content-header-tabs cms-tabset-nav-primary ss-ui-tabs-nav">
<div class="cms-content-header-tabs">
<ul class="cms-tabset-nav-primary">
<% loop $Tabs %>
<li<% if $extraClass %> class="$extraClass"<% end_if %>><a href="#$id">$Title</a></li>
@ -28,4 +27,4 @@
</div>
</div>
</div>

View File

@ -1,33 +1,29 @@
<form $FormAttributes data-layout-type="border">
<form $FormAttributes>
<div class="cms-content-fields center">
<% if $Message %>
<p id="{$FormName}_error" class="message $MessageType">$Message</p>
<% else %>
<p id="{$FormName}_error" class="message $MessageType" style="display: none"></p>
<% end_if %>
<% if $Message %>
<p id="{$FormName}_error" class="message $MessageType">$Message</p>
<% else %>
<p id="{$FormName}_error" class="message $MessageType" style="display: none"></p>
<% end_if %>
<fieldset>
<% if $Legend %><legend>$Legend</legend><% end_if %>
<% loop $Fields %>
$FieldHolder
<% end_loop %>
<div class="clear"><!-- --></div>
</fieldset>
</div>
<fieldset>
<% if $Legend %><legend>$Legend</legend><% end_if %>
<% loop $Fields %>
$FieldHolder
<% end_loop %>
<div class="clear"><!-- --></div>
</fieldset>
<div class="cms-content-actions cms-content-controls south">
<% if $Actions %>
<div class="Actions">
<% loop $Actions %>
$Field
<% end_loop %>
<% if $Controller.LinkPreview %>
<a href="$Controller.LinkPreview" class="cms-preview-toggle-link ss-ui-button" data-icon="preview">
<% _t('LeftAndMain.PreviewButton', 'Preview') %> &raquo;
</a>
<% end_if %>
</div>
<% if $Actions %>
<div class="Actions">
<% loop $Actions %>
$Field
<% end_loop %>
<% if $Controller.LinkPreview %>
<a href="$Controller.LinkPreview" class="cms-preview-toggle-link ss-ui-button" data-icon="preview">
<% _t('LeftAndMain.PreviewButton', 'Preview') %> &raquo;
</a>
<% end_if %>
</div>
</form>
<% end_if %>
</form>

View File

@ -11,7 +11,7 @@
class ZZZSearchFormTest extends FunctionalTest {
protected static $fixture_file = 'SearchFormTest.yml';
protected $mockController;
public function waitUntilIndexingFinished() {
@ -37,7 +37,7 @@ class ZZZSearchFormTest extends FunctionalTest {
$this->waitUntilIndexingFinished();
}
/**
* @return Boolean
*/
@ -101,7 +101,7 @@ class ZZZSearchFormTest extends FunctionalTest {
'Unpublished pages are not found by searchform'
);
}
public function testPagesRestrictedToLoggedinUsersNotIncluded() {
if(!$this->checkFulltextSupport()) return;
@ -109,7 +109,6 @@ class ZZZSearchFormTest extends FunctionalTest {
$page = $this->objFromFixture('SiteTree', 'restrictedViewLoggedInUsers');
$page->publish('Stage', 'Live');
$results = $sf->getResults(null, array('Search'=>'restrictedViewLoggedInUsers'));
$this->assertNotContains(
$page->ID,
@ -135,7 +134,6 @@ class ZZZSearchFormTest extends FunctionalTest {
$page = $this->objFromFixture('SiteTree', 'restrictedViewOnlyWebsiteUsers');
$page->publish('Stage', 'Live');
$results = $sf->getResults(null, array('Search'=>'restrictedViewOnlyWebsiteUsers'));
$this->assertNotContains(
$page->ID,
@ -165,16 +163,13 @@ class ZZZSearchFormTest extends FunctionalTest {
}
public function testInheritedRestrictedPagesNotIncluded() {
if(!$this->checkFulltextSupport()) return;
$sf = new SearchForm($this->mockController, 'SearchForm');
$parent = $this->objFromFixture('SiteTree', 'restrictedViewLoggedInUsers');
$parent->publish('Stage', 'Live');
$page = $this->objFromFixture('SiteTree', 'inheritRestrictedView');
$page->publish('Stage', 'Live');
$results = $sf->getResults(null, array('Search'=>'inheritRestrictedView'));
$this->assertNotContains(
$page->ID,
@ -232,6 +227,10 @@ class ZZZSearchFormTest extends FunctionalTest {
public function testSearchTitleAndContentWithSpecialCharacters() {
if(!$this->checkFulltextSupport()) return;
if(class_exists('PostgreSQLDatabase') && DB::getConn() instanceof PostgreSQLDatabase) {
$this->markTestSkipped("PostgreSQLDatabase doesn't support entity-encoded searches");
}
$sf = new SearchForm($this->mockController, 'SearchForm');
$pageWithSpecialChars = $this->objFromFixture('SiteTree', 'pageWithSpecialChars');