Merge remote-tracking branch 'origin/3.1'

This commit is contained in:
Ingo Schommer 2012-12-14 11:08:10 +01:00
commit 75e2567a05
10 changed files with 152 additions and 55 deletions

View File

@ -95,7 +95,7 @@ JS
// Don't filter list when a detail view is requested, // Don't filter list when a detail view is requested,
// to avoid edge cases where the filtered list wouldn't contain the requested // to avoid edge cases where the filtered list wouldn't contain the requested
// record due to faulty session state (current folder not always encoded in URL, see #7408). // record due to faulty session state (current folder not always encoded in URL, see #7408).
if(!$folder->ID && ($this->request->param('ID') == 'field')) { if(!$folder->ID && $this->request->requestVar('ID') === null && ($this->request->param('ID') == 'field')) {
return $list; return $list;
} }

View File

@ -638,6 +638,18 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
$actions = $record->getAllCMSActions(); $actions = $record->getAllCMSActions();
} else { } else {
$actions = $record->getCMSActions(); $actions = $record->getCMSActions();
// Find and remove action menus that have no actions.
if ($actions && $actions->Count()) {
$tabset = $actions->fieldByName('ActionMenus');
if ($tabset) {
foreach ($tabset->getChildren() as $tab) {
if (!$tab->getChildren()->count()) {
$tabset->removeByName($tab->getName());
}
}
}
}
} }
// Use <button> to allow full jQuery UI styling // Use <button> to allow full jQuery UI styling
@ -845,24 +857,6 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
// If the 'Save & Publish' button was clicked, also publish the page // If the 'Save & Publish' button was clicked, also publish the page
if (isset($data['publish']) && $data['publish'] == 1) { if (isset($data['publish']) && $data['publish'] == 1) {
$record->doPublish(); $record->doPublish();
// Update classname with original and get new instance (see above for explanation)
if(isset($data['ClassName'])) {
$record->setClassName($data['ClassName']);
$publishedRecord = $record->newClassInstance($record->ClassName);
}
$this->response->addHeader(
'X-Status',
rawurlencode(_t(
'LeftAndMain.STATUSPUBLISHEDSUCCESS',
"Published '{title}' successfully",
'Status message after publishing a page, showing the page title',
array('title' => $record->Title)
))
);
} else {
$this->response->addHeader('X-Status', rawurlencode(_t('LeftAndMain.SAVEDUP', 'Saved.')));
} }
return $this->getResponseNegotiator()->respond($this->request); return $this->getResponseNegotiator()->respond($this->request);

View File

@ -2047,17 +2047,47 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
/** /**
* Get the actions available in the CMS for this page - eg Save, Publish. * Get the actions available in the CMS for this page - eg Save, Publish.
*
* Frontend scripts and styles know how to handle the following FormFields:
* * top-level FormActions appear as standalone buttons
* * top-level CompositeField with FormActions within appear as grouped buttons
* * TabSet & Tabs appear as a drop ups
* * FormActions within the Tab are restyled as links
* * major actions can provide alternate states for richer presentation (see ssui.button widget extension).
*
* @return FieldList The available actions for this page. * @return FieldList The available actions for this page.
*/ */
public function getCMSActions() { public function getCMSActions() {
$minorActions = CompositeField::create()->setTag('fieldset')->addExtraClass('ss-ui-buttonset'); $existsOnLive = $this->getExistsOnLive();
$actions = new FieldList($minorActions);
// Major actions appear as buttons immediately visible as page actions.
$majorActions = CompositeField::create()->setName('MajorActions')->setTag('fieldset')->addExtraClass('ss-ui-buttonset');
// Minor options are hidden behind a drop-up and appear as links (although they are still FormActions).
$rootTabSet = new TabSet('ActionMenus');
$moreOptions = new Tab(
'MoreOptions',
_t('SiteTree.MoreOptions', 'More options', 'Expands a view for more buttons')
);
$rootTabSet->push($moreOptions);
$rootTabSet->addExtraClass('ss-ui-action-tabset action-menus');
// Render page information into the "more-options" drop-up, on the top.
$moreOptions->push(
new LiteralField('Information',
$this->customise(array(
'ExistsOnLive' => $existsOnLive
))->renderWith('SiteTree_Information')
)
);
// "readonly"/viewing version that isn't the current version of the record // "readonly"/viewing version that isn't the current version of the record
$stageOrLiveRecord = Versioned::get_one_by_stage($this->class, Versioned::current_stage(), sprintf('"SiteTree"."ID" = %d', $this->ID)); $stageOrLiveRecord = Versioned::get_one_by_stage($this->class, Versioned::current_stage(), sprintf('"SiteTree"."ID" = %d', $this->ID));
if($stageOrLiveRecord && $stageOrLiveRecord->Version != $this->Version) { if($stageOrLiveRecord && $stageOrLiveRecord->Version != $this->Version) {
$minorActions->push(FormAction::create('email', _t('CMSMain.EMAIL', 'Email'))); $moreOptions->push(FormAction::create('email', _t('CMSMain.EMAIL', 'Email')));
$minorActions->push(FormAction::create('rollback', _t('CMSMain.ROLLBACK', 'Roll back to this version'))); $moreOptions->push(FormAction::create('rollback', _t('CMSMain.ROLLBACK', 'Roll back to this version')));
$actions = new FieldList(array($majorActions, $rootTabSet));
// getCMSActions() can be extended with updateCMSActions() on a extension // getCMSActions() can be extended with updateCMSActions() on a extension
$this->extend('updateCMSActions', $actions); $this->extend('updateCMSActions', $actions);
@ -2067,17 +2097,17 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
if($this->isPublished() && $this->canPublish() && !$this->IsDeletedFromStage && $this->canDeleteFromLive()) { if($this->isPublished() && $this->canPublish() && !$this->IsDeletedFromStage && $this->canDeleteFromLive()) {
// "unpublish" // "unpublish"
$minorActions->push( $moreOptions->push(
FormAction::create('unpublish', _t('SiteTree.BUTTONUNPUBLISH', 'Unpublish'), 'delete') FormAction::create('unpublish', _t('SiteTree.BUTTONUNPUBLISH', 'Unpublish'), 'delete')
->setDescription(_t('SiteTree.BUTTONUNPUBLISHDESC', 'Remove this page from the published site')) ->setDescription(_t('SiteTree.BUTTONUNPUBLISHDESC', 'Remove this page from the published site'))
->addExtraClass('ss-ui-action-destructive')->setAttribute('data-icon', 'unpublish') ->addExtraClass('ss-ui-action-destructive')
); );
} }
if($this->stagesDiffer('Stage', 'Live') && !$this->IsDeletedFromStage) { if($this->stagesDiffer('Stage', 'Live') && !$this->IsDeletedFromStage) {
if($this->isPublished() && $this->canEdit()) { if($this->isPublished() && $this->canEdit()) {
// "rollback" // "rollback"
$minorActions->push( $moreOptions->push(
FormAction::create('rollback', _t('SiteTree.BUTTONCANCELDRAFT', 'Cancel draft changes'), 'delete') FormAction::create('rollback', _t('SiteTree.BUTTONCANCELDRAFT', 'Cancel draft changes'), 'delete')
->setDescription(_t('SiteTree.BUTTONCANCELDRAFTDESC', 'Delete your draft and revert to the currently published page')) ->setDescription(_t('SiteTree.BUTTONCANCELDRAFTDESC', 'Delete your draft and revert to the currently published page'))
); );
@ -2086,46 +2116,58 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
if($this->canEdit()) { if($this->canEdit()) {
if($this->IsDeletedFromStage) { if($this->IsDeletedFromStage) {
if($this->ExistsOnLive) { // The usual major actions are not available, so we provide alternatives here.
if($existsOnLive) {
// "restore" // "restore"
$minorActions->push(FormAction::create('revert',_t('CMSMain.RESTORE','Restore'))); $majorActions->push(FormAction::create('revert',_t('CMSMain.RESTORE','Restore')));
if($this->canDelete() && $this->canDeleteFromLive()) { if($this->canDelete() && $this->canDeleteFromLive()) {
// "delete from live" // "delete from live"
$minorActions->push( $majorActions->push(
FormAction::create('deletefromlive',_t('CMSMain.DELETEFP','Delete'))->addExtraClass('ss-ui-action-destructive') FormAction::create('deletefromlive',_t('CMSMain.DELETEFP','Delete'))->addExtraClass('ss-ui-action-destructive')
); );
} }
} else { } else {
// "restore" // "restore"
$minorActions->push( $majorActions->push(
FormAction::create('restore',_t('CMSMain.RESTORE','Restore'))->setAttribute('data-icon', 'decline') FormAction::create('restore',_t('CMSMain.RESTORE','Restore'))->setAttribute('data-icon', 'decline')
); );
} }
} else { } else {
if($this->canDelete()) { if($this->canDelete()) {
// "delete" // "delete"
$minorActions->push( $moreOptions->push(
FormAction::create('delete',_t('CMSMain.DELETE','Delete draft'))->addExtraClass('delete ss-ui-action-destructive') FormAction::create('delete',_t('CMSMain.DELETE','Delete draft'))->addExtraClass('delete ss-ui-action-destructive')
->setAttribute('data-icon', 'decline')
); );
} }
// "save" // "save", supports an alternate state that is still clickable, but notifies the user that the action is not needed.
$minorActions->push( $majorActions->push(
FormAction::create('save',_t('CMSMain.SAVEDRAFT','Save Draft'))->setAttribute('data-icon', 'addpage') FormAction::create('save', _t('SiteTree.BUTTONSAVED', 'Saved'))
->setAttribute('data-icon', 'accept')
->setAttribute('data-icon-alternate', 'addpage')
->setAttribute('data-text-alternate', _t('CMSMain.SAVEDRAFT','Save draft'))
); );
} }
} }
if($this->canPublish() && !$this->IsDeletedFromStage) { if($this->canPublish() && !$this->IsDeletedFromStage) {
// "publish" // "publish", as with "save", it supports an alternate state to show when action is needed.
$actions->push( $majorActions->push(
FormAction::create('publish', _t('SiteTree.BUTTONSAVEPUBLISH', 'Save & Publish')) $publish = FormAction::create('publish', _t('SiteTree.BUTTONPUBLISHED', 'Published'))
->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept') ->setAttribute('data-icon', 'accept')
->setAttribute('data-icon-alternate', 'disk')
->setAttribute('data-text-alternate', _t('SiteTree.BUTTONSAVEPUBLISH', 'Save & publish'))
); );
// 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');
}
} }
// getCMSActions() can be extended with updateCMSActions() on a extension $actions = new FieldList(array($majorActions, $rootTabSet));
// Hook for extensions to add/remove actions.
$this->extend('updateCMSActions', $actions); $this->extend('updateCMSActions', $actions);
return $actions; return $actions;

View File

@ -163,7 +163,7 @@ class SS_Report extends ViewableData {
/** /**
* Return the SS_Report objects making up the given list. * Return the SS_Report objects making up the given list.
* @return ArrayList an arraylist of SS_Report objects * @return Array of SS_Report objects
*/ */
static public function get_reports() { static public function get_reports() {
$reports = ClassInfo::subclassesFor(get_called_class()); $reports = ClassInfo::subclassesFor(get_called_class());
@ -182,13 +182,12 @@ class SS_Report extends ViewableData {
} }
} }
//convert array into ArrayList uasort($reportsArray, function($a, $b) {
$list = ArrayList::create($reportsArray); if($a->sort == $b->sort) return 0;
else return ($a->sort < $b->sort) ? -1 : 1;
});
//sort return $reportsArray;
$list = $list->sort('sort');
return $list;
} }
/////////////////////// UI METHODS /////////////////////// /////////////////////// UI METHODS ///////////////////////

View File

@ -310,6 +310,50 @@
} }
}); });
/**
* Enable save buttons upon detecting changes to content.
* "changed" class is added by jQuery.changetracker.
*/
$('.cms-edit-form .changed').entwine({
onmatch: function(e) {
var form = this.closest('.cms-edit-form');
form.find('button[name=action_save]').button('option', 'showingAlternate', true);
form.find('button[name=action_publish]').button('option', 'showingAlternate', true);
this._super(e);
},
onunmatch: function(e) {
this._super(e);
}
});
$('.cms-edit-form .Actions button[name=action_publish]').entwine({
/**
* Bind to ssui.button event to trigger stylistic changes.
*/
onbuttonafterrefreshalternate: function() {
if (this.button('option', 'showingAlternate')) {
this.addClass('ss-ui-action-constructive');
}
else {
this.removeClass('ss-ui-action-constructive');
}
}
});
$('.cms-edit-form .Actions button[name=action_save]').entwine({
/**
* Bind to ssui.button event to trigger stylistic changes.
*/
onbuttonafterrefreshalternate: function() {
if (this.button('option', 'showingAlternate')) {
this.addClass('ss-ui-action-constructive');
}
else {
this.removeClass('ss-ui-action-constructive');
}
}
});
/** /**
* Class: .cms-edit-form.CMSPageSettingsController input[name="ParentType"]:checked * Class: .cms-edit-form.CMSPageSettingsController input[name="ParentType"]:checked
* *

View File

@ -16,7 +16,7 @@ class MigrateSiteTreeLinkingTask extends BuildTask {
$links = 0; $links = 0;
$linkedPages = new DataList('SiteTree'); $linkedPages = new DataList('SiteTree');
$linkedPages->innerJoin('SiteTree_LinkTracking', '"SiteTree_LinkTracking"."SiteTreeID" = "SiteTree"."ID"'); $linkedPages = $linkedPages->innerJoin('SiteTree_LinkTracking', '"SiteTree_LinkTracking"."SiteTreeID" = "SiteTree"."ID"');
if($linkedPages) foreach($linkedPages as $page) { if($linkedPages) foreach($linkedPages as $page) {
$tracking = DB::query(sprintf('SELECT "ChildID", "FieldName" FROM "SiteTree_LinkTracking" WHERE "SiteTreeID" = %d', $page->ID))->map(); $tracking = DB::query(sprintf('SELECT "ChildID", "FieldName" FROM "SiteTree_LinkTracking" WHERE "SiteTreeID" = %d', $page->ID))->map();

View File

@ -8,17 +8,17 @@
<div class="cms-content-header-tabs"> <div class="cms-content-header-tabs">
<ul class="cms-tabset-nav-primary"> <ul class="cms-tabset-nav-primary">
<li class="content-treeview<% if class == 'CMSPageEditController' %> ui-tabs-active<% end_if %>"> <li class="content-treeview<% if class == 'CMSPageEditController' %> ui-tabs-active<% end_if %>">
<a href="$LinkPageEdit" title="Form_EditForm" data-href="$LinkPageEdit"> <a href="$LinkPageEdit" class="cms-panel-link" title="Form_EditForm" data-href="$LinkPageEdit">
<% _t('CMSMain.TabContent', 'Content') %> <% _t('CMSMain.TabContent', 'Content') %>
</a> </a>
</li> </li>
<li class="content-listview<% if class == 'CMSPageSettingsController' %> ui-tabs-active<% end_if %>"> <li class="content-listview<% if class == 'CMSPageSettingsController' %> ui-tabs-active<% end_if %>">
<a href="$LinkPageSettings" title="Form_EditForm" data-href="$LinkPageSettings"> <a href="$LinkPageSettings" class="cms-panel-link" title="Form_EditForm" data-href="$LinkPageSettings">
<% _t('CMSMain.TabSettings', 'Settings') %> <% _t('CMSMain.TabSettings', 'Settings') %>
</a> </a>
</li> </li>
<li class="content-listview<% if class == 'CMSPageHistoryController' %> ui-tabs-active<% end_if %>"> <li class="content-listview<% if class == 'CMSPageHistoryController' %> ui-tabs-active<% end_if %>">
<a href="$LinkPageHistory" title="Form_EditForm" data-href="$LinkPageHistory"> <a href="$LinkPageHistory" class="cms-panel-link" title="Form_EditForm" data-href="$LinkPageHistory">
<% _t('CMSMain.TabHistory', 'History') %> <% _t('CMSMain.TabHistory', 'History') %>
</a> </a>
</li> </li>

View File

@ -0,0 +1,9 @@
<div class='cms-sitetree-information'>
<p class="meta-info"><% _t('LASTSAVED', 'Last saved') %> $LastEdited.Ago(0)
<% if ExistsOnLive %>
<br /><% _t('LASTPUBLISHED', 'Last published') %> $Live.LastEdited.Ago(0)
<% else %>
<br /><em><% _t('NOTPUBLISHED', 'Not published') %></em>
<% end_if %>
</p>
</div>

View File

@ -182,9 +182,10 @@ class CMSMainTest extends FunctionalTest {
$parentPage->doUnpublish(); $parentPage->doUnpublish();
$childPage->doUnpublish(); $childPage->doUnpublish();
$this->assertContains( $actions = $childPage->getCMSActions()->dataFields();
$this->assertArrayHasKey(
'action_publish', 'action_publish',
$childPage->getCMSActions()->column('Name'), $actions,
'Can publish a page with an unpublished parent with strict hierarchy off' 'Can publish a page with an unpublished parent with strict hierarchy off'
); );
SiteTree::set_enforce_strict_hierarchy(false); SiteTree::set_enforce_strict_hierarchy(false);

View File

@ -4,6 +4,14 @@
BUILD_DIR=$1 BUILD_DIR=$1
# Environment info
echo "# Environment info"
echo " - `php --version`"
echo " - `mysql --version`"
echo " - `pg_config --version`"
echo " - SQLite3 `sqlite3 -version`"
echo ""
# Fetch all dependencies # Fetch all dependencies
# TODO Replace with different composer.json variations # TODO Replace with different composer.json variations