From ea807315417f55f5c48d5d6db7e85e42905191a1 Mon Sep 17 00:00:00 2001
From: pbarroca <pbarroca@afi-sa.fr>
Date: Mon, 2 Oct 2017 17:36:24 +0200
Subject: [PATCH] dev #65265 : versionning plugin refactored

---
 FEATURES/65265                                |  10 ++
 VERSIONS_WIP/65265                            |   1 +
 .../admin/views/scripts/cms/versions.phtml    |  32 +---
 .../admin/views/scripts/widget/versions.phtml |  45 +-----
 .../Plugin/Versionning/Abstract.php           | 144 ++++++++++++++++++
 .../Controller/Plugin/Versionning/Article.php | 110 ++-----------
 .../Controller/Plugin/Versionning/Widget.php  |  95 ++----------
 .../ZendAfi/View/Helper/Admin/Versions.php    |  96 ++++++++++++
 .../View/Helper/Article/RenderAbstract.php    |  44 +++---
 .../ZendAfi/View/Helper/TagEditArticle.php    |  56 +++++--
 .../Versionning/VersionningArticleTest.php    |   2 +-
 11 files changed, 350 insertions(+), 285 deletions(-)
 create mode 100644 FEATURES/65265
 create mode 100644 VERSIONS_WIP/65265
 create mode 100644 library/ZendAfi/Controller/Plugin/Versionning/Abstract.php
 create mode 100644 library/ZendAfi/View/Helper/Admin/Versions.php

diff --git a/FEATURES/65265 b/FEATURES/65265
new file mode 100644
index 00000000000..59abe2a1cb3
--- /dev/null
+++ b/FEATURES/65265
@@ -0,0 +1,10 @@
+        '65265' =>
+            ['Label' => $this->_('Versionning des articles en Front'),
+             'Desc' => '',
+             'Image' => '',
+             'Video' => '',
+             'Category' => '',
+             'Right' => '',
+             'Wiki' => '',
+             'Test' => '',
+             'Date' => '2017-10-02']
\ No newline at end of file
diff --git a/VERSIONS_WIP/65265 b/VERSIONS_WIP/65265
new file mode 100644
index 00000000000..08814730204
--- /dev/null
+++ b/VERSIONS_WIP/65265
@@ -0,0 +1 @@
+ - ticket #65265 : Versionning des articles en Front
\ No newline at end of file
diff --git a/application/modules/admin/views/scripts/cms/versions.phtml b/application/modules/admin/views/scripts/cms/versions.phtml
index 1c336082db3..be1ca7c1662 100644
--- a/application/modules/admin/views/scripts/cms/versions.phtml
+++ b/application/modules/admin/views/scripts/cms/versions.phtml
@@ -1,29 +1,7 @@
 <?php
-$date_formater = function($model, $attrib) {
-  return strftime($this->_('%d %B %Y à %Hh %Mmn %Ss'), $model->get($attrib));
-};
+echo $this
+  ->versions($this->versions,
+             '/admin/cms/version/id/' . $this->model->getId() . '/key/%s',
+             '/admin/cms/version-delete/id/' . $this->model->getId() . '/key/%s');
 
-
-$user_formater = function($model, $attrib) {
-  return ($user = $model->get($attrib)) ? $user->getNomAff() : $this->_('Inconnu');
-};
-
-
-$actions = [['url' => '/admin/cms/version/id/'. $this->article->getId()  .'/key/%s',
-             'icon' => 'view',
-             'label' => $this->_('Voir')],
-            ['url' => '/admin/cms/version-delete/id/'. $this->article->getId()  .'/key/%s',
-             'icon' => 'delete',
-             'label' => $this->_('Supprimer'),
-             'anchorOptions' => ['onclick' => "return confirm('" . htmlspecialchars($this->_('Êtes-vous sur de vouloir supprimer cette version de l\\\'historique ?')) .  "')"]]];
-
-
-echo $this->tagModelTable($this->versions,
-                          [$this->_('Date'), $this->_('Auteur')],
-                          ['Date', 'User'],
-                          [function($model) use($actions)
-                           { return $this->renderModelActions($model, $actions); }],
-                          'versions',
-                          null,
-                          ['Date' => $date_formater,
-                           'User' => $user_formater]);
+echo $this->Button_Back();
diff --git a/application/modules/admin/views/scripts/widget/versions.phtml b/application/modules/admin/views/scripts/widget/versions.phtml
index cfdbc95c3c0..6c307562f10 100644
--- a/application/modules/admin/views/scripts/widget/versions.phtml
+++ b/application/modules/admin/views/scripts/widget/versions.phtml
@@ -1,44 +1,9 @@
 <?php
-$date_formater = function($model, $attrib) {
-  return strftime($this->_('%d %B %Y à %Hh %Mmn %Ss'), $model->get($attrib));
-};
+echo $this
+  ->versions($this->versions,
+             '/admin/widget/version/id_profil/' . $this->model->getProfileId() . '/id/' . $this->model->getId() . '/key/%s',
+             '/admin/widget/version-delete/id_profil/' . $this->model->getProfileId() . '/id/' . $this->model->getId() . '/key/%s'
+  );
 
-$user_formater = function($model, $attrib) {
-  return ($user = $model->get($attrib)) ? $user->getNomAff() : $this->_('Inconnu');
-};
-
-$details = ['url' => '/admin/widget/version/id_profil/' . $this->widget->getProfileId() . '/id/'. $this->widget->getId() .'/key/%s',
-            'icon' => 'view',
-            'label' => $this->_('Voir')];
-
-if ($this->isPopup()) {
-  $details['url'] .= '/render/popup';
-  $details['anchorOptions'] = ['onclick' => 'opacDialogFromUrl(this.href); return false;'];
-}
-
-$confirm = $this->_('Êtes-vous sur de vouloir supprimer cette version de l\\\'historique ?');
-
-$delete = ['url' => '/admin/widget/version-delete/id_profil/'. $this->widget->getProfileId() .'/id/'. $this->widget->getId() .'/key/%s',
-           'icon' => 'delete',
-           'label' => $this->_('Supprimer'),
-           'anchorOptions' => ['onclick' => "return confirm('" . htmlspecialchars($confirm) .  "')"]];
-
-if ($this->isPopup()) {
-  $delete['url'] .= '/render/popup';
-  $delete['anchorOptions'] = ['onclick' => sprintf("if (confirm('%s')) { opacDialogFromUrl(this.href); }; return false;",
-                                                   htmlspecialchars($confirm))];
-}
-
-$actions = [$details, $delete];
-
-echo $this->tagModelTable($this->versions,
-                          [$this->_('Date'), $this->_('Auteur')],
-                          ['Date', 'User'],
-                          [function($model) use($actions)
-                           { return $this->renderModelActions($model, $actions); }],
-                          'versions',
-                          null,
-                          ['Date' => $date_formater,
-                           'User' => $user_formater]);
 
 echo $this->Button_Back();
diff --git a/library/ZendAfi/Controller/Plugin/Versionning/Abstract.php b/library/ZendAfi/Controller/Plugin/Versionning/Abstract.php
new file mode 100644
index 00000000000..c4787e3d675
--- /dev/null
+++ b/library/ZendAfi/Controller/Plugin/Versionning/Abstract.php
@@ -0,0 +1,144 @@
+<?php
+/**
+ * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+abstract class ZendAfi_Controller_Plugin_Versionning_Abstract
+  extends ZendAfi_Controller_Plugin_Abstract {
+
+  public function visitGetForm($closure) {
+    $this->_get_form_closure = $closure;
+    return $this;
+  }
+
+
+  public function versionsAction() {
+    if (!$model = $this->_loadModel())
+      return $this->_redirectCloseReferer();
+
+    if (!$versions = $this->_versionsFor($model)->findAll())
+      return $this->_notifyToReferer($this->_('Aucune version dans l\'historique'));
+
+    $this->_view->titre = $this->_('Versions de : "%s"', $this->_modelLabel($model));
+    $this->_view->versions = $versions;
+    $this->_view->model = $model;
+  }
+
+
+  public function versionAction() {
+    if (!$model = $this->_loadModel())
+      return $this->_redirectCloseReferer();
+
+    if (!$key = $this->_getParam('key'))
+      $key = $this->_versionsFor($model)->findLastKey();
+
+    if (!$version = $this->_versionsFor($model)->find($key))
+      return $this->_notifyToReferer($this->_('Aucune version dans l\'historique'));
+
+    $this->_view->titre = $this->_('Version de : "%s"', $this->_modelLabel($model));
+    $this->_view->version = $version;
+    $form = call_user_func($this->_get_form_closure, $model);
+    $form->beVersionCompare($version->getData());
+
+    $this->_view->form = $form;
+  }
+
+
+  public function versionApplyAction() {
+    if (!$model = $this->_loadModel())
+      return $this->_redirectCloseReferer();
+
+    if (!$version = $this->_versionsFor($model)->find($this->_getParam('key')))
+      return $this->_notifyToReferer($this->_('Version introuvable'));
+
+    $version->injectIn($this->_request);
+    $this->_forwardToEdit($model);
+  }
+
+
+  public function versionDeleteAction() {
+    if (!$model = $this->_loadModel())
+      return $this->_redirectCloseReferer();
+
+    if (!$version = $this->_versionsFor($model)->find($this->_getParam('key')))
+      return $this->_notifyToReferer($this->_('Version introuvable'));
+
+    $version->delete();
+    $this->_notify($this->_('Version supprimée'));
+
+    $this->_view->isPopup()
+      ? $this->_redirectCloseReferer()
+      : $this->_redirect($this->_versionUrl($model));
+  }
+
+
+  public function notifyAfterDelete($model) {
+    $this->_versionsFor($model)->clear();
+  }
+
+
+  public function notifyAfterSave($model) {
+    $this->_versionsFor($model)
+         ->newInstance()
+         ->setData($this->_getPost())
+         ->save();
+  }
+
+
+  protected function _notifyToReferer($message) {
+    $this->_notify($message);
+    $this->_redirectCloseReferer();
+  }
+
+
+  protected function _redirectCloseReferer() {
+    $this->_redirectClose($this->_getReferer());
+  }
+
+
+  protected function _notify($message) {
+    $this->_helper->notify($message);
+  }
+
+
+  protected function _loadModel() {
+    return;
+  }
+
+
+  protected function _modelLabel($model) {
+    return '';
+  }
+
+
+  protected function _versionsFor($model) {
+    return null;
+  }
+
+
+  protected function _forwardToEdit($model) {
+
+  }
+
+
+  protected function _versionUrl($model) {
+    return '';
+  }
+}
diff --git a/library/ZendAfi/Controller/Plugin/Versionning/Article.php b/library/ZendAfi/Controller/Plugin/Versionning/Article.php
index 7fed31379f3..7fc25568bfd 100644
--- a/library/ZendAfi/Controller/Plugin/Versionning/Article.php
+++ b/library/ZendAfi/Controller/Plugin/Versionning/Article.php
@@ -21,7 +21,7 @@
 
 
 class ZendAfi_Controller_Plugin_Versionning_Article
-  extends ZendAfi_Controller_Plugin_Abstract {
+  extends ZendAfi_Controller_Plugin_Versionning_Abstract {
 
   public function getActions($model) {
     if ('Class_Article' != get_class($model))
@@ -55,115 +55,27 @@ class ZendAfi_Controller_Plugin_Versionning_Article
   }
 
 
-  public function visitGetForm($closure) {
-    $this->_get_form_closure = $closure;
-    return $this;
+  protected function _loadModel() {
+    return Class_Article::find((int)$this->_getParam('id'));
   }
 
 
-  public function versionsAction() {
-    if (!$article = Class_Article::find((int)$this->_getParam('id'))) {
-      $this->_redirectToIndex();
-      return;
-    }
-
-    $this->_view->titre = $this->_('Versions de l\'article : "%s"',
-                                   $article->getTitre());
-
-    if (!$versions = $this->_versionsFor($article)->findAll()) {
-      $this->_helper->notify($this->_('Aucune version dans l\'historique'));
-      $this->_redirect('admin/cms/edit/id/' . $article->getId());
-      return;
-    }
-
-    $this->_view->versions = $this->_versionsFor($article)->findAll();
-    $this->_view->article = $article;
-  }
-
-
-  public function versionAction() {
-    if (!$article = Class_Article::find((int)$this->_getParam('id'))) {
-      $this->_redirectToIndex();
-      return;
-    }
-
-    if (!$key = $this->_getParam('key'))
-      $key = $this->_versionsFor($article)->findLastKey();
-
-    if (!$version = $this->_versionsFor($article)->find($key)) {
-      $this->_helper->notify($this->_('Aucune version dans l\'historique'));
-      $this->_redirectToEdit($article);
-      return;
-    }
-
-    $this->_view->titre = $this->_('Version de l\'article : "%s"',
-                                   $article->getTitre());
-
-    $this->_view->version = $version;
-    $form = call_user_func($this->_get_form_closure, $article);
-    $form->setAttrib('data-backurl', $this->_view->url(['action' => 'edit',
-                                                        'key' => null]))
-         ->beVersionCompare($version->getData());
-
-    $this->_view->form = $form;
-  }
-
-
-  public function versionApplyAction() {
-    if (!$article = Class_Article::find((int)$this->_getParam('id'))) {
-      $this->_redirectToIndex();
-      return;
-    }
-
-    if (!$version = $this->_versionsFor($article)->find($this->_getParam('key'))) {
-      $this->_helper->notify($this->_view->_('Version introuvable'));
-      $this->_redirectToEdit($article);
-      return;
-    }
-
-    $version->injectIn($this->_request);
-    $this->_forward('edit', 'cms', 'admin', ['id' => $article->getId()]);
-  }
-
-
-  public function versionDeleteAction() {
-    if (!$article = Class_Article::find((int)$this->_getParam('id'))) {
-      $this->_redirectToIndex();
-      return;
-    }
-
-    if (!$version = $this->_versionsFor($article)->find($this->_getParam('key'))) {
-      $this->_helper->notify($this->_view->_('Version introuvable'));
-      $this->_redirectToEdit($article);
-      return;
-    }
-
-    $version->delete();
-    $this->_helper->notify($this->_view->_('Version supprimée'));
-    $this->_redirect('admin/cms/version/id/' . $article->getId());
+  protected function _modelLabel($model) {
+    return $model->getTitre();
   }
 
 
-  public function notifyAfterSave($model) {
-    $this->_versionsFor($model)
-         ->newInstance()
-         ->setData($this->_getPost())
-         ->save();
-  }
-
-
-  public function notifyAfterDelete($model) {
-    $this->_versionsFor($model)
-         ->clear();
+  protected function _versionsFor($model) {
+    return Class_Versions::forArticle($model);
   }
 
 
-  protected function _redirectToEdit($article) {
-    $this->_redirect('admin/cms/edit/id/' . $article->getId());
+  protected function _forwardToEdit($model) {
+    $this->_forward('edit', 'cms', 'admin', ['id' => $model->getId()]);
   }
 
 
-  protected function _versionsFor($model) {
-    return Class_Versions::forArticle($model);
+  protected function _versionUrl($model) {
+    return '/admin/cms/version/id/' . $model->getId();
   }
 }
diff --git a/library/ZendAfi/Controller/Plugin/Versionning/Widget.php b/library/ZendAfi/Controller/Plugin/Versionning/Widget.php
index 62c3aed9ca6..78072aec395 100644
--- a/library/ZendAfi/Controller/Plugin/Versionning/Widget.php
+++ b/library/ZendAfi/Controller/Plugin/Versionning/Widget.php
@@ -21,85 +21,7 @@
 
 
 class ZendAfi_Controller_Plugin_Versionning_Widget
-  extends ZendAfi_Controller_Plugin_Abstract {
-
-  public function visitGetForm($closure) {
-    $this->_get_form_closure = $closure;
-    return $this;
-  }
-
-
-  public function versionsAction() {
-    if (!$widget = $this->_loadWidget()) {
-      $this->_redirectClose($this->_getReferer());
-      return;
-    }
-
-    $this->_view->titre = $this->_('Versions de : "%s"',
-                                   $widget->getTitle());
-
-    if (!$versions = $this->_versionsFor($widget)->findAll()) {
-      $this->_helper->notify($this->_('Aucune version dans l\'historique'));
-      $this->_redirectClose($this->_getReferer());
-      return;
-    }
-
-    $this->_view->versions = $versions;
-    $this->_view->widget = $widget;
-  }
-
-
-  public function versionAction() {
-    if (!$widget = $this->_loadWidget())
-      return $this->_redirectClose($this->_getReferer());
-
-    if (!$key = $this->_getParam('key'))
-      $key = $this->_versionsFor($widget)->findLastKey();
-
-    if (!$version = $this->_versionsFor($widget)->find($key)) {
-      $this->_helper->notify($this->_('Aucune version dans l\'historique'));
-      return $this->_redirectClose($this->_getReferer());
-    }
-
-    $this->_view->titre = $this->_('Version de : "%s"', $widget->getTitle());
-
-    $this->_view->version = $version;
-    $form = call_user_func($this->_get_form_closure, $widget);
-    $form->beVersionCompare($version->getData());
-
-    $this->_view->form = $form;
-  }
-
-
-  public function versionApplyAction() {
-    if (!$widget = $this->_loadWidget())
-      return $this->_redirectClose($this->_getReferer());
-
-    if (!$version = $this->_versionsFor($widget)->find($this->_getParam('key'))) {
-      $this->_helper->notify($this->_view->_('Version introuvable'));
-      return $this->_redirectClose($this->_getReferer());
-    }
-
-    $version->injectIn($this->_request);
-    $this->_forward('edit-widget', 'widget', 'admin');
-  }
-
-
-  public function versionDeleteAction() {
-    if (!$widget = $this->_loadWidget())
-      return $this->_redirectClose($this->_getReferer());
-
-    if (!$version = $this->_versionsFor($widget)->find($this->_getParam('key'))) {
-      $this->_helper->notify($this->_view->_('Version introuvable'));
-      return $this->_redirectClose($this->_getReferer());
-    }
-
-    $version->delete();
-
-    $this->_helper->notify($this->_view->_('Version supprimée'));
-    $this->_redirectClose($this->_getReferer());
-  }
-
+  extends ZendAfi_Controller_Plugin_Versionning_Abstract {
 
   public function notifyAfterSave($model) {
     if (!$model->shouldVersion())
@@ -116,8 +38,7 @@ class ZendAfi_Controller_Plugin_Versionning_Widget
     if (!$model->shouldVersion())
       return;
 
-    $this->_versionsFor($model)
-         ->clear();
+    parent::notifyAfterDelete($model);
   }
 
 
@@ -126,10 +47,20 @@ class ZendAfi_Controller_Plugin_Versionning_Widget
   }
 
 
-  protected function _loadWidget() {
+  protected function _loadModel() {
     return (new Class_Systeme_Widget_Widget())
       ->setId($this->_getParam('id'))
       ->setProfileId($this->_getParam('id_profil'))
       ->load();
   }
+
+
+  protected function _modelLabel($model) {
+    return $model->getTitle();
+  }
+
+
+  protected function _forwardToEdit($model) {
+    $this->_forward('edit-widget', 'widget', 'admin');
+  }
 }
diff --git a/library/ZendAfi/View/Helper/Admin/Versions.php b/library/ZendAfi/View/Helper/Admin/Versions.php
new file mode 100644
index 00000000000..74fb43c2d34
--- /dev/null
+++ b/library/ZendAfi/View/Helper/Admin/Versions.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class ZendAfi_View_Helper_Admin_Versions extends ZendAfi_View_Helper_BaseHelper {
+  protected
+    $_view_url,
+    $_delete_url;
+
+  public function versions($versions, $view_url, $delete_url) {
+    $this->_view_url = $view_url;
+    $this->_delete_url = $delete_url;
+
+    $description = (new Class_TableDescription('versions'))
+      ->addColumn($this->_('Date'), ['attribute' => 'Date',
+                                     'callback' => [$this, 'dateFormat']])
+
+      ->addColumn($this->_('Auteur'), ['attribute' => 'User',
+                                       'callback' => [$this, 'userFormat']])
+
+      ->addRowAction(function($model)
+                     {
+                       return $this->view->renderModelActions($model, $this->actions());
+                     })
+      ;
+
+    return $this->view->renderTable($description, $versions, ['sorter' => true]);
+  }
+
+
+  public function dateFormat($model, $attrib) {
+    return strftime($this->_('%d %B %Y à %Hh %Mmn %Ss'), $model->get($attrib));
+  }
+
+
+  public function userFormat($model, $attrib) {
+    return ($user = $model->get($attrib)) ? $user->getNomAff() : $this->_('Inconnu');
+  }
+
+
+  public function actions() {
+    return [ $this->detailAction(), $this->deleteAction() ];
+  }
+
+
+  public function detailAction() {
+    $action = ['url' => $this->_view_url,
+               'icon' => 'view',
+               'label' => $this->_('Voir')];
+
+    if (!$this->view->isPopup())
+      return $action;
+
+    $action['url'] .= '/render/popup';
+    $action['anchorOptions'] = ['onclick' => 'opacDialogFromUrl(this.href); return false;'];
+
+    return $action;
+  }
+
+
+  public function deleteAction() {
+    $message = htmlspecialchars($this->_('Êtes-vous sur de vouloir supprimer cette version de l\\\'historique ?'));
+
+    $action = ['url' => $this->_delete_url,
+               'icon' => 'delete',
+               'label' => $this->_('Supprimer'),
+               'anchorOptions' => ['onclick' => "return confirm('" . $message .  "')"]];
+
+    if (!$this->view->isPopup())
+      return $action;
+
+    $action['url'] .= '/render/popup';
+    $action['anchorOptions']  = ['onclick' => sprintf("if (confirm('%s')) { opacDialogClose(); opacDialogFromUrl(this.href); }; return false;",
+                                                      $message)];
+
+    return $action;
+  }
+}
diff --git a/library/ZendAfi/View/Helper/Article/RenderAbstract.php b/library/ZendAfi/View/Helper/Article/RenderAbstract.php
index 28adc8325d8..e75025529e2 100644
--- a/library/ZendAfi/View/Helper/Article/RenderAbstract.php
+++ b/library/ZendAfi/View/Helper/Article/RenderAbstract.php
@@ -18,30 +18,30 @@
  * along with BOKEH; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
-abstract class ZendAfi_View_Helper_Article_RenderAbstract extends ZendAfi_View_Helper_BaseHelper {
+abstract class ZendAfi_View_Helper_Article_RenderAbstract
+  extends ZendAfi_View_Helper_BaseHelper {
+
   public function renderArticle($article, $html_class = 'article') {
+    $content = '<!-- RSPEAK_START -->'
+      . $this->_tag('header',
+                    $this->view->tagEditArticle($article)
+                    . $this->renderReadSpeaker($article)
+                    . $this->renderTitreHeader($article)
+                    . $this->renderDraftStatus($article)
+                    . $this->renderArticleInfo($article)
+                    . $this->tagArticleEvent($article))
+      . $this->_tag('div', $this->renderContent($article),
+                    ['class' => 'article_content'])
+      . $this->_tag('footer',
+                    $this->renderLieu($article)
+                    .$this->renderReseauxSociaux($article)
+                    .$this->renderAvis($article))
+      . '<!-- RSPEAK_STOP -->';
+
     return
-      $this->renderArticleHTML(
-        '<article class="auto_resize '.$html_class.'"><!-- RSPEAK_START -->'
-        .'<header>'
-        .$this->view->tagEditArticle($article)
-        .$this->renderReadSpeaker($article)
-        .$this->renderTitreHeader($article)
-        .$this->renderDraftStatus($article)
-        .$this->renderArticleInfo($article)
-        .$this->tagArticleEvent($article)
-        .'</header>'
-        .'<div class="article_content">'
-        .$this->renderContent($article)
-        .'</div>'
-        .'<footer>'
-        .$this->renderLieu($article)
-        .$this->renderReseauxSociaux($article)
-        .$this->renderAvis($article)
-        .'</footer>'
-        .'<!-- RSPEAK_STOP --></article>',
-
-        $article);
+      $this->renderArticleHTML($this->_tag('article', $content,
+                                           ['class' => 'auto_resize '.$html_class]),
+                               $article);
   }
 
 
diff --git a/library/ZendAfi/View/Helper/TagEditArticle.php b/library/ZendAfi/View/Helper/TagEditArticle.php
index cbd088b4468..6beb6f36066 100644
--- a/library/ZendAfi/View/Helper/TagEditArticle.php
+++ b/library/ZendAfi/View/Helper/TagEditArticle.php
@@ -18,26 +18,54 @@
  * along with BOKEH; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
  */
-class ZendAfi_View_Helper_TagEditArticle extends Zend_View_Helper_HtmlElement {
+class ZendAfi_View_Helper_TagEditArticle extends ZendAfi_View_Helper_BaseHelper {
+  protected
+    $_article,
+    $_current_skin;
+
   /**
    * @param Class_Article $article
    * @return string
    */
   public function tagEditArticle($article) {
-    if (!Class_Users::getLoader()->isCurrentUserCanEditArticle($article))
+    $this->_current_skin = Class_Admin_Skin::current();
+    $this->_article = $article;
+
+    if (!Class_Users::isCurrentUserCanEditArticle($article))
+      return '';
+
+    return $this->_renderEdit() . $this->_renderVersion();
+  }
+
+
+  protected function _renderEdit() {
+    return $this
+      ->_renderActionLink('edit', $this->_('Modifier l\'article'),
+                          ['module' => 'admin',
+                           'controller' => 'cms',
+                           'action' => 'edit',
+                           'id' => $this->_article->getId()]);
+  }
+
+
+  protected function _renderVersion() {
+    if (0 == Class_Versions::forArticle($this->_article)->count())
       return '';
 
-    return $this->view->tagAnchor($this->view->url(['module' => 'admin',
-                                                    'controller' => 'cms',
-                                                    'action' => 'edit',
-                                                    'id' => $article->getId()]),
-                                  Class_Admin_Skin::current()
-                                  ->renderActionIconOn('edit', $this->view,
-                                                       ['class' => 'article_edit',
-                                                        'alt' => $this->view->translate("Modifier l'article"),
-                                                        'title' => $this->view->translate("Modifier l'article")]),
-                                  ['class' => 'edit_article',
-                                   'data-popup' => 'true']);
+    return $this
+      ->_renderActionLink('batch', $this->_('Historique des modifications'),
+                          ['module' => 'admin',
+                           'controller' => 'cms',
+                           'action' => 'version',
+                           'id' => $this->_article->getId()]);
+  }
+
+
+  protected function _renderActionLink($icon, $label, $url) {
+    $icon = $this->_current_skin
+      ->renderActionIconOn($icon, $this->view, ['alt' => $label]);
+
+    return $this->view->tagAnchor($url, $icon,
+                                  ['data-popup' => 'true', 'title' => $label]);
   }
 }
-?>
\ No newline at end of file
diff --git a/tests/scenarios/Versionning/VersionningArticleTest.php b/tests/scenarios/Versionning/VersionningArticleTest.php
index c83110f03e7..8925925e9b0 100644
--- a/tests/scenarios/Versionning/VersionningArticleTest.php
+++ b/tests/scenarios/Versionning/VersionningArticleTest.php
@@ -95,7 +95,7 @@ class VersionningArticleVersionsTest extends VersionningAdminTestCase {
 
   /** @test */
   public function titleShouldBeVersionDuProfilAProfile() {
-    $this->assertXPathContentContains('//h1', 'Versions de l\'article : "An article"');
+    $this->assertXPathContentContains('//h1', 'Versions de : "An article"');
   }
 
 
-- 
GitLab