Merge pull request #6136 from open-sausages/pulls/4.0/add-status-flag

Add status flag to File and Image Edit Form
This commit is contained in:
Ingo Schommer 2016-10-06 11:25:07 +13:00 committed by GitHub
commit 406ff5b183
8 changed files with 174 additions and 18 deletions

View File

@ -476,9 +476,13 @@ class File extends DataObject implements ShortcodeHandler, AssetContainer, Thumb
$previewLink = Convert::raw2att($this->PreviewLink());
$image = "<img src=\"{$previewLink}\" class=\"editor__thumbnail\" />";
$statusTitle = $this->getStatusTitle();
$statusFlag = ($statusTitle) ? "<span class=\"editor__status-flag\">{$statusTitle}</span>" : '';
$content = Tab::create('Main',
HeaderField::create('TitleHeader', $this->Title, 1)
->addExtraClass('editor__heading'),
LiteralField::create('StatusFlag', $statusFlag),
LiteralField::create("IconFull", $image)
->addExtraClass('editor__file-preview'),
TabSet::create('Editor',
@ -512,6 +516,21 @@ class File extends DataObject implements ShortcodeHandler, AssetContainer, Thumb
return $fields;
}
/**
* Get title for current file status
*
* @return string
*/
public function getStatusTitle() {
$statusTitle = '';
if ($this->isOnDraftOnly()) {
$statusTitle = _t('File.DRAFT', 'Draft');
} elseif ($this->isModifiedOnDraft()) {
$statusTitle = _t('File.MODIFIED', 'Modified');
}
return $statusTitle;
}
/**
* Returns a category based on the file extension.
* This can be useful when grouping files by type,

View File

@ -52,6 +52,9 @@ class Image extends File implements ShortcodeHandler {
$link = $this->Link();
$statusTitle = $this->getStatusTitle();
$statusFlag = "<span class=\"editor__status-flag\">{$statusTitle}</span>";
$content = Tab::create('Main',
HeaderField::create('TitleHeader', $this->Title, 1)
->addExtraClass('editor__heading'),
@ -92,10 +95,15 @@ class Image extends File implements ShortcodeHandler {
'TitleHeader',
LiteralField::create(
"DisplaySize",
sprintf('<div class="editor__specs">%spx, %s</div>',
$dimensions, $this->getSize())
sprintf('<div class="editor__specs">%spx, %s %s</div>',
$dimensions, $this->getSize(), $statusFlag)
)
);
} else {
$content->insertAfter(
'TitleHeader',
LiteralField::create('StatusFlag', $statusFlag)
);
}
$fields = FieldList::create(TabSet::create('Root', $content));

View File

@ -1774,9 +1774,8 @@ class Versioned extends DataExtension implements TemplateGlobalProvider {
public function stagesDiffer($stage1, $stage2) {
$table1 = $this->baseTable($stage1);
$table2 = $this->baseTable($stage2);
$owner = $this->owner;
if(!is_numeric($owner->ID)) {
$id = $this->owner->ID ?: $this->owner->OldID;
if (!$id) {
return true;
}
@ -1788,7 +1787,7 @@ class Versioned extends DataExtension implements TemplateGlobalProvider {
"SELECT CASE WHEN \"$table1\".\"Version\"=\"$table2\".\"Version\" THEN 1 ELSE 0 END
FROM \"$table1\" INNER JOIN \"$table2\" ON \"$table1\".\"ID\" = \"$table2\".\"ID\"
AND \"$table1\".\"ID\" = ?",
array($owner->ID)
array($id)
)->value();
return !$stagesAreEqual;
@ -2292,8 +2291,8 @@ class Versioned extends DataExtension implements TemplateGlobalProvider {
* @return bool
*/
public function isPublished() {
$owner = $this->owner;
if(!$owner->isInDB()) {
$id = $this->owner->ID ?: $this->owner->OldID;
if(!$id) {
return false;
}
@ -2305,31 +2304,69 @@ class Versioned extends DataExtension implements TemplateGlobalProvider {
$table = $this->baseTable(static::LIVE);
$result = DB::prepared_query(
"SELECT COUNT(*) FROM \"{$table}\" WHERE \"{$table}\".\"ID\" = ?",
array($owner->ID)
array($id)
);
return (bool)$result->value();
}
/**
* Check if page doesn't exist on any stage, but used to be
*
* @return bool
*/
public function isArchived() {
$id = $this->owner->ID ?: $this->owner->OldID;
return $id && !$this->isOnDraft() && !$this->isPublished();
}
/**
* Check if this record exists on the draft stage
*
* @return bool
*/
public function isOnDraft() {
$owner = $this->owner;
if(!$owner->isInDB()) {
$id = $this->owner->ID ?: $this->owner->OldID;
if(!$id) {
return false;
}
$table = $this->baseTable();
$result = DB::prepared_query(
"SELECT COUNT(*) FROM \"{$table}\" WHERE \"{$table}\".\"ID\" = ?",
array($owner->ID)
array($id)
);
return (bool)$result->value();
}
/**
* Compares current draft with live version, and returns true if no draft version of this page exists but the page
* is still published (eg, after triggering "Delete from draft site" in the CMS).
*
* @return bool
*/
public function isOnLiveOnly() {
return $this->isPublished() && !$this->isOnDraft();
}
/**
* Compares current draft with live version, and returns true if no live version exists, meaning the page was never
* published.
*
* @return bool
*/
public function isOnDraftOnly() {
return $this->isOnDraft() && !$this->isPublished();
}
/**
* Compares current draft with live version, and returns true if these versions differ, meaning there have been
* unpublished changes to the draft site.
*
* @return bool
*/
public function isModifiedOnDraft() {
return $this->isOnDraft() && $this->stagesDiffer(Versioned::DRAFT, Versioned::LIVE);
}
/**
* Return the equivalent of a DataList::create() call, querying the latest

View File

@ -7,6 +7,9 @@ if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
} else {
ss.i18n.addDictionary('en', {
"FormField.NONE": "None",
"File.DRAFT": "Draft",
"File.MODIFIED": "Modified",
"File.PUBLISHED": "Published",
"FILEIFRAMEFIELD.CONFIRMDELETE": "Are you sure you want to delete this file?",
"FILEIFRAMEFIELD.DELETEFILE": "Delete File",
"FILEIFRAMEFIELD.DELETEIMAGE": "Delete Image",

View File

@ -1,5 +1,8 @@
{
"FormField.NONE": "None",
"File.DRAFT": "Draft",
"File.MODIFIED": "Modified",
"File.PUBLISHED": "Published",
"FILEIFRAMEFIELD.CONFIRMDELETE": "Are you sure you want to delete this file?",
"FILEIFRAMEFIELD.DELETEFILE": "Delete File",
"FILEIFRAMEFIELD.DELETEIMAGE": "Delete Image",

View File

@ -887,10 +887,18 @@ A very small number of methods were chosen for deprecation, and will be removed
* Any extension declared via `versionableExtensions` config on Versioned dataobject must now
`VersionableExtension` interface at a minimum. `Translatable` has been removed from default
`versionableExtensions`
* A lot of standard versioned API has been refactored from `SiteTree` into `Versioned` extension. Now
all versioned DataObjects have `canPublish()`, `canArchive()`, `canUnpublish()`, `doPublish()`, `doArchive()`
`doUnpublish()`, `isPublished()` and `isonDraft()` out of the box. However, `do*()` methods will no longer
automatically check `can*()` permissions, and must be done by usercode before invocation.
* A lot of standard versioned API has been refactored from `SiteTree` into `Versioned` extension.
* All versioned DataObjects have `canPublish()`, `canArchive()`, `canUnpublish()` permission checks
* All versioned Dataobjects have `doPublish()`, `doArchive()`, `doPublish()`, and `doUnpublish()` actions.
However, `do*()` methods will no longer automatically check `can*()` permissions, and must be done by
usercode before invocation.
* `SiteTree::getIsAddedToStage()` moved to `Versioned` and renamed to `isOnDraftOnly()`
* `SiteTre::getIsModifiedOnStage()` moved to `Versioned` and renamed to `isModifiedOnDraft()`
* `SiteTree::isPublished()` moved to `Versioned`.
* `SiteTree::getExistsOnLive()` removed in favour of `isPublished()`
* `isOnDraft()` added to `Versioned`.
* `isArchived()` added to `Versioned`.
* `isOnLiveOnly()` added to `Versioned`.
* `ChangeSet` and `ChangeSetItem` have been added for batch publishing of versioned dataobjects.
* `DataObject.table_name` config can now be used to customise the database table for any record.
* `DataObjectSchema` class added to assist with mapping between classes and tables.
@ -903,6 +911,8 @@ A very small number of methods were chosen for deprecation, and will be removed
* Removed `UpgradeSiteTreePermissionSchemaTask`
* Removed `EncryptAllPasswordsTask`
* Removed `DBString::LimitWordCountXML()` method. Use `LimitWordCount` for XML safe version.
* Removed `SiteTree::getExistsOnLive()`. Use `isPublished()` instead.
* Removed `SiteTree::getIsDeletedFromStage()`. Use `isOnDraft()` instead (inverse case).
### <a name="overview-filesystem"></a>Filesystem API

View File

@ -202,6 +202,7 @@ en:
CssType: 'CSS file'
DmgType: 'Apple disk image'
DocType: 'Word document'
DRAFT: 'Draft'
Filename: Filename
GifType: 'GIF image - good for diagrams'
GzType: 'GZIP compressed file'
@ -212,6 +213,7 @@ en:
IcoType: 'Icon image'
JpgType: 'JPEG image - good for photos'
JsType: 'Javascript file'
MODIFIED: 'Modified'
Mp3Type: 'MP3 audio file'
MpgType: 'MPEG video file'
NOFILESIZE: 'Filesize is zero bytes.'
@ -220,6 +222,7 @@ en:
PLURALNAME: Files
PdfType: 'Adobe Acrobat PDF file'
PngType: 'PNG image - good general-purpose format'
PUBLISHED: 'Published'
SINGULARNAME: File
TOOLARGE: 'Filesize is too large, maximum {size} allowed'
TOOLARGESHORT: 'File size exceeds {size}'

View File

@ -1,6 +1,8 @@
<?php
use SilverStripe\ORM\DB;
use SilverStripe\ORM\HasManyList;
use SilverStripe\ORM\ManyManyList;
use SilverStripe\ORM\Versioning\Versioned;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\FieldType\DBDatetime;
@ -1087,6 +1089,77 @@ class VersionedTest extends SapphireTest {
$this->assertEquals(2, $version->Version);
$this->assertEquals($record->Title, $version->Title);
}
public function testStageStates() {
// newly created page
$createdPage = new VersionedTest_DataObject();
$createdPage->write();
$this->assertTrue($createdPage->isOnDraft());
$this->assertFalse($createdPage->isPublished());
$this->assertTrue($createdPage->isOnDraftOnly());
$this->assertTrue($createdPage->isModifiedOnDraft());
// published page
$publishedPage = new VersionedTest_DataObject();
$publishedPage->write();
$publishedPage->copyVersionToStage('Stage','Live');
$this->assertTrue($publishedPage->isOnDraft());
$this->assertTrue($publishedPage->isPublished());
$this->assertFalse($publishedPage->isOnDraftOnly());
$this->assertFalse($publishedPage->isOnLiveOnly());
$this->assertFalse($publishedPage->isModifiedOnDraft());
// published page, deleted from stage
$deletedFromDraftPage = new VersionedTest_DataObject();
$deletedFromDraftPage->write();
$deletedFromDraftPage->copyVersionToStage('Stage','Live');
$deletedFromDraftPage->deleteFromStage('Stage');
$this->assertFalse($deletedFromDraftPage->isArchived());
$this->assertFalse($deletedFromDraftPage->isOnDraft());
$this->assertTrue($deletedFromDraftPage->isPublished());
$this->assertFalse($deletedFromDraftPage->isOnDraftOnly());
$this->assertTrue($deletedFromDraftPage->isOnLiveOnly());
$this->assertFalse($deletedFromDraftPage->isModifiedOnDraft());
// published page, deleted from live
$deletedFromLivePage = new VersionedTest_DataObject();
$deletedFromLivePage->write();
$deletedFromLivePage->copyVersionToStage('Stage','Live');
$deletedFromLivePage->deleteFromStage('Live');
$this->assertFalse($deletedFromLivePage->isArchived());
$this->assertTrue($deletedFromLivePage->isOnDraft());
$this->assertFalse($deletedFromLivePage->isPublished());
$this->assertTrue($deletedFromLivePage->isOnDraftOnly());
$this->assertFalse($deletedFromLivePage->isOnLiveOnly());
$this->assertTrue($deletedFromLivePage->isModifiedOnDraft());
// published page, deleted from both stages
$deletedFromAllStagesPage = new VersionedTest_DataObject();
$deletedFromAllStagesPage->write();
$deletedFromAllStagesPage->copyVersionToStage('Stage','Live');
$deletedFromAllStagesPage->doArchive();
$this->assertTrue($deletedFromAllStagesPage->isArchived());
$this->assertFalse($deletedFromAllStagesPage->isOnDraft());
$this->assertFalse($deletedFromAllStagesPage->isPublished());
$this->assertFalse($deletedFromAllStagesPage->isOnDraftOnly());
$this->assertFalse($deletedFromAllStagesPage->isOnLiveOnly());
$this->assertFalse($deletedFromAllStagesPage->isModifiedOnDraft());
// published page, modified
$modifiedOnDraftPage = new VersionedTest_DataObject();
$modifiedOnDraftPage->write();
$modifiedOnDraftPage->copyVersionToStage('Stage','Live');
$modifiedOnDraftPage->Content = 'modified';
$modifiedOnDraftPage->write();
$this->assertFalse($modifiedOnDraftPage->isArchived());
$this->assertTrue($modifiedOnDraftPage->isOnDraft());
$this->assertTrue($modifiedOnDraftPage->isPublished());
$this->assertFalse($modifiedOnDraftPage->isOnDraftOnly());
$this->assertFalse($modifiedOnDraftPage->isOnLiveOnly());
$this->assertTrue($modifiedOnDraftPage->isModifiedOnDraft());
}
}