diff options
Diffstat (limited to 'engine/lib/navigation.php')
-rw-r--r-- | engine/lib/navigation.php | 502 |
1 files changed, 502 insertions, 0 deletions
diff --git a/engine/lib/navigation.php b/engine/lib/navigation.php new file mode 100644 index 000000000..a5b087bd8 --- /dev/null +++ b/engine/lib/navigation.php @@ -0,0 +1,502 @@ +<?php +/** + * Elgg navigation library + * Functions for managing menus and other navigational elements + * + * @package Elgg.Core + * @subpackage Navigation + */ + +/** + * Deprecated by elgg_add_submenu_item() + * + * @see elgg_add_submenu_item() + * @deprecated 1.8 + * + * @param string $label The label + * @param string $link The link + * @param string $group The group to store item in + * @param boolean $onclick Add a confirmation when clicked? + * @param boolean $selected Is menu item selected + * + * @return bool + */ +function add_submenu_item($label, $link, $group = 'default', $onclick = false, $selected = NULL) { + elgg_deprecated_notice('add_submenu_item was deprecated by elgg_add_submenu_item', 1.8); + + $item = array( + 'text' => $label, + 'href' => $link, + 'selected' => $selected + ); + + if (!$group) { + $group = 'default'; + } + + if ($onclick) { + $js = "onclick=\"javascript:return confirm('" . elgg_echo('deleteconfirm') . "')\""; + $item['vars'] = array('js' => $js); + } + // submenu items were added in the page setup hook usually by checking + // the context. We'll pass in the current context here, which will + // emulate that effect. + // if context == 'main' (default) it probably means they always wanted + // the menu item to show up everywhere. + $context = get_context(); + + if ($context == 'main') { + $context = 'all'; + } + return elgg_add_submenu_item($item, $context, $group); +} + +/** + * Add an entry to the submenu. + * + * @param array $item The item as: + * <code> + * array( + * 'title' => 'Text to display', + * 'url' => 'URL of the link', + * 'id' => 'entry_unique_id' //used by children items to identify parents + * 'parent_id' => 'id_of_parent', + * 'selected' => BOOL // Is this item selected? (If NULL or unset will attempt to guess) + * 'vars' => array() // Array of vars to pass to the navigation/submenu_item view + * ) + * </code> + * + * @param string $context Context in which to display this menu item. 'all' + * will make it show up all the time. Use sparingly. + * @param string $group Group for the item. Each submenu group has its own <ul> + * + * @return BOOL + * @since 1.8 + * @see elgg_prepare_submenu + */ +function elgg_add_submenu_item(array $item, $context = 'all', $group = 'default') { + global $CONFIG; + + if (!isset($CONFIG->submenu_items)) { + $CONFIG->submenu_items = array(); + } + + if (!isset($CONFIG->submenu_items[$context])) { + $CONFIG->submenu_items[$context] = array(); + } + + if (!isset($CONFIG->submenu_items[$context][$group])) { + $CONFIG->submenu_items[$context][$group] = array(); + } + + if (!isset($item['text'])) { + return FALSE; + } + + // we use persistent object properties in the submenu + // setup function, so normalize the array to an object. + // we pass it in as an array because this would be the only + // place in elgg that we ask for an object like this. + // consistency ftw. + $item_obj = new StdClass(); + + foreach ($item as $k => $v) { + switch ($k) { + case 'parent_id': + case 'id': + // make sure '' and false make sense + $v = (empty($v)) ? NULL : $v; + + default: + $item_obj->$k = $v; + break; + } + } + + $CONFIG->submenu_items[$context][$group][] = $item_obj; + + return TRUE; +} + +/** + * Properly nest all submenu entries for contexts $context and 'all' + * + * @param string $context Context for menus + * @param bool $sort Sort the menu items alphabetically + * + * @since 1.8 + * @see elgg_add_submenu_item + * + * @return true + */ +function elgg_prepare_submenu($context = 'main', $sort = FALSE) { + global $CONFIG; + + if (!isset($CONFIG->submenu_items) || !($CONFIG->submenu_items)) { + return FALSE; + } + + $groups = array(); + + if (isset($CONFIG->submenu_items['all'])) { + $groups = $CONFIG->submenu_items['all']; + } + + if (isset($CONFIG->submenu_items[$context])) { + $groups = array_merge_recursive($groups, $CONFIG->submenu_items[$context]); + } + + if (!$groups) { + return FALSE; + } + + foreach ($groups as $group => $items) { + if ($sort) { + usort($items, 'elgg_submenu_item_cmp'); + } + + $parsed_menu = array(); + // determin which children need to go in this item. + foreach ($items as $i => $item) { + // can only support children if there's an id + if (isset($item->id)) { + foreach ($items as $child_i => $child_item) { + // don't check ourselves or used children. + if ($child_i == $i || $child_item->used == TRUE) { + continue; + } + + if (isset($child_item->parent_id) && $child_item->parent_id == $item->id) { + if (!isset($item->children)) { + $item->children = array(); + } + $item->children[] = $child_item; + $child_item->parent = $item; + // don't unset because we still need to check this item for children + $child_item->used = TRUE; + } + } + + // if the parent doesn't have a url, make it the first child item. + if (isset($item->children) && $item->children && !$item->href) { + $child = $item->children[0]; + while ($child && !isset($child->href)) { + if (isset($child->children) && isset($child->children[0])) { + $child = $child->children[0]; + } else { + $child = NULL; + } + } + + if ($child && isset($child->href)) { + $item->href = $child->href; + } else { + // @todo There are no URLs anywhere in this tree. + $item->href = $CONFIG->url; + } + } + } + + // only add top-level elements to the menu. + // the rest are children. + if (!isset($item->parent_id)) { + $parsed_menu[] = $item; + } + } + + $CONFIG->submenu[$context][$group] = $parsed_menu; + } + + return TRUE; +} + +/** + * Helper function used to sort submenu items by their display text. + * + * @param object $a First object + * @param object $b Second object + * + * @return int + * @since 1.8 + * @see elgg_prepare_submenu + */ +function elgg_submenu_item_cmp($a, $b) { + $a = $a->text; + $b = $b->text; + + return strnatcmp($a, $b); +} + +/** + * Use elgg_get_submenu(). + * + * @see elgg_get_submenu() + * @deprecated 1.8 + * + * @return string + */ +function get_submenu() { + elgg_deprecated_notice("get_submenu() has been deprecated by elgg_get_submenu()", 1.8); + return elgg_get_submenu(); +} + +/** + * Return the HTML for a sidemenu. + * + * @param string $context The context of the submenu (defaults to main) + * @param BOOL $sort Sort by display name? + * + * @return string Formatted HTML. + * @since 1.8 + * @todo Rename to a view function. See {@trac #2320}. + */ +function elgg_get_submenu($context = NULL, $sort = FALSE) { + global $CONFIG; + + if (!$context) { + $context = get_context(); + } + + if (!elgg_prepare_submenu($context, $sort)) { + return ''; + } + + $groups = $CONFIG->submenu[$context]; + $submenu_html = ''; + + foreach ($groups as $group => $items) { + // how far down we are in children arrays + $depth = 0; + // push and pop parent items + $temp_items = array(); + + while ($item = current($items)) { + // ignore parents created by a child but parent never defined properly + if (!isset($item->text) || !($item->text)) { + next($items); + continue; + } + + // try to guess if this should be selected if they don't specify + if ((!isset($item->selected) || $item->selected === NULL) && isset($item->href)) { + $item->selected = elgg_http_url_is_identical(full_url(), $item->href); + } + + // traverse up the parent tree if matached to mark all parents as selected/expanded. + if ($item->selected && isset($item->parent)) { + $parent = $item->parent; + while ($parent) { + $parent->selected = TRUE; + if (isset($parent->parent)) { + $parent = $parent->parent; + } else { + $parent = NULL; + } + } + } + + // get the next item + if (isset($item->children) && $item->children) { + $depth++; + array_push($temp_items, $items); + $items = $item->children; + } elseif ($depth > 0) { + // check if there are more children elements in the current items + // pop back up to the parent(s) if not + if ($item = next($items)) { + continue; + } else { + while ($depth > 0) { + $depth--; + $items = array_pop($temp_items); + if ($item = next($items)) { + break; + } + } + } + } else { + next($items); + } + } + + $vars = array('group' => $group, 'items' => $items); + $submenu_html .= elgg_view('navigation/submenu_group', $vars); + } + + // include the JS for the expand menus too + return elgg_view('navigation/submenu_js') . $submenu_html; +} + +/** + * Registers any custom menu items with the main Site Menu. + * + * @note Custom menu items are added through the admin interface. Plugins + * can add standard menu items by using {@link add_menu()}. + * + * @since 1.8 + * @link http://docs.elgg.org/Tutorials/UI/SiteMenu + * @elgg_event_handler init system + * @return void + */ +function add_custom_menu_items() { + if ($custom_items = get_config('menu_items_custom_items')) { + foreach ($custom_items as $url => $name) { + add_menu($name, $url); + } + } +} + +/** + * Returns the main site menu. + * + * @note The main site menu is split into "featured" links and + * "more" links. + * + * @return array ('featured_urls' and 'more') + * @since 1.8 + * @link http://docs.elgg.org/Tutorials/UI/SiteMenu + */ +function elgg_get_nav_items() { + $menu_items = get_register('menu'); + $featured_urls_info = get_config('menu_items_featured_urls'); + + $more = array(); + $featured_urls = array(); + $featured_urls_sanitised = array(); + + // easier to compare with in_array() than embedded foreach()es + $valid_urls = array(); + foreach ($menu_items as $info) { + $valid_urls[] = $info->value->url; + } + + // make sure the url is a valid link. + // this prevents disabled plugins leaving behind + // valid links when not using a pagehandler. + if ($featured_urls_info) { + foreach ($featured_urls_info as $info) { + if (in_array($info->value->url, $valid_urls)) { + $featured_urls[] = $info->value->url; + $featured_urls_sanitised[] = $info; + } + } + } + + // add toolbar entries if not hiding dupes. + foreach ($menu_items as $name => $info) { + if (!in_array($info->value->url, $featured_urls)) { + $more[] = $info; + } + } + + return array( + 'featured' => $featured_urls_sanitised, + 'more' => $more + ); +} + +/** + * Adds an item to the site-wide menu. + * + * You can obtain the menu array by calling {@link get_register('menu')} + * + * @param string $menu_name The name of the menu item + * @param string $menu_url The URL of the page + * @param array $menu_children Optionally, an array of submenu items (not currently used) + * @param string $context The context of the menu + * + * @return true|false Depending on success + * @todo Can be deprecated when the new menu system is introduced. + */ +function add_menu($menu_name, $menu_url, $menu_children = array(), $context = "") { + global $CONFIG; + + if (!isset($CONFIG->menucontexts)) { + $CONFIG->menucontexts = array(); + } + + if (empty($context)) { + $context = get_plugin_name(); + } + + $value = new stdClass(); + $value->url = $menu_url; + $value->context = $context; + + $CONFIG->menucontexts[] = $context; + return add_to_register('menu', $menu_name, $value, $menu_children); +} + +/** + * Removes an item from the menu register + * + * @param string $menu_name The name of the menu item + * + * @return true|false Depending on success + */ +function remove_menu($menu_name) { + return remove_from_register('menu', $menu_name); +} + +/** + * Returns a menu item for use in the children section of add_menu() + * This is not currently used in the Elgg core. + * + * @param string $menu_name The name of the menu item + * @param string $menu_url Its URL + * + * @return stdClass|false Depending on success + * @todo Can be deprecated when the new menu system is introduced. + */ +function menu_item($menu_name, $menu_url) { + elgg_deprecated_notice('menu_item() is deprecated by add_submenu_item', 1.7); + return make_register_object($menu_name, $menu_url); +} + +/** + * Adds a breadcrumb to the breadcrumbs stack. + * + * @param string $title The title to display + * @param string $link Optional. The link for the title. + * + * @return void + * + * @link http://docs.elgg.org/Tutorials/UI/Breadcrumbs + */ +function elgg_push_breadcrumb($title, $link = NULL) { + global $CONFIG; + if (!is_array($CONFIG->breadcrumbs)) { + $CONFIG->breadcrumbs = array(); + } + + // avoid key collisions. + $CONFIG->breadcrumbs[] = array('title' => $title, 'link' => $link); +} + +/** + * Removes last breadcrumb entry. + * + * @return array popped item. + * @link http://docs.elgg.org/Tutorials/UI/Breadcrumbs + */ +function elgg_pop_breadcrumb() { + global $CONFIG; + + if (is_array($CONFIG->breadcrumbs)) { + array_pop($CONFIG->breadcrumbs); + } + + return FALSE; +} + +/** + * Returns all breadcrumbs as an array of array('title' => 'Readable Title', 'link' => 'URL') + * + * @return array Breadcrumbs + * @link http://docs.elgg.org/Tutorials/UI/Breadcrumbs + */ +function elgg_get_breadcrumbs() { + global $CONFIG; + + return (is_array($CONFIG->breadcrumbs)) ? $CONFIG->breadcrumbs : array(); +} |