From e0ec4d990b50a2a816164ae8f6863adf6184d340 Mon Sep 17 00:00:00 2001 From: pawbuj Date: Mon, 4 Mar 2019 16:30:37 +0100 Subject: [PATCH] EZP-30139: As an editor I want to hide and reveal a content item (#865) * EZP-30139: As an editor I want to hide and reveal a content item * cs fixes and refactoring * fixes js cs * cs fixes * more cs fixes * cs fixes * fix * fixes --- src/bundle/Controller/ContentController.php | 80 ++++++++++++++++- .../Controller/ContentViewController.php | 31 +++++++ src/bundle/Resources/config/routing.yml | 6 ++ src/bundle/Resources/encore/ez.js.config.js | 2 + src/bundle/Resources/public/img/ez-icons.svg | 7 ++ .../Resources/public/img/icons/hide.svg | 4 + .../Resources/public/img/icons/reveal.svg | 5 ++ .../js/scripts/sidebar/btn/content.hide.js | 30 +++++++ .../js/scripts/sidebar/btn/content.reveal.js | 18 ++++ src/bundle/Resources/public/scss/_alerts.scss | 4 +- src/bundle/Resources/public/scss/_mixins.scss | 5 ++ src/bundle/Resources/public/scss/_modals.scss | 7 ++ .../Resources/translations/content.en.xliff | 20 +++++ .../translations/locationview.en.xliff | 35 ++++++-- .../Resources/translations/menu.en.xliff | 12 ++- .../views/content/locationview.html.twig | 14 +++ .../modal_content_hide_confirmation.html.twig | 26 ++++++ .../views/content/tab/locations/tab.html.twig | 37 ++++---- .../Content/ContentVisibilityUpdateData.php | 89 +++++++++++++++++++ .../Content/ContentVisibilityUpdateType.php | 50 +++++++++++ src/lib/Menu/ContentRightSidebarBuilder.php | 48 ++++++++++ src/lib/Tab/LocationView/LocationsTab.php | 2 +- 22 files changed, 502 insertions(+), 30 deletions(-) create mode 100644 src/bundle/Resources/public/img/icons/hide.svg create mode 100644 src/bundle/Resources/public/img/icons/reveal.svg create mode 100644 src/bundle/Resources/public/js/scripts/sidebar/btn/content.hide.js create mode 100644 src/bundle/Resources/public/js/scripts/sidebar/btn/content.reveal.js create mode 100644 src/bundle/Resources/views/content/modal_content_hide_confirmation.html.twig create mode 100644 src/lib/Form/Data/Content/ContentVisibilityUpdateData.php create mode 100644 src/lib/Form/Type/Content/ContentVisibilityUpdateType.php diff --git a/src/bundle/Controller/ContentController.php b/src/bundle/Controller/ContentController.php index ce62d4595c..52282d3b83 100644 --- a/src/bundle/Controller/ContentController.php +++ b/src/bundle/Controller/ContentController.php @@ -15,6 +15,7 @@ use eZ\Publish\API\Repository\Values\Content\Location; use eZ\Publish\Core\Base\Exceptions\BadStateException; use EzSystems\EzPlatformAdminUi\Exception\InvalidArgumentException as AdminInvalidArgumentException; +use EzSystems\EzPlatformAdminUi\Form\Data\Content\ContentVisibilityUpdateData; use EzSystems\EzPlatformAdminUi\Form\Data\Content\Draft\ContentCreateData; use EzSystems\EzPlatformAdminUi\Form\Data\Content\Draft\ContentEditData; use EzSystems\EzPlatformAdminUi\Form\Data\Content\Location\ContentMainLocationUpdateData; @@ -23,6 +24,7 @@ use EzSystems\EzPlatformAdminUi\Form\DataMapper\MainTranslationUpdateMapper; use EzSystems\EzPlatformAdminUi\Form\Factory\FormFactory; use EzSystems\EzPlatformAdminUi\Form\SubmitHandler; +use EzSystems\EzPlatformAdminUi\Form\Type\Content\ContentVisibilityUpdateType; use EzSystems\EzPlatformAdminUi\Form\Type\Content\Translation\MainTranslationUpdateType; use EzSystems\EzPlatformAdminUi\Notification\NotificationHandlerInterface; use EzSystems\EzPlatformAdminUi\Siteaccess\SiteaccessResolverInterface; @@ -279,9 +281,9 @@ public function updateMainLocationAction(Request $request): Response if (null !== $contentInfo) { return new RedirectResponse($this->generateUrl('_ezpublishLocation', [ - 'locationId' => $contentInfo->mainLocationId, - '_fragment' => 'ez-tab-location-view-locations', - ])); + 'locationId' => $contentInfo->mainLocationId, + '_fragment' => 'ez-tab-location-view-locations', + ])); } return $this->redirectToRoute('ezplatform.dashboard'); @@ -381,4 +383,76 @@ public function updateMainTranslationAction(Request $request): Response return $this->redirectToRoute('ezplatform.dashboard'); } + + /** + * @param Symfony\Component\HttpFoundation\Request $request + * + * @return \Symfony\Component\HttpFoundation\Response + */ + public function updateVisibilityAction(Request $request): Response + { + $form = $this->createForm(ContentVisibilityUpdateType::class); + $form->handleRequest($request); + $result = null; + + if ($form->isSubmitted()) { + $result = $this->submitHandler->handle($form, function (ContentVisibilityUpdateData $data) { + $contentInfo = $data->getContentInfo(); + $desiredVisibility = $data->getVisible(); + $location = $data->getLocation(); + + if ($contentInfo->isHidden && $desiredVisibility === false) { + $this->notificationHandler->success( + $this->translator->trans( + /** @Desc("Content '%name%' was already hidden.") */ + 'content.hide.already_hidden', + ['%name%' => $contentInfo->name], + 'content' + ) + ); + } + + if (!$contentInfo->isHidden && $desiredVisibility === true) { + $this->notificationHandler->success( + $this->translator->trans( + /** @Desc("Content '%name%' was already visible.") */ + 'content.reveal.already_visible', + ['%name%' => $contentInfo->name], + 'content' + ) + ); + } + + if (!$contentInfo->isHidden && $desiredVisibility === false) { + $this->contentService->hideContent($contentInfo); + + $this->notificationHandler->success( + $this->translator->trans( + /** @Desc("Content '%name%' has been hidden.") */ + 'content.hide.success', + ['%name%' => $contentInfo->name], + 'content' + ) + ); + } + + if ($contentInfo->isHidden && $desiredVisibility === true) { + $this->contentService->revealContent($contentInfo); + + $this->notificationHandler->success( + $this->translator->trans( + /** @Desc("Content '%name%' has been revealed.") */ + 'content.reveal.success', + ['%name%' => $contentInfo->name], + 'content' + ) + ); + } + + return $location === null ? $this->redirectToRoute('ezplatform.dashboard') : $this->redirectToLocation($location); + }); + } + + return $result instanceof Response ? $result : $this->redirectToRoute('ezplatform.dashboard'); + } } diff --git a/src/bundle/Controller/ContentViewController.php b/src/bundle/Controller/ContentViewController.php index 123c18937d..80247d7437 100644 --- a/src/bundle/Controller/ContentViewController.php +++ b/src/bundle/Controller/ContentViewController.php @@ -20,6 +20,7 @@ use eZ\Publish\API\Repository\UserService; use eZ\Publish\Core\MVC\Symfony\Locale\UserLanguagePreferenceProviderInterface; use eZ\Publish\Core\MVC\Symfony\View\ContentView; +use EzSystems\EzPlatformAdminUi\Form\Data\Content\ContentVisibilityUpdateData; use EzSystems\EzPlatformAdminUi\Form\Data\Content\Draft\ContentCreateData; use EzSystems\EzPlatformAdminUi\Form\Data\Content\Draft\ContentEditData; use EzSystems\EzPlatformAdminUi\Form\Data\Location\LocationCopyData; @@ -31,6 +32,7 @@ use EzSystems\EzPlatformAdminUi\Form\Data\User\UserDeleteData; use EzSystems\EzPlatformAdminUi\Form\Data\User\UserEditData; use EzSystems\EzPlatformAdminUi\Form\Factory\FormFactory; +use EzSystems\EzPlatformAdminUi\Form\Type\Content\ContentVisibilityUpdateType; use EzSystems\EzPlatformAdminUi\Specification\Content\ContentHaveAssetRelation; use EzSystems\EzPlatformAdminUi\Specification\Content\ContentHaveUniqueRelation; use EzSystems\EzPlatformAdminUi\Specification\ContentIsUser; @@ -38,6 +40,7 @@ use EzSystems\EzPlatformAdminUi\Specification\Location\IsContainer; use EzSystems\EzPlatformAdminUi\UI\Module\Subitems\ContentViewParameterSupplier as SubitemsContentViewParameterSupplier; use EzSystems\EzPlatformAdminUi\UI\Service\PathService; +use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\HttpFoundation\Request; @@ -91,6 +94,9 @@ class ContentViewController extends Controller /** @var \eZ\Publish\Core\MVC\Symfony\Locale\UserLanguagePreferenceProviderInterface */ private $userLanguagePreferenceProvider; + /** @var \Symfony\Component\Form\FormFactoryInterface */ + private $sfFormFactory; + /** * @param \eZ\Publish\API\Repository\ContentTypeService $contentTypeService * @param \eZ\Publish\API\Repository\LanguageService $languageService @@ -114,6 +120,7 @@ public function __construct( LanguageService $languageService, PathService $pathService, FormFactory $formFactory, + FormFactoryInterface $sfFormFactory, SubitemsContentViewParameterSupplier $subitemsContentViewParameterSupplier, UserService $userService, BookmarkService $bookmarkService, @@ -131,6 +138,7 @@ public function __construct( $this->languageService = $languageService; $this->pathService = $pathService; $this->formFactory = $formFactory; + $this->sfFormFactory = $sfFormFactory; $this->subitemsContentViewParameterSupplier = $subitemsContentViewParameterSupplier; $this->userService = $userService; $this->bookmarkService = $bookmarkService; @@ -178,6 +186,8 @@ public function locationViewAction(Request $request, ContentView $view): Content $this->supplyIsLocationBookmarked($view); + $this->supplyContentReverseRelations($view); + return $view; } @@ -258,10 +268,20 @@ private function supplyContentActionForms(ContentView $view): void new LocationCopySubtreeData($location) ); + $contentVisibilityUpdateForm = $this->sfFormFactory->create( + ContentVisibilityUpdateType::class, + new ContentVisibilityUpdateData( + $location->getContentInfo(), + $location, + $location->getContentInfo()->isHidden + ) + ); + $view->addParameters([ 'form_location_copy' => $locationCopyType->createView(), 'form_location_move' => $locationMoveType->createView(), 'form_content_create' => $contentCreateType->createView(), + 'form_content_visibility_update' => $contentVisibilityUpdateForm->createView(), 'form_subitems_content_edit' => $subitemsContentEdit->createView(), 'form_location_copy_subtree' => $locationCopySubtreeType->createView(), ]); @@ -462,4 +482,15 @@ private function supplyIsLocationBookmarked(ContentView $view): void $view->addParameters(['location_is_bookmarked' => $locationIsBookmarked]); } + + /** + * @param \eZ\Publish\Core\MVC\Symfony\View\ContentView $view + */ + private function supplyContentReverseRelations(ContentView $view): void + { + $contentInfo = $view->getLocation()->getContentInfo(); + $relations = $this->contentService->loadReverseRelations($contentInfo); + + $view->addParameters(['content_has_reverse_relations' => count($relations) > 0]); + } } diff --git a/src/bundle/Resources/config/routing.yml b/src/bundle/Resources/config/routing.yml index 33b2cc6ec9..40f069194d 100644 --- a/src/bundle/Resources/config/routing.yml +++ b/src/bundle/Resources/config/routing.yml @@ -465,6 +465,12 @@ ezplatform.content.update_main_translation: defaults: _controller: 'EzPlatformAdminUiBundle:Content:updateMainTranslation' +ezplatform.content.update_visibility: + path: /content/update-visibility + methods: ['POST'] + defaults: + _controller: 'EzPlatformAdminUiBundle:Content:updateVisibility' + # LocationView / Versions tab ezplatform.version.remove: diff --git a/src/bundle/Resources/encore/ez.js.config.js b/src/bundle/Resources/encore/ez.js.config.js index 7cdd3f58d5..9f264e4e47 100644 --- a/src/bundle/Resources/encore/ez.js.config.js +++ b/src/bundle/Resources/encore/ez.js.config.js @@ -185,6 +185,8 @@ module.exports = (Encore) => { path.resolve('./vendor/ezsystems/ezplatform-admin-ui-assets/Resources/public/vendors/leaflet/dist/leaflet.js'), path.resolve(__dirname, '../public/js/scripts/admin.location.load.map.js'), path.resolve(__dirname, '../public/js/scripts/sidebar/btn/content.edit.js'), + path.resolve(__dirname, '../public/js/scripts/sidebar/btn/content.hide.js'), + path.resolve(__dirname, '../public/js/scripts/sidebar/btn/content.reveal.js'), path.resolve(__dirname, '../public/js/scripts/admin.location.add.custom_url.js'), path.resolve(__dirname, '../public/js/scripts/button.state.toggle.js'), path.resolve(__dirname, '../public/js/scripts/admin.version.edit.conflict.js'), diff --git a/src/bundle/Resources/public/img/ez-icons.svg b/src/bundle/Resources/public/img/ez-icons.svg index bee6033ed7..3fb89adc67 100644 --- a/src/bundle/Resources/public/img/ez-icons.svg +++ b/src/bundle/Resources/public/img/ez-icons.svg @@ -272,6 +272,9 @@ + + + @@ -470,6 +473,10 @@ + + + + diff --git a/src/bundle/Resources/public/img/icons/hide.svg b/src/bundle/Resources/public/img/icons/hide.svg new file mode 100644 index 0000000000..20826df32f --- /dev/null +++ b/src/bundle/Resources/public/img/icons/hide.svg @@ -0,0 +1,4 @@ + +hide + + diff --git a/src/bundle/Resources/public/img/icons/reveal.svg b/src/bundle/Resources/public/img/icons/reveal.svg new file mode 100644 index 0000000000..14257215c1 --- /dev/null +++ b/src/bundle/Resources/public/img/icons/reveal.svg @@ -0,0 +1,5 @@ + +reveal + + + diff --git a/src/bundle/Resources/public/js/scripts/sidebar/btn/content.hide.js b/src/bundle/Resources/public/js/scripts/sidebar/btn/content.hide.js new file mode 100644 index 0000000000..3b04e4eeb0 --- /dev/null +++ b/src/bundle/Resources/public/js/scripts/sidebar/btn/content.hide.js @@ -0,0 +1,30 @@ +(function(global, doc, $) { + const hideButton = doc.querySelector('.ez-btn--hide'); + const modal = doc.querySelector('#hide-content-modal'); + const form = doc.querySelector('form[name="content_visibility_update"]'); + const visiblity = doc.querySelector('#content_visibility_update_visible'); + + if (!hideButton) { + return; + } + + if (modal) { + modal.querySelector('.btn-confirm').addEventListener('click', () => { + visiblity.value = 0; + form.submit(); + }); + } + + hideButton.addEventListener( + 'click', + () => { + if (modal) { + $(modal).modal('show'); + } else { + visiblity.value = 0; + form.submit(); + } + }, + false + ); +})(window, document, window.jQuery); diff --git a/src/bundle/Resources/public/js/scripts/sidebar/btn/content.reveal.js b/src/bundle/Resources/public/js/scripts/sidebar/btn/content.reveal.js new file mode 100644 index 0000000000..b2720e6e4a --- /dev/null +++ b/src/bundle/Resources/public/js/scripts/sidebar/btn/content.reveal.js @@ -0,0 +1,18 @@ +(function(global, doc) { + const revealButton = doc.querySelector('.ez-btn--reveal'); + const form = doc.querySelector('form[name="content_visibility_update"]'); + const visiblity = doc.querySelector('#content_visibility_update_visible'); + + if (!revealButton) { + return; + } + + revealButton.addEventListener( + 'click', + () => { + visiblity.value = 1; + form.submit(); + }, + false + ); +})(window, document); diff --git a/src/bundle/Resources/public/scss/_alerts.scss b/src/bundle/Resources/public/scss/_alerts.scss index acb4b996d6..e9dedb6427 100644 --- a/src/bundle/Resources/public/scss/_alerts.scss +++ b/src/bundle/Resources/public/scss/_alerts.scss @@ -5,5 +5,7 @@ padding: 0.35rem 1rem; border: 0; font-style: italic; + fill: currentColor; + vertical-align: middle; } -} +} \ No newline at end of file diff --git a/src/bundle/Resources/public/scss/_mixins.scss b/src/bundle/Resources/public/scss/_mixins.scss index 083acf71f0..aec035743e 100644 --- a/src/bundle/Resources/public/scss/_mixins.scss +++ b/src/bundle/Resources/public/scss/_mixins.scss @@ -51,6 +51,11 @@ } } + &.disabled { + cursor: inherit; + opacity: 0.5; + } + .ez-checkbox-icon__checkbox { display: none; } diff --git a/src/bundle/Resources/public/scss/_modals.scss b/src/bundle/Resources/public/scss/_modals.scss index 02fa69c8fa..ce27378feb 100644 --- a/src/bundle/Resources/public/scss/_modals.scss +++ b/src/bundle/Resources/public/scss/_modals.scss @@ -116,6 +116,13 @@ } } +.ez-modal--content-hide-confirmation { + .modal-header { + background: $ez-color-base-pale; + border-bottom: none; + } +} + .ez-modal--version-draft-conflict { .modal-header { background: $ez-color-base-pale; diff --git a/src/bundle/Resources/translations/content.en.xliff b/src/bundle/Resources/translations/content.en.xliff index 4f610eb3db..5be5e3a971 100644 --- a/src/bundle/Resources/translations/content.en.xliff +++ b/src/bundle/Resources/translations/content.en.xliff @@ -26,6 +26,26 @@ User with login '%login%' deleted. key: user.delete.success + + Content '%name%' has been hidden. + Content '%name%' has been hidden. + key: content.hide.success + + + Content '%name%' has been revealed. + Content '%name%' has been revealed. + key: content.reveal.success + + + Content '%name%' was already hidden. + Content '%name%' has been hidden. + key: content.hide.already_hidden + + + Content '%name%' was already visible. + Content '%name%' was already visible. + key: content.reveal.already_visible + diff --git a/src/bundle/Resources/translations/locationview.en.xliff b/src/bundle/Resources/translations/locationview.en.xliff index e2bab0d016..59e562cfc4 100644 --- a/src/bundle/Resources/translations/locationview.en.xliff +++ b/src/bundle/Resources/translations/locationview.en.xliff @@ -186,11 +186,6 @@ Content locations key: tab.locations.content_locations - - Hidden - Hidden - key: tab.locations.hidden - Hidden by superior Hidden by superior @@ -456,6 +451,36 @@ Select language key: user.edit.select_language + + This content item is hidden and is not publicly available + This content item is hidden and is not publicly available + key: content.hidden.message + + + Conflict when hiding content item + Conflict when hiding content item + key: content.hide.modal.title + + + This item is being used by other content item(s). Please remove all instance(s) to avoid a 404 error. + This item is being used by other content item(s). Please remove all instance(s) to avoid a 404 error. + key: content.hide.modal.warning_content_used_by_other_content + + + If you wish to continue, please click on Confirm. + If you wish to continue, please click on Confirm. + key: content.hide.modal.please_confirm_to_continue + + + Cancel + Cancel + key: content.hide.modal.cancel + + + Confirm + Confirm + key: content.hide.modal.confirm + diff --git a/src/bundle/Resources/translations/menu.en.xliff b/src/bundle/Resources/translations/menu.en.xliff index 637d8e3fb4..58bab904ef 100644 --- a/src/bundle/Resources/translations/menu.en.xliff +++ b/src/bundle/Resources/translations/menu.en.xliff @@ -36,7 +36,17 @@ Move key: content__sidebar_right__move - + + Hide + Hide + key: content__sidebar_right__hide + + + Reveal + Reveal + key: content__sidebar_right__reveal + + Send to Trash Send to Trash key: content__sidebar_right__send_to_trash diff --git a/src/bundle/Resources/views/content/locationview.html.twig b/src/bundle/Resources/views/content/locationview.html.twig index 605a0040c0..f51d1d107f 100644 --- a/src/bundle/Resources/views/content/locationview.html.twig +++ b/src/bundle/Resources/views/content/locationview.html.twig @@ -45,6 +45,15 @@ {% set items = items|merge([{ 'value': content.name }]) %} {% include '@ezdesign/parts/breadcrumbs.html.twig' with { items: items } %} + {% if location.contentInfo.isHidden %} +
+ + + + {{ 'content.hidden.message'|trans()|desc('This content item is hidden and is not publicly available') }} +
+ {% endif %} + {% include '@ezdesign/parts/page_title.html.twig' with { title: content.name, iconName: contentType.identifier, @@ -130,8 +139,13 @@ 'has_unique_asset': form_location_trash_with_single_asset is defined } only %} {% endif %} + {{ form(form_content_visibility_update, {'action': path('ezplatform.content.update_visibility')}) }} + {% if content_has_reverse_relations and not location.contentInfo.isHidden %} + {% include '@ezdesign/content/modal_content_hide_confirmation.html.twig' %} + {% endif %} + {% endblock %} {% block stylesheets %} diff --git a/src/bundle/Resources/views/content/modal_content_hide_confirmation.html.twig b/src/bundle/Resources/views/content/modal_content_hide_confirmation.html.twig new file mode 100644 index 0000000000..d80c800716 --- /dev/null +++ b/src/bundle/Resources/views/content/modal_content_hide_confirmation.html.twig @@ -0,0 +1,26 @@ + diff --git a/src/bundle/Resources/views/content/tab/locations/tab.html.twig b/src/bundle/Resources/views/content/tab/locations/tab.html.twig index f82d5d3e97..74db390d4b 100644 --- a/src/bundle/Resources/views/content/tab/locations/tab.html.twig +++ b/src/bundle/Resources/views/content/tab/locations/tab.html.twig @@ -38,10 +38,8 @@ {% if location.invisible and not location.hidden %} {{ 'tab.locations.hidden_by_superior'|trans()|desc('Hidden by superior') }} - {% elseif not can_hide[location.id] %} - {{ location.hidden ? 'tab.locations.hidden'|trans()|desc('Hidden') : 'tab.locations.visible'|trans()|desc('Visible') }} {% else %} -