- created renderable object tabtree that represents the tree of tabs, extends tabobject
- created core_renderer::tabtree(), and supporting core_renderer::render_tabtree(), core_renderer::render_tabobject()
- change print_tabs() to use renderer function, deprecate supporting not needed functions
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".'<ul class="tabrow'.$row.'">'."\n";
+
+ $first = true;
+ $count = count($tree);
+
+ foreach ($tree as $tab) {
+ $count--; // countdown to zero
+
+ $liclass = '';
+
+ if ($first && ($count == 0)) { // Just one in the row
+ $liclass = 'first last';
+ $first = false;
+ } else if ($first) {
+ $liclass = 'first';
+ $first = false;
+ } else if ($count == 0) {
+ $liclass = 'last';
+ }
+
+ if ((empty($tab->subtree)) && (!empty($tab->selected))) {
+ $liclass .= (empty($liclass)) ? 'onerow' : ' onerow';
+ }
+
+ if ($tab->inactive || $tab->active || $tab->selected) {
+ if ($tab->selected) {
+ $liclass .= (empty($liclass)) ? 'here selected' : ' here selected';
+ } else if ($tab->active) {
+ $liclass .= (empty($liclass)) ? 'here active' : ' here active';
+ }
+ }
+
+ $str .= (!empty($liclass)) ? '<li class="'.$liclass.'">' : '<li>';
+
+ if ($tab->inactive || $tab->active || ($tab->selected && !$tab->linkedwhenselected)) {
+ // The a tag is used for styling
+ $str .= '<a class="nolink"><span>'.$tab->text.'</span></a>';
+ } else {
+ $str .= '<a href="'.$tab->link.'" title="'.$tab->title.'"><span>'.$tab->text.'</span></a>';
+ }
+
+ if (!empty($tab->subtree)) {
+ $str .= convert_tree_to_html($tab->subtree, $row+1);
+ } else if ($tab->selected) {
+ $str .= '<div class="tabrow'.($row+1).' empty"> </div>'."\n";
+ }
+
+ $str .= ' </li>'."\n";
+ }
+ $str .= '</ul>'."\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;
+}
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);
+ }
+}
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 <a> 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 .= "<a href=\"$tabobject->link\" title=\"$tabobject->title\"><span>$tabobject->text</span></a>";
+ } 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;
+ }
}
/**
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".'<div class="tabtree">'.$output.'</div><div class="clearer"> </div>'."\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".'<ul class="tabrow'.$row.'">'."\n";
-
- $first = true;
- $count = count($tree);
-
- foreach ($tree as $tab) {
- $count--; // countdown to zero
-
- $liclass = '';
-
- if ($first && ($count == 0)) { // Just one in the row
- $liclass = 'first last';
- $first = false;
- } else if ($first) {
- $liclass = 'first';
- $first = false;
- } else if ($count == 0) {
- $liclass = 'last';
- }
-
- if ((empty($tab->subtree)) && (!empty($tab->selected))) {
- $liclass .= (empty($liclass)) ? 'onerow' : ' onerow';
- }
-
- if ($tab->inactive || $tab->active || $tab->selected) {
- if ($tab->selected) {
- $liclass .= (empty($liclass)) ? 'here selected' : ' here selected';
- } else if ($tab->active) {
- $liclass .= (empty($liclass)) ? 'here active' : ' here active';
- }
- }
-
- $str .= (!empty($liclass)) ? '<li class="'.$liclass.'">' : '<li>';
-
- if ($tab->inactive || $tab->active || ($tab->selected && !$tab->linkedwhenselected)) {
- // The a tag is used for styling
- $str .= '<a class="nolink"><span>'.$tab->text.'</span></a>';
- } else {
- $str .= '<a href="'.$tab->link.'" title="'.$tab->title.'"><span>'.$tab->text.'</span></a>';
- }
-
- if (!empty($tab->subtree)) {
- $str .= convert_tree_to_html($tab->subtree, $row+1);
- } else if ($tab->selected) {
- $str .= '<div class="tabrow'.($row+1).' empty"> </div>'."\n";
- }
-
- $str .= ' </li>'."\n";
- }
- $str .= '</ul>'."\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);
+ }
}
/**