diff --git a/Controller/ArticleController.php b/Controller/ArticleController.php index 47cbc6a73..baeaa6cea 100644 --- a/Controller/ArticleController.php +++ b/Controller/ArticleController.php @@ -159,10 +159,12 @@ public function getAction($uuid, Request $request) */ public function postAction(Request $request) { + $action = $request->get('action'); $document = $this->getDocumentManager()->create(self::DOCUMENT_TYPE); $locale = $this->getRequestParameter($request, 'locale', true); $this->persistDocument($request->request->all(), $document, $locale); + $this->handleActionParameter($action, $document, $locale); $this->getDocumentManager()->flush(); return $this->handleView( @@ -183,6 +185,7 @@ public function postAction(Request $request) public function putAction(Request $request, $uuid) { $locale = $this->getRequestParameter($request, 'locale', true); + $action = $request->get('action'); $document = $this->getDocumentManager()->find( $uuid, @@ -196,6 +199,7 @@ public function putAction(Request $request, $uuid) $this->get('sulu_hash.request_hash_checker')->checkHash($request, $document, $document->getUuid()); $this->persistDocument($request->request->all(), $document, $locale); + $this->handleActionParameter($action, $document, $locale); $this->getDocumentManager()->flush(); return $this->handleView( @@ -288,4 +292,20 @@ protected function getDocumentManager() { return $this->get('sulu_document_manager.document_manager'); } + + /** + * Delegates actions by given actionParameter, which can be retrieved from the request. + * + * @param string $actionParameter + * @param object $document + * @param string $locale + */ + private function handleActionParameter($actionParameter, $document, $locale) + { + switch ($actionParameter) { + case 'publish': + $this->getDocumentManager()->publish($document, $locale); + break; + } + } } diff --git a/Document/ArticleDocument.php b/Document/ArticleDocument.php index 2e79657d2..01bd64b2a 100644 --- a/Document/ArticleDocument.php +++ b/Document/ArticleDocument.php @@ -18,6 +18,7 @@ use Sulu\Component\Content\Document\Behavior\LocalizedAuditableBehavior; use Sulu\Component\Content\Document\Behavior\LocalizedStructureBehavior; use Sulu\Component\Content\Document\Behavior\StructureBehavior; +use Sulu\Component\Content\Document\Behavior\WorkflowStageBehavior; use Sulu\Component\Content\Document\Extension\ExtensionContainer; use Sulu\Component\Content\Document\Structure\Structure; use Sulu\Component\Content\Document\Structure\StructureInterface; @@ -41,7 +42,8 @@ class ArticleDocument implements LocalizedAuditableBehavior, DateShardingBehavior, RoutableInterface, - ExtensionBehavior + ExtensionBehavior, + WorkflowStageBehavior { /** * @var string @@ -125,6 +127,20 @@ class ArticleDocument implements */ protected $extensions; + /** + * Workflow Stage currently Test or Published. + * + * @var int + */ + protected $workflowStage; + + /** + * Is Document is published. + * + * @var bool + */ + protected $published; + public function __construct() { $this->structure = new Structure(); @@ -359,4 +375,28 @@ public function setExtension($name, $data) { $this->extensions[$name] = $data; } + + /** + * {@inheritdoc} + */ + public function getWorkflowStage() + { + return $this->workflowStage; + } + + /** + * {@inheritdoc} + */ + public function setWorkflowStage($workflowStage) + { + $this->workflowStage = $workflowStage; + } + + /** + * {@inheritdoc} + */ + public function getPublished() + { + return $this->published; + } } diff --git a/Resources/config/serializer/Document.ArticleDocument.xml b/Resources/config/serializer/Document.ArticleDocument.xml index f8fdc096e..4258f37d7 100644 --- a/Resources/config/serializer/Document.ArticleDocument.xml +++ b/Resources/config/serializer/Document.ArticleDocument.xml @@ -25,6 +25,7 @@ + diff --git a/Resources/public/js/components/articles/edit/details/main.js b/Resources/public/js/components/articles/edit/details/main.js index 9b9f52ddb..7a714391c 100644 --- a/Resources/public/js/components/articles/edit/details/main.js +++ b/Resources/public/js/components/articles/edit/details/main.js @@ -46,7 +46,8 @@ define(['underscore', 'jquery', 'config'], function(_, $, Config) { }, listenForChange: function() { - this.sandbox.dom.on(this.$el, 'keyup change', _.debounce(this.setDirty.bind(this), 10), '.trigger-save-button'); + this.sandbox.dom.on(this.$el, 'keyup', _.debounce(this.setDirty.bind(this), 10), 'input, textarea'); + this.sandbox.dom.on(this.$el, 'change', _.debounce(this.setDirty.bind(this), 10), 'input[type="checkbox"], select'); this.sandbox.on('sulu.content.changed', this.setDirty.bind(this)); }, @@ -55,17 +56,15 @@ define(['underscore', 'jquery', 'config'], function(_, $, Config) { this.sandbox.emit('sulu.tab.dirty'); }, - save: function() { + save: function(action) { if (!this.sandbox.form.validate(this.formId)) { return this.sandbox.emit('sulu.tab.dirty', true); } var data = this.sandbox.form.getData(this.formId); data.template = this.template; - this.sandbox.util.save(this.options.url(), !this.data.id ? 'POST' : 'PUT', data).then(function(data) { - this.data = data; - this.sandbox.emit('sulu.tab.saved', data); - }.bind(this)); + + this.sandbox.emit('sulu.articles.save', data, action); }, render: function() { @@ -107,9 +106,7 @@ define(['underscore', 'jquery', 'config'], function(_, $, Config) { }, loadFormTemplate: function(template) { - if (!!template) { - this.setDirty(); - } else { + if (!template) { var types = Config.get('sulu_article.types'); template = types[(this.options.type || this.data.type)]; } diff --git a/Resources/public/js/components/articles/edit/excerpt/main.js b/Resources/public/js/components/articles/edit/excerpt/main.js index 4e1b4d3c7..b8bbceb94 100644 --- a/Resources/public/js/components/articles/edit/excerpt/main.js +++ b/Resources/public/js/components/articles/edit/excerpt/main.js @@ -18,10 +18,7 @@ define([], function() { var content = this.options.data(); content.ext.excerpt = data; - this.sandbox.util.save(this.options.url(), !content.id ? 'POST' : 'PUT', content).then(function(data) { - this.data = data; - this.sandbox.emit('sulu.tab.saved', data); - }.bind(this)); + this.sandbox.emit('sulu.articles.save', data, action); } }; }); diff --git a/Resources/public/js/components/articles/edit/main.js b/Resources/public/js/components/articles/edit/main.js index 8f64c5172..7f714720d 100644 --- a/Resources/public/js/components/articles/edit/main.js +++ b/Resources/public/js/components/articles/edit/main.js @@ -7,7 +7,7 @@ * with this source code in the file LICENSE. */ -define(['jquery', 'underscore'], function($, _) { +define(['jquery', 'underscore', 'sulusecurity/services/user-manager'], function($, _, UserManager) { 'use strict'; @@ -23,14 +23,15 @@ define(['jquery', 'underscore'], function($, _) { }, translations: { - headline: 'sulu_article.edit.title' + headline: 'sulu_article.edit.title', + draftLabel: 'sulu-content.draft-label' } }, header: function() { var buttons = { save: { - parent: 'saveWithOptions' + parent: 'saveWithDraft' }, template: { options: { @@ -76,14 +77,17 @@ define(['jquery', 'underscore'], function($, _) { this.saveState = 'disabled'; this.bindCustomEvents(); + this.showDraftLabel(); }, bindCustomEvents: function() { this.sandbox.on('sulu.header.back', this.toList.bind(this)); - this.sandbox.on('sulu.tab.dirty', this.enableSave.bind(this)); + this.sandbox.on('sulu.tab.dirty', this.setHeaderBar.bind(this)); this.sandbox.on('sulu.toolbar.save', this.save.bind(this)); this.sandbox.on('sulu.toolbar.delete', this.deleteItem.bind(this)); this.sandbox.on('sulu.tab.data-changed', this.setData.bind(this)); + this.sandbox.on('sulu.articles.save', this.saveArticle.bind(this)); + this.sandbox.on('sulu.tab.saved', this.showDraftLabel.bind(this)); this.sandbox.on('sulu.header.language-changed', function(item) { this.sandbox.sulu.saveUserSetting(this.options.config.settingsKey, item.id); @@ -120,7 +124,7 @@ define(['jquery', 'underscore'], function($, _) { save: function(action) { this.loadingSave(); - this.saveTab().then(function(data) { + this.saveTab(action).then(function(data) { this.afterSave(action, data); }.bind(this)); }, @@ -129,7 +133,7 @@ define(['jquery', 'underscore'], function($, _) { this.data = data; }, - saveTab: function() { + saveTab: function(action) { var promise = $.Deferred(); this.sandbox.once('sulu.tab.saved', function(savedData) { @@ -138,27 +142,33 @@ define(['jquery', 'underscore'], function($, _) { promise.resolve(savedData); }.bind(this)); - this.sandbox.emit('sulu.tab.save'); + this.sandbox.emit('sulu.tab.save', action); return promise; }, - enableSave: function(force) { - if (!force && this.saveState === 'loading') { - return; - } - - this.saveState = 'enabled'; - this.sandbox.emit('sulu.header.toolbar.item.enable', 'save', false); + saveArticle: function(data, action) { + return this.sandbox.util.save(this.getUrl(action), !this.data.id ? 'POST' : 'PUT', data).then(function(data) { + this.data = data; + this.sandbox.emit('sulu.tab.saved', data); + }.bind(this)); }, - disableSave: function(force) { - if (!force && this.saveState === 'loading') { - return; - } + setHeaderBar: function(saved) { + var saveDraft = !saved, + savePublish = !saved, + publish = !!saved && !this.data.publishedState; - this.saveState = 'disabled'; - this.sandbox.emit('sulu.header.toolbar.item.disable', 'save', true); + this.setSaveToolbarItems.call(this, 'saveDraft', saveDraft); + this.setSaveToolbarItems.call(this, 'savePublish', savePublish); + this.setSaveToolbarItems.call(this, 'publish', publish); + this.setSaveToolbarItems.call(this, 'save', (!!saveDraft || !!savePublish || !!publish)); + + this.saved = saved; + }, + + setSaveToolbarItems: function(item, value) { + this.sandbox.emit('sulu.header.toolbar.item.' + (!!value ? 'enable' : 'disable'), item, false); }, loadingSave: function() { @@ -167,7 +177,7 @@ define(['jquery', 'underscore'], function($, _) { }, afterSave: function(action, data) { - this.disableSave(true); + this.setHeaderBar(true); this.sandbox.emit('sulu.header.saved', data); if (action === 'back') { @@ -179,6 +189,42 @@ define(['jquery', 'underscore'], function($, _) { } }, + showDraftLabel: function() { + this.sandbox.emit('sulu.header.tabs.label.hide'); + + if (!this.data.id || !!this.data.publishedState) { + return; + } + + this.setHeaderBar(true); + + UserManager.find(this.data.changer).then(function(response) { + this.sandbox.emit( + 'sulu.header.tabs.label.show', + this.sandbox.util.sprintf( + this.sandbox.translate(this.translations.draftLabel), + { + changed: this.sandbox.date.format(this.data.changed, true), + user: response.username + } + ) + ); + }.bind(this)); + }, + + getUrl: function(action) { + var url = _.template(this.defaults.templates.url, { + id: this.options.id, + locale: this.options.locale + }); + + if (action) { + url += '&action=' + action; + } + + return url; + }, + loadComponentData: function() { var promise = $.Deferred(); @@ -188,10 +234,7 @@ define(['jquery', 'underscore'], function($, _) { return promise; } - this.sandbox.util.load(_.template(this.defaults.templates.url, { - id: this.options.id, - locale: this.options.locale - })).done(function(data) { + this.sandbox.util.load(this.getUrl()).done(function(data) { promise.resolve(data); }); diff --git a/Resources/public/js/components/articles/edit/seo/main.js b/Resources/public/js/components/articles/edit/seo/main.js index ff0b46a24..54c0d8a59 100644 --- a/Resources/public/js/components/articles/edit/seo/main.js +++ b/Resources/public/js/components/articles/edit/seo/main.js @@ -29,10 +29,7 @@ define(function() { var content = this.options.data(); content.ext.seo = data; - this.sandbox.util.save(this.options.url(), !content.id ? 'POST' : 'PUT', content).then(function(data) { - this.data = data; - this.sandbox.emit('sulu.tab.saved', data); - }.bind(this)); + this.sandbox.emit('sulu.articles.save', data, action); } }; });