Parcourir la source

Add new option "keep_open" to keep menu group always open (#4423)

Dariusz Markowicz il y a 8 ans
Parent
commit
ce012f9b95

+ 6 - 0
Annotation/Admin.php

@@ -90,6 +90,11 @@ class Admin implements MetadataProcessorInterface
      */
     public $showInDashboard = true;
 
+    /**
+     * @var bool
+     */
+    public $keepOpen = false;
+
     /**
      * @param ClassMetadata $metadata
      */
@@ -106,6 +111,7 @@ class Admin implements MetadataProcessorInterface
             'icon' => $this->icon,
             'pager_type' => $this->pagerType,
             'persist_filters' => $this->persistFilters,
+            'keep_open' => $this->keepOpen,
         );
 
         $tag = array_filter($tag, function ($v) {

+ 9 - 0
DependencyInjection/Compiler/AddDependencyCallsCompilerPass.php

@@ -83,6 +83,7 @@ class AddDependencyCallsCompilerPass implements CompilerPassInterface
                 $labelCatalogue = isset($attributes['label_catalogue']) ? $attributes['label_catalogue'] : 'SonataAdminBundle';
                 $icon = isset($attributes['icon']) ? $attributes['icon'] : '<i class="fa fa-folder"></i>';
                 $onTop = isset($attributes['on_top']) ? $attributes['on_top'] : false;
+                $keepOpen = isset($attributes['keep_open']) ? $attributes['keep_open'] : false;
 
                 if (!isset($groupDefaults[$resolvedGroupName])) {
                     $groupDefaults[$resolvedGroupName] = array(
@@ -91,6 +92,7 @@ class AddDependencyCallsCompilerPass implements CompilerPassInterface
                         'icon' => $icon,
                         'roles' => array(),
                         'on_top' => false,
+                        'keep_open' => false,
                     );
                 }
 
@@ -107,6 +109,8 @@ class AddDependencyCallsCompilerPass implements CompilerPassInterface
                     throw new \RuntimeException('You can\'t use "on_top" option with multiple same name groups.');
                 }
                 $groupDefaults[$resolvedGroupName]['on_top'] = $onTop;
+
+                $groupDefaults[$resolvedGroupName]['keep_open'] = $keepOpen;
             }
         }
 
@@ -122,6 +126,7 @@ class AddDependencyCallsCompilerPass implements CompilerPassInterface
                         'label' => $resolvedGroupName,
                         'roles' => array(),
                         'on_top' => false,
+                        'keep_open' => false,
                     );
                 }
 
@@ -156,6 +161,10 @@ class AddDependencyCallsCompilerPass implements CompilerPassInterface
                 if (empty($group['on_top'])) {
                     $groups[$resolvedGroupName]['on_top'] = $groupDefaults[$resolvedGroupName]['on_top'];
                 }
+
+                if (empty($group['keep_open'])) {
+                    $groups[$resolvedGroupName]['keep_open'] = $groupDefaults[$resolvedGroupName]['keep_open'];
+                }
             }
         } elseif ($container->getParameter('sonata.admin.configuration.sort_admins')) {
             $groups = $groupDefaults;

+ 1 - 0
DependencyInjection/Configuration.php

@@ -140,6 +140,7 @@ class Configuration implements ConfigurationInterface
                                     ->scalarNode('label_catalogue')->end()
                                     ->scalarNode('icon')->defaultValue('<i class="fa fa-folder"></i>')->end()
                                     ->scalarNode('on_top')->defaultFalse()->info('Show menu item in side dashboard menu without treeview')->end()
+                                    ->scalarNode('keep_open')->defaultFalse()->info('Keep menu group always open')->end()
                                     ->scalarNode('provider')->end()
                                     ->arrayNode('items')
                                         ->beforeNormalization()

+ 3 - 0
Menu/Provider/GroupMenuProvider.php

@@ -138,6 +138,9 @@ class GroupMenuProvider implements MenuProviderInterface
 
             if (false === $menuItem->hasChildren()) {
                 $menuItem->setDisplay(false);
+            } elseif (!empty($group['keep_open'])) {
+                $menuItem->setAttribute('class', 'keep-open');
+                $menuItem->setExtra('keep_open', $group['keep_open']);
             }
         } else {
             foreach ($group['items'] as $item) {

+ 26 - 0
Resources/doc/cookbook/recipe_knp_menu.rst

@@ -205,6 +205,32 @@ your admin services or simply remove menu items from the ``sonata_admin`` dashbo
                           label:        Blog
                         - sonata.news.admin.news
 
+Keeping menu group open
+-----------------------
+
+You can add the ``keep_open`` option to menu group to keep that group always
+open and ignore open/close effects:
+
+.. code-block:: yaml
+
+    # app/config/config.yml
+
+    sonata_admin:
+        dashboard:
+            groups:
+                sonata.admin.group.content:
+                    keep_open:            true
+                    label:                sonata_media
+                    label_catalogue:      SonataMediaBundle
+                    icon:                 '<i class="fa fa-image"></i>'
+                    items:
+                        - sonata.media.admin.media
+                        - sonata.media.admin.gallery
+
+.. figure:: ../images/keep_open.png
+   :align: center
+   :alt: The navigation side bar with a group which uses "keep_open" option
+
 Show menu item without treeview
 -------------------------------
 

BIN
Resources/doc/images/keep_open.png


+ 5 - 0
Resources/public/css/styles.css

@@ -216,6 +216,11 @@ body.fixed .content-header .navbar {
     padding: 15px;
 }
 
+.sidebar-menu li.keep-open > .treeview-menu {
+    display: block !important;
+    height: auto !important;
+}
+
 .arrow {
     float: right;
 }

+ 3 - 1
Resources/views/Menu/sonata_menu.html.twig

@@ -43,7 +43,9 @@
             {% set icon = item.extra('icon')|default('') %}
             {{ icon|raw }}
             {{ parent() }}
-            <span class="pull-right-container"><i class="fa pull-right fa-angle-left"></i></span>
+            {%- if item.extra('keep_open') is not defined or not item.extra('keep_open') -%}
+                <span class="pull-right-container"><i class="fa pull-right fa-angle-left"></i></span>
+            {%- endif -%}
         </a>
     {% endspaceless %}
 {% endblock %}

+ 11 - 0
Tests/DependencyInjection/Compiler/AddDependencyCallsCompilerPassTest.php

@@ -83,6 +83,7 @@ class AddDependencyCallsCompilerPassTest extends PHPUnit_Framework_TestCase
         $this->assertSame('SonataAdminBundle', $dashboardGroupsSettings['sonata_group_one']['label_catalogue']);
         $this->assertSame(false, $dashboardGroupsSettings['sonata_group_one']['on_top']);
         $this->assertSame(true, $dashboardGroupsSettings['sonata_group_three']['on_top']);
+        $this->assertFalse($dashboardGroupsSettings['sonata_group_one']['keep_open']);
         $this->assertArrayHasKey('admin', $dashboardGroupsSettings['sonata_group_one']['items'][0]);
         $this->assertArrayHasKey('route', $dashboardGroupsSettings['sonata_group_one']['items'][0]);
         $this->assertArrayHasKey('label', $dashboardGroupsSettings['sonata_group_one']['items'][0]);
@@ -114,6 +115,9 @@ class AddDependencyCallsCompilerPassTest extends PHPUnit_Framework_TestCase
         $this->assertArrayHasKey('sonata_group_two', $dashboardGroupsSettings);
         $this->assertArrayHasKey('provider', $dashboardGroupsSettings['sonata_group_two']);
         $this->assertContains('my_menu', $dashboardGroupsSettings['sonata_group_two']['provider']);
+
+        $this->assertArrayHasKey('sonata_group_five', $dashboardGroupsSettings);
+        $this->assertTrue($dashboardGroupsSettings['sonata_group_five']['keep_open']);
     }
 
     /**
@@ -152,6 +156,7 @@ class AddDependencyCallsCompilerPassTest extends PHPUnit_Framework_TestCase
         $this->assertSame('SonataAdminBundle', $adminGroups['sonata_group_one']['label_catalogue']);
         $this->assertSame(false, $adminGroups['sonata_group_one']['on_top']);
         $this->assertSame(true, $adminGroups['sonata_group_three']['on_top']);
+        $this->assertFalse($adminGroups['sonata_group_one']['keep_open']);
         $this->assertContains('sonata_post_admin', $adminGroups['sonata_group_one']['items'][0]['admin']);
         $this->assertContains('sonata_news_admin', $adminGroups['sonata_group_one']['items']);
         $this->assertContains('sonata_news_admin', $adminGroups['sonata_group_one']['item_adds']);
@@ -162,6 +167,9 @@ class AddDependencyCallsCompilerPassTest extends PHPUnit_Framework_TestCase
         $this->assertArrayHasKey('provider', $adminGroups['sonata_group_two']);
         $this->assertContains('my_menu', $adminGroups['sonata_group_two']['provider']);
 
+        $this->assertArrayHasKey('sonata_group_five', $adminGroups);
+        $this->assertTrue($adminGroups['sonata_group_five']['keep_open']);
+
         $this->assertArrayHasKey('Sonata\AdminBundle\Tests\DependencyInjection\Post', $adminClasses);
         $this->assertContains('sonata_post_admin', $adminClasses['Sonata\AdminBundle\Tests\DependencyInjection\Post']);
         $this->assertArrayHasKey('Sonata\AdminBundle\Tests\DependencyInjection\Article', $adminClasses);
@@ -548,6 +556,9 @@ class AddDependencyCallsCompilerPassTest extends PHPUnit_Framework_TestCase
                             'sonata_post_admin',
                         ),
                     ),
+                    'sonata_group_five' => array(
+                        'keep_open' => true,
+                    ),
                 ),
             ),
             'admin_services' => array(

+ 6 - 1
Tests/DependencyInjection/Compiler/AnnotationCompilerPassTest.php

@@ -59,6 +59,7 @@ class AnnotationCompilerPassTest extends PHPUnit_Framework_TestCase
                 'group' => 'Admin',
                 'label' => 'Tests\Fixtures\Foo',
                 'show_in_dashboard' => false,
+                'keep_open' => false,
             )
         );
     }
@@ -82,6 +83,7 @@ class AnnotationCompilerPassTest extends PHPUnit_Framework_TestCase
                 'group' => 'Admin',
                 'label' => 'Foo',
                 'show_in_dashboard' => true,
+                'keep_open' => false,
             )
         );
     }
@@ -94,7 +96,8 @@ class AnnotationCompilerPassTest extends PHPUnit_Framework_TestCase
          *      managerType="doctrine_mongodb",
          *      group="myGroup",
          *      label="myLabel",
-         *      translationDomain="OMG"
+         *      translationDomain="OMG",
+         *      keepOpen=true
          * )
          */
         $annotation = new Admin();
@@ -104,6 +107,7 @@ class AnnotationCompilerPassTest extends PHPUnit_Framework_TestCase
         $annotation->label = 'myLabel';
         $annotation->showInDashboard = false;
         $annotation->translationDomain = 'OMG';
+        $annotation->keepOpen = true;
 
         $meta = new ClassMetadata('Sonata\AdminBundle\Tests\Fixtures\Entity\Foo');
 
@@ -116,6 +120,7 @@ class AnnotationCompilerPassTest extends PHPUnit_Framework_TestCase
                 'group' => 'myGroup',
                 'label' => 'myLabel',
                 'show_in_dashboard' => false,
+                'keep_open' => true,
             )
         );
 

+ 31 - 0
Tests/Menu/Provider/GroupMenuProviderTest.php

@@ -263,6 +263,37 @@ class GroupMenuProviderTest extends PHPUnit_Framework_TestCase
         $this->assertCount(0, $menu->getChildren());
     }
 
+    /**
+     * @param array $adminGroups
+     *
+     * @dataProvider getAdminGroups
+     */
+    public function testGetMenuProviderKeepOpenOption(array $adminGroups)
+    {
+        $this->pool->expects($this->once())
+            ->method('getInstance')
+            ->with($this->equalTo('sonata_admin_foo_service'))
+            ->will($this->returnValue($this->getAdminMock()));
+
+        $this->checker->expects($this->any())
+            ->method('isGranted')
+            ->willReturn(true);
+
+        $adminGroups['keep_open'] = true;
+
+        $menu = $this->provider->get(
+            'providerFoo',
+            array(
+                'name' => 'foo',
+                'group' => $adminGroups,
+            )
+        );
+
+        $this->assertInstanceOf('Knp\Menu\ItemInterface', $menu);
+        $this->assertSame('keep-open', $menu->getAttribute('class'));
+        $this->assertTrue($menu->getExtra('keep_open'));
+    }
+
     /**
      * @return array
      */