From 153a13226ebda2388f5b984e8f52241d3193aff8 Mon Sep 17 00:00:00 2001 From: David Mudrak Date: Tue, 5 Jul 2011 09:08:49 +0200 Subject: [PATCH 1/3] MDL-28168 Revert "MDL-27073 Support multi-language content in custom menu" This reverts commit 87e0230d0a0f5993111e81e01a9f62713595136a. --- lib/outputcomponents.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/outputcomponents.php b/lib/outputcomponents.php index 79f01e0db2c..7cea429543a 100644 --- a/lib/outputcomponents.php +++ b/lib/outputcomponents.php @@ -2370,10 +2370,6 @@ class custom_menu extends custom_menu_item { * @return array */ public static function convert_text_to_menu_nodes($text) { - $text = format_text($text, FORMAT_MOODLE, array( - 'para' => false, - 'newlines' => false, - 'context' => get_system_context())); $lines = explode("\n", $text); $children = array(); $lastchild = null; From 155fffe6a4db4dc16d7dad86e7988a39f977c1b7 Mon Sep 17 00:00:00 2001 From: David Mudrak Date: Tue, 5 Jul 2011 10:13:14 +0200 Subject: [PATCH 2/3] MDL-28168 Improved custom_menu constructor This improves custom_menu constructor by dropping support for useless $text parameter and replacing it with the menu definition. This makes custom_menu instance independent on the place where the menu is defined ($CFG->custommenuitems) and can be unit-tested. Also, multiple instances of custom_menu can be instantiated now which can be interesting in the future. --- lib/outputcomponents.php | 14 ++++++++------ lib/outputrenderers.php | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/outputcomponents.php b/lib/outputcomponents.php index 7cea429543a..e0a02cbcda7 100644 --- a/lib/outputcomponents.php +++ b/lib/outputcomponents.php @@ -2323,15 +2323,17 @@ class custom_menu_item implements renderable { * @since Moodle 2.0 */ class custom_menu extends custom_menu_item { + /** * Creates the custom menu - * @param string $text Sets the text for this custom menu, never gets used and is optional + * + * @param string $definition the menu items definition in syntax required by {@link convert_text_to_menu_nodes()} */ - public function __construct($text='base') { - global $CFG; - parent::__construct($text); - if (!empty($CFG->custommenuitems)) { - $this->override_children(self::convert_text_to_menu_nodes($CFG->custommenuitems)); + public function __construct($definition = '') { + + parent::__construct('root'); // create virtual root element of the menu + if (!empty($definition)) { + $this->override_children(self::convert_text_to_menu_nodes($definition)); } } diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php index 9f2bb835d78..c54f16a84a5 100644 --- a/lib/outputrenderers.php +++ b/lib/outputrenderers.php @@ -2410,7 +2410,7 @@ EOD; if (empty($CFG->custommenuitems)) { return ''; } - $custommenu = new custom_menu(); + $custommenu = new custom_menu($CFG->custommenuitems); return $this->render_custom_menu($custommenu); } From 4564d58f9e1435cc81768f35f445f6d845fd2314 Mon Sep 17 00:00:00 2001 From: David Mudrak Date: Tue, 5 Jul 2011 11:43:09 +0200 Subject: [PATCH 3/3] MDL-28168 Multi-language support for custom_menu reimplemented This is a reimplementation of the multi-language support for the custom_menu class. The menu items now accept the forth optional parameter with the explicit list of languages the item is valid for. If no languages are listed, the item is valid for any language. The caller of the custom_menu constructor must provide the user's current language or null if the multi-language should not be supported (all items are valid for any language then, regardless the definition). See the attached unit tests for the examples of usage. --- lib/outputcomponents.php | 57 +++++++++---- lib/outputrenderers.php | 2 +- lib/simpletest/testoutputcomponents.php | 108 ++++++++++++++++++++++++ 3 files changed, 148 insertions(+), 19 deletions(-) diff --git a/lib/outputcomponents.php b/lib/outputcomponents.php index e0a02cbcda7..2b18213bcc8 100644 --- a/lib/outputcomponents.php +++ b/lib/outputcomponents.php @@ -2324,16 +2324,21 @@ class custom_menu_item implements renderable { */ class custom_menu extends custom_menu_item { + /** @var string the language we should render for, null disables multilang support */ + protected $currentlanguage = null; + /** * Creates the custom menu * * @param string $definition the menu items definition in syntax required by {@link convert_text_to_menu_nodes()} + * @param string $language the current language code, null disables multilang support */ - public function __construct($definition = '') { + public function __construct($definition = '', $currentlanguage = null) { + $this->currentlanguage = $currentlanguage; parent::__construct('root'); // create virtual root element of the menu if (!empty($definition)) { - $this->override_children(self::convert_text_to_menu_nodes($definition)); + $this->override_children(self::convert_text_to_menu_nodes($definition, $currentlanguage)); } } @@ -2355,8 +2360,9 @@ class custom_menu extends custom_menu_item { * then be added to a custom menu. * * Structure: - * text|url|title - * The number of hyphens at the start determines the depth of the item + * text|url|title|langs + * The number of hyphens at the start determines the depth of the item. The + * languages are optional, comma separated list of languages the line is for. * * Example structure: * First level first item|http://www.moodle.com/ @@ -2366,12 +2372,16 @@ class custom_menu extends custom_menu_item { * -Second level third item|http://www.moodle.com/development/ * First level second item|http://www.moodle.com/feedback/ * First level third item + * English only|http://moodle.com|English only item|en + * German only|http://moodle.de|Deutsch|de,de_du,de_kids + * * * @static - * @param string $text + * @param string $text the menu items definition + * @param string $language the language code, null disables multilang support * @return array */ - public static function convert_text_to_menu_nodes($text) { + public static function convert_text_to_menu_nodes($text, $language = null) { $lines = explode("\n", $text); $children = array(); $lastchild = null; @@ -2379,27 +2389,38 @@ class custom_menu extends custom_menu_item { $lastsort = 0; foreach ($lines as $line) { $line = trim($line); - $bits = explode('|', $line ,4); // name|url|title|sort - if (!array_key_exists(0, $bits) || empty($bits[0])) { + $bits = explode('|', $line, 4); // name|url|title|langs + if (!array_key_exists(0, $bits) or empty($bits[0])) { // Every item must have a name to be valid continue; } else { $bits[0] = ltrim($bits[0],'-'); } - if (!array_key_exists(1, $bits)) { + if (!array_key_exists(1, $bits) or empty($bits[1])) { // Set the url to null $bits[1] = null; } else { // Make sure the url is a moodle url $bits[1] = new moodle_url(trim($bits[1])); } - if (!array_key_exists(2, $bits)) { + if (!array_key_exists(2, $bits) or empty($bits[2])) { // Set the title to null seeing as there isn't one $bits[2] = $bits[0]; } + if (!array_key_exists(3, $bits) or empty($bits[3])) { + // The item is valid for all languages + $itemlangs = null; + } else { + $itemlangs = array_map('trim', explode(',', $bits[3])); + } + if (!empty($language) and !empty($itemlangs)) { + // check that the item is intended for the current language + if (!in_array($language, $itemlangs)) { + continue; + } + } // Set an incremental sort order to keep it simple. - $bits[3] = $lastsort; - $lastsort = $bits[3]+1; + $lastsort++; if (preg_match('/^(\-*)/', $line, $match) && $lastchild != null && $lastdepth !== null) { $depth = strlen($match[1]); if ($depth < $lastdepth) { @@ -2409,26 +2430,26 @@ class custom_menu extends custom_menu_item { for ($i =0; $i < $difference; $i++) { $tempchild = $tempchild->get_parent(); } - $lastchild = $tempchild->add($bits[0], $bits[1], $bits[2], $bits[3]); + $lastchild = $tempchild->add($bits[0], $bits[1], $bits[2], $lastsort); } else { $depth = 0; - $lastchild = new custom_menu_item($bits[0], $bits[1], $bits[2], $bits[3]); + $lastchild = new custom_menu_item($bits[0], $bits[1], $bits[2], $lastsort); $children[] = $lastchild; } } else if ($depth > $lastdepth) { $depth = $lastdepth + 1; - $lastchild = $lastchild->add($bits[0], $bits[1], $bits[2], $bits[3]); + $lastchild = $lastchild->add($bits[0], $bits[1], $bits[2], $lastsort); } else { if ($depth == 0) { - $lastchild = new custom_menu_item($bits[0], $bits[1], $bits[2], $bits[3]); + $lastchild = new custom_menu_item($bits[0], $bits[1], $bits[2], $lastsort); $children[] = $lastchild; } else { - $lastchild = $lastchild->get_parent()->add($bits[0], $bits[1], $bits[2], $bits[3]); + $lastchild = $lastchild->get_parent()->add($bits[0], $bits[1], $bits[2], $lastsort); } } } else { $depth = 0; - $lastchild = new custom_menu_item($bits[0], $bits[1], $bits[2], $bits[3]); + $lastchild = new custom_menu_item($bits[0], $bits[1], $bits[2], $lastsort); $children[] = $lastchild; } $lastdepth = $depth; diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php index c54f16a84a5..1f00572bdc6 100644 --- a/lib/outputrenderers.php +++ b/lib/outputrenderers.php @@ -2410,7 +2410,7 @@ EOD; if (empty($CFG->custommenuitems)) { return ''; } - $custommenu = new custom_menu($CFG->custommenuitems); + $custommenu = new custom_menu($CFG->custommenuitems, current_language()); return $this->render_custom_menu($custommenu); } diff --git a/lib/simpletest/testoutputcomponents.php b/lib/simpletest/testoutputcomponents.php index 61f67086d35..f8aa788b2ef 100644 --- a/lib/simpletest/testoutputcomponents.php +++ b/lib/simpletest/testoutputcomponents.php @@ -112,3 +112,111 @@ class user_picture_test extends UnitTestCase { $this->assertEqual($returned->custom1, 'Value of custom1'); } } + + +/** + * Unit tests for the custom_menu class + */ +class custom_menu_test extends UnitTestCase { + + public function test_empty_menu() { + $emptymenu = new custom_menu(); + $this->assertTrue($emptymenu instanceof custom_menu); + $this->assertFalse($emptymenu->has_children()); + } + + public function test_basic_syntax() { + $definition = <<assertTrue($menu instanceof custom_menu); + $this->assertTrue($menu->has_children()); + $firstlevel = $menu->get_children(); + $this->assertIsA($firstlevel, 'array'); + $this->assertEqual(2, count($firstlevel)); + + $item = array_shift($firstlevel); + $this->assertTrue($item instanceof custom_menu_item); + $this->assertTrue($item->has_children()); + $this->assertEqual(3, count($item->get_children())); + $this->assertEqual('Moodle community', $item->get_text()); + $itemurl = $item->get_url(); + $this->assertTrue($itemurl instanceof moodle_url); + $this->assertEqual('http://moodle.org', $itemurl->out()); + $this->assertEqual($item->get_text(), $item->get_title()); // implicit title + + $item = array_shift($firstlevel); + $this->assertTrue($item->has_children()); + $this->assertEqual(2, count($item->get_children())); + $this->assertEqual('Moodle company', $item->get_text()); + $this->assertTrue(is_null($item->get_url())); + + $subitem = array_shift($item->get_children()); + $this->assertFalse($subitem->has_children()); + $this->assertEqual('Hosting', $subitem->get_text()); + $this->assertEqual('Commercial hosting', $subitem->get_title()); + } + + public function test_multilang_support() { + $definition = <<assertTrue($menu->has_children()); + $this->assertEqual(2, count($menu->get_children())); + + $infomenu = array_pop($menu->get_children()); + $this->assertTrue($infomenu->has_children()); + $this->assertEqual(2, count($infomenu->get_children())); + + $langspecinfo = array_shift($infomenu->get_children()); + $this->assertEqual('Information in English', $langspecinfo->get_title()); + + // same menu for English language selected + $menu = new custom_menu($definition, 'en'); + $this->assertTrue($menu->has_children()); + $this->assertEqual(2, count($menu->get_children())); + + $infomenu = array_pop($menu->get_children()); + $this->assertTrue($infomenu->has_children()); + $this->assertEqual(1, count($infomenu->get_children())); + + $langspecinfo = array_shift($infomenu->get_children()); + $this->assertEqual('Information in English', $langspecinfo->get_title()); + + // same menu for German (de_du) language selected + $menu = new custom_menu($definition, 'de_du'); + $this->assertTrue($menu->has_children()); + $this->assertEqual(2, count($menu->get_children())); + + $infomenu = array_pop($menu->get_children()); + $this->assertTrue($infomenu->has_children()); + $this->assertEqual(1, count($infomenu->get_children())); + + $langspecinfo = array_shift($infomenu->get_children()); + $this->assertEqual('Informationen in deutscher Sprache', $langspecinfo->get_title()); + + // same menu for Czech language selected + $menu = new custom_menu($definition, 'cs'); + $this->assertTrue($menu->has_children()); + $this->assertEqual(2, count($menu->get_children())); + + $infomenu = array_pop($menu->get_children()); + $this->assertFalse($infomenu->has_children()); + } +}