diff --git a/includes/Components/CitizenComponent.php b/includes/Components/CitizenComponent.php new file mode 100644 index 00000000..cfab9164 --- /dev/null +++ b/includes/Components/CitizenComponent.php @@ -0,0 +1,14 @@ +sidebarData = $sidebarData; + } + + /** + * @inheritDoc + */ + public function getTemplateData(): array { + $portletsRest = []; + foreach ( $this->sidebarData[ 'array-portlets-rest' ] as $data ) { + /** + * Remove toolbox from main menu as we moved it to article tools + * TODO: Move handling to SkinCitizen.php after we convert pagetools to component + */ + if ( $data['id'] === 'p-tb' ) { + continue; + } + $portletsRest[] = ( new CitizenComponentMenu( $data ) )->getTemplateData(); + } + $firstPortlet = new CitizenComponentMenu( $this->sidebarData['data-portlets-first'] ); + + return [ + 'data-portlets-first' => $firstPortlet->getTemplateData(), + 'array-portlets-rest' => $portletsRest + ]; + } +} \ No newline at end of file diff --git a/includes/Components/CitizenComponentMenu.php b/includes/Components/CitizenComponentMenu.php new file mode 100644 index 00000000..ce4ec035 --- /dev/null +++ b/includes/Components/CitizenComponentMenu.php @@ -0,0 +1,49 @@ +data = $data; + } + + /** + * Counts how many items the menu has. + * + * @return int + */ + public function count(): int { + $items = $this->data['array-list-items'] ?? null; + if ( $items ) { + return count( $items ); + } + $htmlItems = $this->data['html-items'] ?? ''; + return substr_count( $htmlItems, 'data + [ + 'class' => '', + 'label' => '', + 'html-tooltip' => '', + 'label-class' => '', + 'html-before-portal' => '', + 'html-items' => '', + 'html-after-portal' => '', + 'array-list-items' => null, + ]; + } +} \ No newline at end of file diff --git a/includes/Partials/Drawer.php b/includes/Partials/Drawer.php index ea7fbf2c..eb54a344 100644 --- a/includes/Partials/Drawer.php +++ b/includes/Partials/Drawer.php @@ -32,31 +32,10 @@ use NumberFormatter; * Drawer partial of Skin Citizen * Generates the following partials: * - Logo - * - Drawer * + Special Pages Link * + Upload Link */ final class Drawer extends Partial { - /** - * Decorate main menu template data - * - * @return array - */ - public function decorateMainMenuData( $mainMenuData ) { - for ( $i = 0; $i < count( $mainMenuData['array-portlets-rest'] ); $i++ ) { - if ( $mainMenuData['array-portlets-rest'][$i]['id'] === 'p-tb' ) { - // Remove toolbox since it is handled by page tools - unset( $mainMenuData['array-portlets-rest'][$i] ); - break; - } - } - - // Reset index after unsetting toolbox - $mainMenuData['array-portlets-rest'] = array_values( $mainMenuData['array-portlets-rest'] ); - - return $mainMenuData; - } - /** * Get messages used for site stats in the drawer * diff --git a/includes/SkinCitizen.php b/includes/SkinCitizen.php index 05a3b0c4..cfbca128 100644 --- a/includes/SkinCitizen.php +++ b/includes/SkinCitizen.php @@ -23,6 +23,7 @@ namespace MediaWiki\Skins\Citizen; +use MediaWiki\Skins\Citizen\Components\CitizenComponentMainMenu; use MediaWiki\Skins\Citizen\Partials\BodyContent; use MediaWiki\Skins\Citizen\Partials\Drawer; use MediaWiki\Skins\Citizen\Partials\Footer; @@ -116,13 +117,23 @@ class SkinCitizen extends SkinMustache { 'msg-citizen-footer-tagline' => $this->msg( "citizen-footer-tagline" )->inContentLanguage()->parse(), // Decorate data provided by core 'data-search-box' => $header->decorateSearchBoxData( $parentData['data-search-box'] ), - 'data-main-menu' => $drawer->decorateMainMenuData( $parentData['data-portlets-sidebar'] ), 'data-footer' => $footer->decorateFooterData( $parentData['data-footer'] ), ]; $data += $sidebar->getSidebarData( $parentData ); $data += $tools->getPageToolsData( $parentData ); + $components = [ + 'data-main-menu' => new CitizenComponentMainMenu( $parentData['data-portlets-sidebar'] ) + ]; + + foreach ( $components as $key => $component ) { + // Array of components or null values. + if ( $component ) { + $parentData[$key] = $component->getTemplateData(); + } + } + return array_merge( $parentData, $data ); } diff --git a/templates/Drawer.mustache b/templates/Drawer.mustache index ad9618c6..29f0568b 100644 --- a/templates/Drawer.mustache +++ b/templates/Drawer.mustache @@ -21,10 +21,7 @@ {{#data-main-menu}} -
- {{#data-portlets-first}}{{>Menu}}{{/data-portlets-first}} - {{#array-portlets-rest}}{{>Menu}}{{/array-portlets-rest}} -
+ {{>MainMenu}} {{/data-main-menu}} \ No newline at end of file diff --git a/templates/MainMenu.mustache b/templates/MainMenu.mustache new file mode 100644 index 00000000..ad8bef32 --- /dev/null +++ b/templates/MainMenu.mustache @@ -0,0 +1,4 @@ +
+ {{#data-portlets-first}}{{>Menu}}{{/data-portlets-first}} + {{#array-portlets-rest}}{{>Menu}}{{/array-portlets-rest}} +
\ No newline at end of file diff --git a/tests/phpunit/Partials/DrawerTest.php b/tests/phpunit/Partials/DrawerTest.php index 1d637aee..0db6fa87 100644 --- a/tests/phpunit/Partials/DrawerTest.php +++ b/tests/phpunit/Partials/DrawerTest.php @@ -11,38 +11,7 @@ use MediaWiki\Skins\Citizen\SkinCitizen; * @group Citizen * @group Database */ -class DrawerTest extends \MediaWikiIntegrationTestCase { - /** - * @covers \MediaWiki\Skins\Citizen\Partials\Drawer::decorateMainMenuData - * @return void - */ - public function testDecorateMainMenuDataEmpty() { - $partial = new Drawer( new SkinCitizen() ); - - $this->assertEmpty( $partial->decorateMainMenuData( [ - 'array-portlets-rest' => [], - ] )['array-portlets-rest'] ); - } - - /** - * @covers \MediaWiki\Skins\Citizen\Partials\Drawer::decorateMainMenuData - * @return void - */ - public function testDecorateMainMenuRemovePageTools() { - $partial = new Drawer( new SkinCitizen() ); - - $mainMenuData = [ - 'array-portlets-rest' => [ - [ 'id' => 'foo' ], - [ 'id' => 'p-tb' ], - ], - ]; - - $this->assertNotEmpty( $partial->decorateMainMenuData( $mainMenuData ) ); - $this->assertArrayHasKey( 'array-portlets-rest', $partial->decorateMainMenuData( $mainMenuData ) ); - $this->assertNotContains( [ 'id' => 'pt-tb' ], $partial->decorateMainMenuData( $mainMenuData )['array-portlets-rest'] ); - } - +class DrawerTest extends MediaWikiIntegrationTestCase { /** * @covers \MediaWiki\Skins\Citizen\Partials\Drawer::getSiteStatsData * @return void diff --git a/tests/phpunit/Unit/Components/CitizenComponentMainMenuTest.php b/tests/phpunit/Unit/Components/CitizenComponentMainMenuTest.php new file mode 100644 index 00000000..e3680f0a --- /dev/null +++ b/tests/phpunit/Unit/Components/CitizenComponentMainMenuTest.php @@ -0,0 +1,58 @@ +assertInstanceOf( CitizenComponent::class, $mainMenu ); + } + + /** + * @covers ::getTemplateData + */ + public function testGetTemplateData( array $sidebarData, array $languageData, bool $isPinned ) { + // Create a new CitizenComponentMainMenu object + $mainMenu = new CitizenComponentMainMenu( + $sidebarData + ); + + // Call the getTemplateData method + $templateData = $mainMenu->getTemplateData(); + + // Assert main menu id + $this->assertSame( 'citizen-main-menu', $templateData['id'] ); + + // Assert the structure and types of expected keys + $this->assertIsArray( $templateData['data-portlets-first'] ); + $this->assertIsArray( $templateData['array-portlets-rest'] ); + + // Assert the structure and types of expected keys + $this->assertArrayHasKey( 'data-portlets-first', $templateData ); + $this->assertArrayHasKey( 'array-portlets-rest', $templateData ); + } +} \ No newline at end of file diff --git a/tests/phpunit/Unit/Components/CitizenComponentMenuTest.php b/tests/phpunit/Unit/Components/CitizenComponentMenuTest.php new file mode 100644 index 00000000..cb88f985 --- /dev/null +++ b/tests/phpunit/Unit/Components/CitizenComponentMenuTest.php @@ -0,0 +1,98 @@ + 'some-class', + 'label' => 'Some label', + 'html-tooltip' => 'Some tooltip', + 'label-class' => 'some-label-class', + 'html-before-portal' => 'Some before portal', + 'html-items' => 'Some items', + 'html-after-portal' => 'Some after portal', + 'array-list-items' => [ 'some-item-one', 'some-item-2', 'some-item-3' ] + ] + ] + ]; + } + + /** + * @return array[] + */ + public function provideCountData(): array { + return [ + [ + [ + 'array-list-items' => [ 'some-item-one', 'some-item-2', 'some-item-3' ] + ], + 3 + ], + [ + [ + 'html-items' => '
  • Some item
  • Some item
  • Some item
  • ' + ], + 3 + ] + ]; + } + + /** + * This test checks if the CitizenComponentMenu class can be instantiated + * @covers ::__construct + */ + public function testConstruct() { + // Create a new CitizenComponentMenu object + $menu = new CitizenComponentMenu( [] ); + + // Check if the object is an instance of CitizenComponent + $this->assertInstanceOf( CitizenComponent::class, $menu ); + } + + /** + * This test checks if the count method returns the correct number of items + * @covers ::count + * @dataProvider provideCountData + */ + public function testCount( array $data, int $expected ) { + // Create a new CitizenComponentMenu object + $menu = new CitizenComponentMenu( $data ); + + // Check if the count method returns the correct number of items + $this->assertSame( $expected, $menu->count() ); + } + + /** + * This test checks if the getTemplateData method returns the correct data + * @covers ::getTemplateData + * @dataProvider provideMenuData + */ + public function testGetTemplateData( array $data ) { + // Create a new CitizenComponentMenu object + $menu = new CitizenComponentMenu( $data ); + + // Call the getTemplateData method + $actualData = $menu->getTemplateData(); + + // Check if the getTemplateData method returns the correct data + $this->assertSame( $data, $actualData ); + } +} \ No newline at end of file