diff --git a/lib/deprecatedlib.php b/lib/deprecatedlib.php index 8022c44df6f..1fc0087c903 100644 --- a/lib/deprecatedlib.php +++ b/lib/deprecatedlib.php @@ -4515,3 +4515,110 @@ function get_courses_wmanagers($categoryid=0, $sort="c.sortorder ASC", $fields=a return $courses; } + +/** + * Converts a nested array tree into HTML ul:li [recursive] + * + * @deprecated since 2.5 + * + * @param array $tree A tree array to convert + * @param int $row Used in identifying the iteration level and in ul classes + * @return string HTML structure + */ +function convert_tree_to_html($tree, $row=0) { + debugging('Function convert_tree_to_html() is deprecated since Moodle 2.5. Consider using class tabtree and core_renderer::render_tabtree()', DEBUG_DEVELOPER); + + $str = "\n".''."\n"; + + return $str; +} + +/** + * Convert nested tabrows to a nested array + * + * @deprecated since 2.5 + * + * @param array $tabrows A [nested] array of tab row objects + * @param string $selected The tabrow to select (by id) + * @param array $inactive An array of tabrow id's to make inactive + * @param array $activated An array of tabrow id's to make active + * @return array The nested array + */ +function convert_tabrows_to_tree($tabrows, $selected, $inactive, $activated) { + + debugging('Function convert_tabrows_to_tree() is deprecated since Moodle 2.5. Consider using class tabtree', DEBUG_DEVELOPER); +/// Work backwards through the rows (bottom to top) collecting the tree as we go. + + $tabrows = array_reverse($tabrows); + + $subtree = array(); + + foreach ($tabrows as $row) { + $tree = array(); + + foreach ($row as $tab) { + $tab->inactive = in_array((string)$tab->id, $inactive); + $tab->active = in_array((string)$tab->id, $activated); + $tab->selected = (string)$tab->id == $selected; + + if ($tab->active || $tab->selected) { + if ($subtree) { + $tab->subtree = $subtree; + } + } + $tree[] = $tab; + } + $subtree = $tree; + } + + return $subtree; +} diff --git a/lib/outputcomponents.php b/lib/outputcomponents.php index 7ad3df779e0..e3080b1a694 100644 --- a/lib/outputcomponents.php +++ b/lib/outputcomponents.php @@ -2857,3 +2857,155 @@ class custom_menu extends custom_menu_item { return ($itema > $itemb) ? +1 : -1; } } + +/** + * Stores one tab + * + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @package core + */ +class tabobject implements renderable { + /** @var string unique id of the tab in this tree, it is used to find selected and/or inactive tabs */ + var $id; + /** @var moodle_url|string link */ + var $link; + /** @var string text on the tab */ + var $text; + /** @var string title under the link, by defaul equals to text */ + var $title; + /** @var bool whether to display a link under the tab name when it's selected */ + var $linkedwhenselected = false; + /** @var bool whether the tab is inactive */ + var $inactive = false; + /** @var bool indicates that this tab's child is selected */ + var $activated = false; + /** @var bool indicates that this tab is selected */ + var $selected = false; + /** @var array stores children tabobjects */ + var $subtree = array(); + /** @var int level of tab in the tree, 0 for root (instance of tabtree), 1 for the first row of tabs */ + var $level = 1; + + /** + * Constructor + * + * @param string $id unique id of the tab in this tree, it is used to find selected and/or inactive tabs + * @param string|moodle_url $link + * @param string $text text on the tab + * @param string $title title under the link, by defaul equals to text + * @param bool $linkedwhenselected whether to display a link under the tab name when it's selected + */ + public function __construct($id, $link = null, $text = '', $title = '', $linkedwhenselected = false) { + $this->id = $id; + $this->link = $link; + $this->text = $text; + $this->title = $title ? $title : $text; + $this->linkedwhenselected = $linkedwhenselected; + } + + /** + * Travels through tree and finds the tab to mark as selected, all parents are automatically marked as activated + * + * @param string $selected the id of the selected tab (whatever row it's on), + * if null marks all tabs as unselected + * @return bool whether this tab is selected or contains selected tab in its subtree + */ + protected function set_selected($selected) { + if ((string)$selected === (string)$this->id) { + $this->selected = true; + // This tab is selected. No need to travel through subtree. + return true; + } + foreach ($this->subtree as $subitem) { + if ($subitem->set_selected($selected)) { + // This tab has child that is selected. Mark it as activated. No need to check other children. + $this->activated = true; + return true; + } + } + return false; + } + + /** + * Travels through tree and finds a tab with specified id + * + * @param string $id + * @return tabtree|null + */ + public function find($id) { + if ((string)$this->id === (string)$id) { + return $this; + } + foreach ($this->subtree as $tab) { + if ($obj = $tab->find($id)) { + return $obj; + } + } + return null; + } + + /** + * Allows to mark each tab's level in the tree before rendering. + * + * @param int $level + */ + protected function set_level($level) { + $this->level = $level; + foreach ($this->subtree as $tab) { + $tab->set_level($level + 1); + } + } +} + +/** + * Stores tabs list + * + * Example how to print a single line tabs: + * $rows = array( + * new tabobject(...), + * new tabobject(...) + * ); + * echo $OUTPUT->tabtree($rows, $selectedid); + * + * Multiple row tabs may not look good on some devices but if you want to use them + * you can specify ->subtree for the active tabobject. + * + * @copyright 2013 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since Moodle 2.5 + * @package core + * @category output + */ +class tabtree extends tabobject { + /** + * Constuctor + * + * It is highly recommended to call constructor when list of tabs is already + * populated, this way you ensure that selected and inactive tabs are located + * and attribute level is set correctly. + * + * @param array $tabs array of tabs, each of them may have it's own ->subtree + * @param string|null $selected which tab to mark as selected, all parent tabs will + * automatically be marked as activated + * @param array|string|null $inactive list of ids of inactive tabs, regardless of + * their level. Note that you can as weel specify tabobject::$inactive for separate instances + */ + public function __construct($tabs, $selected = null, $inactive = null) { + $this->subtree = $tabs; + if ($selected !== null) { + $this->set_selected($selected); + } + if ($inactive !== null) { + if (is_array($inactive)) { + foreach ($inactive as $id) { + if ($tab = $this->find($id)) { + $tab->inactive = true; + } + } + } else if ($tab = $this->find($inactive)) { + $tab->inactive = true; + } + } + $this->set_level(0); + } +} diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php index 04fed8f0c72..2298120ded1 100644 --- a/lib/outputrenderers.php +++ b/lib/outputrenderers.php @@ -2882,6 +2882,107 @@ EOD; return $content; } + + /** + * Renders tabs + * + * This function replaces print_tabs() used before Moodle 2.5 but with slightly different arguments + * + * @param array $tabs array of tabs, each of them may have it's own ->subtree + * @param string|null $selected which tab to mark as selected, all parent tabs will + * automatically be marked as activated + * @param array|string|null $inactive list of ids of inactive tabs, regardless of + * their level. Note that you can as weel specify tabobject::$inactive for separate instances + * @return string + */ + public function tabtree($tabs, $selected = null, $inactive = null) { + return $this->render(new tabtree($tabs, $selected, $inactive)); + } + + /** + * Renders tabtree + * + * @param tabtree $tabtree + * @return string + */ + protected function render_tabtree(tabtree $tabtree) { + if (empty($tabtree->subtree)) { + return ''; + } + $str = ''; + $str .= html_writer::start_tag('div', array('class' => 'tabtree')); + $str .= $this->render_tabobject($tabtree); + $str .= html_writer::end_tag('div'). + html_writer::tag('div', ' ', array('class' => 'clearer')); + return $str; + } + + /** + * Renders tabobject (part of tabtree) + * + * This function is called from {@link core_renderer::render_tabtree()} + * and also it calls itself when printing the $tabobject subtree recursively. + * + * Property $tabobject->level indicates the number of row of tabs. + * + * @param tabobject $tabobject + * @return string HTML fragment + */ + protected function render_tabobject(tabobject $tabobject) { + $str = ''; + + // Print name of the current tab. + if ($tabobject instanceof tabtree) { + // No name for tabtree root. + } else if ($tabobject->inactive || $tabobject->activated || ($tabobject->selected && !$tabobject->linkedwhenselected)) { + // Tab name without a link. The tag is used for styling. + $str .= html_writer::tag('a', html_writer::span($tabobject->text), array('class' => 'nolink')); + } else { + // Tab name with a link. + if (!($tabobject->link instanceof moodle_url)) { + // backward compartibility when link was passed as quoted string + $str .= "link\" title=\"$tabobject->title\">$tabobject->text"; + } else { + $str .= html_writer::link($tabobject->link, html_writer::span($tabobject->text), array('title' => $tabobject->title)); + } + } + + if (empty($tabobject->subtree)) { + if ($tabobject->selected) { + $str .= html_writer::tag('div', ' ', array('class' => 'tabrow'. ($tabobject->level + 1). ' empty')); + } + return $str; + } + + // Print subtree + $str .= html_writer::start_tag('ul', array('class' => 'tabrow'. $tabobject->level)); + $cnt = 0; + foreach ($tabobject->subtree as $tab) { + $liclass = ''; + if (!$cnt) { + $liclass .= ' first'; + } + if ($cnt == count($tabobject->subtree) - 1) { + $liclass .= ' last'; + } + if ((empty($tab->subtree)) && (!empty($tab->selected))) { + $liclass .= ' onerow'; + } + + if ($tab->selected) { + $liclass .= ' here selected'; + } else if ($tab->activated) { + $liclass .= ' here active'; + } + + // This will recursively call function render_tabobject() for each item in subtree + $str .= html_writer::tag('li', $this->render($tab), array('class' => trim($liclass))); + $cnt++; + } + $str .= html_writer::end_tag('ul'); + + return $str; + } } /** diff --git a/lib/weblib.php b/lib/weblib.php index 767d78fb900..c77b8f7950e 100644 --- a/lib/weblib.php +++ b/lib/weblib.php @@ -2670,185 +2670,55 @@ function print_maintenance_message() { die; } -/** - * A class for tabs, Some code to print tabs - * - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @package moodlecore - */ -class tabobject { - /** - * @var string - */ - var $id; - var $link; - var $text; - /** - * @var bool - */ - var $linkedwhenselected; - - /** - * A constructor just because I like constructors - * - * @param string $id - * @param string $link - * @param string $text - * @param string $title - * @param bool $linkedwhenselected - */ - function tabobject ($id, $link='', $text='', $title='', $linkedwhenselected=false) { - $this->id = $id; - $this->link = $link; - $this->text = $text; - $this->title = $title ? $title : $text; - $this->linkedwhenselected = $linkedwhenselected; - } -} - - - /** * Returns a string containing a nested list, suitable for formatting into tabs with CSS. * - * @global object + * It is not recommended to use this function in Moodle 2.5 but it is left for backward + * compartibility. + * + * Example how to print a single line tabs: + * $rows = array( + * new tabobject(...), + * new tabobject(...) + * ); + * echo $OUTPUT->tabtree($rows, $selectedid); + * + * Multiple row tabs may not look good on some devices but if you want to use them + * you can specify ->subtree for the active tabobject. + * * @param array $tabrows An array of rows where each row is an array of tab objects * @param string $selected The id of the selected tab (whatever row it's on) * @param array $inactive An array of ids of inactive tabs that are not selectable. * @param array $activated An array of ids of other tabs that are currently activated * @param bool $return If true output is returned rather then echo'd **/ -function print_tabs($tabrows, $selected=NULL, $inactive=NULL, $activated=NULL, $return=false) { - global $CFG; - -/// $inactive must be an array - if (!is_array($inactive)) { - $inactive = array(); - } - -/// $activated must be an array - if (!is_array($activated)) { - $activated = array(); - } - -/// Convert the tab rows into a tree that's easier to process - if (!$tree = convert_tabrows_to_tree($tabrows, $selected, $inactive, $activated)) { - return false; - } - -/// Print out the current tree of tabs (this function is recursive) - - $output = convert_tree_to_html($tree); - - $output = "\n\n".'
'.$output.'
'."\n\n"; - -/// We're done! - - if ($return) { - return $output; - } - echo $output; -} - -/** - * Converts a nested array tree into HTML ul:li [recursive] - * - * @param array $tree A tree array to convert - * @param int $row Used in identifying the iteration level and in ul classes - * @return string HTML structure - */ -function convert_tree_to_html($tree, $row=0) { - - $str = "\n".''."\n"; - - return $str; -} - -/** - * Convert nested tabrows to a nested array - * - * @param array $tabrows A [nested] array of tab row objects - * @param string $selected The tabrow to select (by id) - * @param array $inactive An array of tabrow id's to make inactive - * @param array $activated An array of tabrow id's to make active - * @return array The nested array - */ -function convert_tabrows_to_tree($tabrows, $selected, $inactive, $activated) { - -/// Work backwards through the rows (bottom to top) collecting the tree as we go. +function print_tabs($tabrows, $selected = null, $inactive = null, $activated = null, $return = false) { + global $OUTPUT; $tabrows = array_reverse($tabrows); - $subtree = array(); - foreach ($tabrows as $row) { $tree = array(); foreach ($row as $tab) { - $tab->inactive = in_array((string)$tab->id, $inactive); - $tab->active = in_array((string)$tab->id, $activated); + $tab->inactive = is_array($inactive) && in_array((string)$tab->id, $inactive); + $tab->activated = is_array($activated) && in_array((string)$tab->id, $activated); $tab->selected = (string)$tab->id == $selected; - if ($tab->active || $tab->selected) { - if ($subtree) { - $tab->subtree = $subtree; - } + if ($tab->activated || $tab->selected) { + $tab->subtree = $subtree; } $tree[] = $tab; } $subtree = $tree; } - - return $subtree; + $output = $OUTPUT->tabtree($subtree); + if ($return) { + return $output; + } else { + print $output; + return !empty($output); + } } /**