diff --git a/Assets/File.php b/Assets/File.php
index 074b287ad..0d2f006a0 100644
--- a/Assets/File.php
+++ b/Assets/File.php
@@ -475,10 +475,14 @@ class File extends DataObject implements ShortcodeHandler, AssetContainer, Thumb
$previewLink = Convert::raw2att($this->PreviewLink());
$image = "";
+
+ $statusTitle = $this->getStatusTitle();
+ $statusFlag = ($statusTitle) ? "{$statusTitle}" : '';
$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',
@@ -511,7 +515,18 @@ class File extends DataObject implements ShortcodeHandler, AssetContainer, Thumb
return $fields;
}
-
+
+ protected function getStatusTitle() {
+ $statusTitle = '';
+ if ($this->getIsAddedToStage()) {
+ $statusTitle = _t('File.DRAFT', 'Draft');
+ } elseif ($this->getIsModifiedOnStage()) {
+ $statusTitle = _t('File.MODIFIED', 'Modified');
+ }
+
+ return $statusTitle;
+ }
+
/**
* Returns a category based on the file extension.
* This can be useful when grouping files by type,
diff --git a/Assets/Image.php b/Assets/Image.php
index 44fee744d..82f1354d4 100644
--- a/Assets/Image.php
+++ b/Assets/Image.php
@@ -51,6 +51,9 @@ class Image extends File implements ShortcodeHandler {
$image = "";
$link = $this->Link();
+
+ $statusTitle = $this->getStatusTitle();
+ $statusFlag = "{$statusTitle}";
$content = Tab::create('Main',
HeaderField::create('TitleHeader', $this->Title, 1)
@@ -92,10 +95,15 @@ class Image extends File implements ShortcodeHandler {
'TitleHeader',
LiteralField::create(
"DisplaySize",
- sprintf('
%spx, %s
',
- $dimensions, $this->getSize())
+ sprintf('%spx, %s %s
',
+ $dimensions, $this->getSize(), $statusFlag)
)
);
+ } else {
+ $content->insertAfter(
+ 'TitleHeader',
+ LiteralField::create('StatusFlag', $statusFlag)
+ );
}
$fields = FieldList::create(TabSet::create('Root', $content));
diff --git a/ORM/Versioning/Versioned.php b/ORM/Versioning/Versioned.php
index 07f746007..94de2679b 100644
--- a/ORM/Versioning/Versioned.php
+++ b/ORM/Versioning/Versioned.php
@@ -2328,8 +2328,56 @@ class Versioned extends DataExtension implements TemplateGlobalProvider {
);
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 getIsDeletedFromStage() {
+ if(!$this->owner->ID) return true;
+
+ $stageVersion = Versioned::get_versionnumber_by_stage($this->owner->class, Versioned::DRAFT, $this->owner->ID);
+
+ // Return true for both completely deleted pages and for pages just deleted from stage
+ return !($stageVersion);
+ }
+
+ /**
+ * 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 getIsModifiedOnStage() {
+ // New unsaved pages could be never be published
+ if(!$this->owner->ID) return false;
-
+ $stageVersion = Versioned::get_versionnumber_by_stage($this->owner->class, 'Stage', $this->owner->ID);
+ $liveVersion = Versioned::get_versionnumber_by_stage($this->owner->class, 'Live', $this->owner->ID);
+
+ $isModified = ($stageVersion && $stageVersion != $liveVersion);
+ $this->owner->extend('updateIsModifiedOnStage', $isModified);
+
+ return $isModified;
+ }
+
+ /**
+ * Compares current draft with live version, and returns true if no live version exists, meaning the page was never
+ * published.
+ *
+ * @return bool
+ */
+ public function getIsAddedToStage() {
+ // New unsaved pages could be never be published
+ if(!$this->owner->ID) return false;
+
+ $stageVersion = Versioned::get_versionnumber_by_stage($this->owner->class, 'Stage', $this->owner->ID);
+ $liveVersion = Versioned::get_versionnumber_by_stage($this->owner->class, 'Live', $this->owner->ID);
+
+ return ($stageVersion && !$liveVersion);
+ }
/**
* Return the equivalent of a DataList::create() call, querying the latest
diff --git a/client/lang/en.js b/client/lang/en.js
index e09c9b2b1..8c5a42845 100644
--- a/client/lang/en.js
+++ b/client/lang/en.js
@@ -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",
@@ -47,4 +50,4 @@ if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
"UploadField.WRITEFAILED": "Failed to write file to disk",
"VALIDATOR.FIELDREQUIRED": "Please fill out \"%s\", it is required."
});
-}
+}
\ No newline at end of file
diff --git a/client/lang/src/en.js b/client/lang/src/en.js
index 4a5374967..3754d41ce 100644
--- a/client/lang/src/en.js
+++ b/client/lang/src/en.js
@@ -1,5 +1,8 @@
{
- "FormField.NONE": "None",
+ "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",
diff --git a/lang/en.yml b/lang/en.yml
index 97026e337..2e33baf17 100644
--- a/lang/en.yml
+++ b/lang/en.yml
@@ -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}'