]> gitweb.fluxo.info Git - lorea/elgg.git/commitdiff
Refs #2320 added new menu functions and classes
authorcash <cash@36083f99-b078-4883-b0ff-0f9b5a30f544>
Fri, 17 Dec 2010 11:33:17 +0000 (11:33 +0000)
committercash <cash@36083f99-b078-4883-b0ff-0f9b5a30f544>
Fri, 17 Dec 2010 11:33:17 +0000 (11:33 +0000)
git-svn-id: http://code.elgg.org/elgg/trunk@7655 36083f99-b078-4883-b0ff-0f9b5a30f544

engine/classes/ElggMenuBuilder.php [new file with mode: 0644]
engine/classes/ElggMenuItem.php [new file with mode: 0644]
engine/lib/navigation.php
engine/lib/views.php

diff --git a/engine/classes/ElggMenuBuilder.php b/engine/classes/ElggMenuBuilder.php
new file mode 100644 (file)
index 0000000..b57ea6e
--- /dev/null
@@ -0,0 +1,249 @@
+<?php
+/**
+ * Elgg Menu Builder
+ *
+ * @package    Elgg.Core
+ * @subpackage Navigation
+ *
+ * @since 1.8.0
+ */
+class ElggMenuBuilder {
+
+       protected $menu = array();
+
+       protected $selected = null;
+
+       /**
+        * ElggMenuBuilder constructor
+        *
+        * @param string $name  Identifier of the menu
+        */
+       public function __construct($name) {
+               global $CONFIG;
+
+               $this->menu = $CONFIG->menus[$name];
+       }
+
+       /**
+        * Get a prepared menu array
+        *
+        * @param mixed $sort_by
+        * @return array
+        */
+       public function getMenu($sort_by) {
+
+               $this->selectFromContext();
+
+               $selected = $this->findSelected();
+
+               $this->setupSections();
+
+               $this->setupTrees();
+
+               $this->sort($sort_by);
+
+               return $this->menu;
+       }
+
+       /**
+        * Get the selected menu item
+        *
+        * @return ElggMenuItem
+        */
+       public function getSelected() {
+               return $this->selected;
+       }
+
+       /**
+        * Select menu items for the current context
+        *
+        * @return void
+        */
+       protected function selectFromContext() {
+               if (!isset($this->menu)) {
+                       $this->menu = array();
+                       return;
+               }
+
+               // get menu items for this context
+               $selected_menu = array();
+               foreach ($this->menu as $menu_item) {
+                       if ($menu_item->inContext()) {
+                               $selected_menu[] = $menu_item;
+                       }
+               }
+
+               $this->menu = $selected_menu;
+       }
+
+       /**
+        * Group the menu items into sections
+        * @return void
+        */
+       protected function setupSections() {
+               $sectioned_menu = array();
+               foreach ($this->menu as $menu_item) {
+                       if (!isset($sectioned_menu[$menu_item->getSection()])) {
+                               $sectioned_menu[$menu_item->getSection()] = array();
+                       }
+                       $sectioned_menu[$menu_item->getSection()][] = $menu_item;
+               }
+               $this->menu = $sectioned_menu;
+       }
+
+       /**
+        * Create trees for each menu section
+        *
+        * @internal The tree is doubly linked (parent and children links)
+        * @return void
+        */
+       protected function setupTrees() {
+               $menu_tree = array();
+
+               foreach ($this->menu as $key => $section) {
+                       $parents = array();
+                       $children = array();
+                       // divide base nodes from children
+                       foreach ($section as $menu_item) {
+                               $parent_name = $menu_item->getParentName();
+                               if (!$parent_name) {
+                                       $parents[$menu_item->getName()] = $menu_item;
+                               } else {
+                                       $children[] = $menu_item;
+                               }
+                       }
+
+                       // attach children to parents
+                       $iteration = 0;
+                       $current_gen = $parents;
+                       while (count($children) && $iteration < 5) {
+                               foreach ($children as $index => $menu_item) {
+                                       $parent_name = $menu_item->getParentName();
+                                       if (array_key_exists($parent_name, $current_gen)) {
+                                               $next_gen[$menu_item->getName()] = $menu_item;
+                                               $current_gen[$parent_name]->addChild($menu_item);
+                                               $menu_item->setParent($current_gen[$parent_name]);
+                                               unset($children[$index]);
+                                       }
+                               }
+                               $current_gen = $next_gen;
+                               $iteration += 1;
+                       }
+
+                       // convert keys to indexes for first level of tree
+                       $parents = array_values($parents);
+
+                       $menu_tree[$key] = $parents;
+               }
+
+               $this->menu = $menu_tree;
+       }
+
+       /**
+        * Find the menu item that is currently selected
+        *
+        * @return ElggMenuItem
+        */
+       protected function findSelected() {
+
+               // do we have a selected menu item already
+               foreach ($this->menu as $menu_item) {
+                       if ($menu_item->getSelected()) {
+                               return $menu_item;
+                       }
+               }
+
+               // scan looking for a selected item
+               foreach ($this->menu as $menu_item) {
+                       if ($menu_item->getURL()) {
+                               if (elgg_http_url_is_identical(full_url(), $menu_item->getURL())) {
+                                       $menu_item->setSelected(true);
+                                       return $menu_item;
+                               }
+                       }
+               }
+
+               return null;
+       }
+
+       /**
+        * Sort the menu sections and trees
+        *
+        * @param mixed $sort_by Sort type as string or php callback
+        * @return void
+        */
+       protected function sort($sort_by) {
+
+               // sort sections
+               ksort($this->menu);
+
+               switch ($sort_by) {
+                       case 'title':
+                               $sort_callback = array('ElggMenuBuilder', 'compareByTitle');
+                               break;
+                       case 'name';
+                               $sort_callback = array('ElggMenuBuilder', 'compareByName');
+                               break;
+                       case 'order':
+                               // use registration order
+                               return;
+                               break;
+                       default:
+                               if (is_callable($sort_by)) {
+                                       $sort_callback = $sort_by;
+                               } else {
+                                       return;
+                               }
+                               break;
+               }
+
+               // sort each section
+               foreach ($this->menu as $index => $section) {
+                       usort($section, $sort_callback);
+                       $this->menu[$index] = $section;
+
+                       // depth first traversal of tree
+                       foreach ($section as $root) {
+                               $stack = array();
+                               array_push($stack, $root);
+                               while (!empty($stack)) {
+                                       $node = array_pop($stack);
+                                       $node->sortChildren($sort_callback);
+                                       $children = $node->getChildren();
+                                       if ($children) {
+                                               $stack = array_merge($stack, $children);
+                                       }
+                                       $p = count($stack);
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Compare two menu items by their titles
+        *
+        * @param ElggMenuItem $a
+        * @param ElggMenuItem $b
+        * @return bool
+        */
+       public static function compareByTitle($a, $b) {
+               $a = $a->getTitle();
+               $b = $b->getTitle();
+
+               return strnatcmp($a, $b);
+       }
+
+       /**
+        * Compare two menu items by their identifiers
+        *
+        * @param ElggMenuItem $a
+        * @param ElggMenuItem $b
+        * @return bool
+        */
+       public static function compareByName($a, $b) {
+               $a = $a->getName();
+               $b = $b->getName();
+
+               return strcmp($a, $b);
+       }
+}
diff --git a/engine/classes/ElggMenuItem.php b/engine/classes/ElggMenuItem.php
new file mode 100644 (file)
index 0000000..97dabe6
--- /dev/null
@@ -0,0 +1,329 @@
+<?php
+/**
+ * Elgg Menu Item
+ *
+ * @package    Elgg.Core
+ * @subpackage Navigation
+ *
+ * @since 1.8.0
+ */
+class ElggMenuItem {
+       /**
+        * @var string Identifier of the menu
+        */
+       protected $name;
+
+       /**
+        * @var string The menu display string
+        */
+       protected $title;
+
+       /**
+        * @var string The menu url
+        */
+       protected $url;
+
+       /**
+        * @var array Page context array
+        */
+       protected $contexts = array('all');
+
+       /**
+        * @var string Menu section identifier
+        */
+       protected $section = 'default';
+
+       /**
+        * @var string Tooltip
+        */
+       protected $tooltip = '';
+
+       /**
+        * @var bool Is this the currently selected menu item
+        */
+       protected $selected = false;
+
+       /**
+        * @var string Identifier of this item's parent
+        */
+        protected $parent_name = '';
+
+        /**
+         * @var ElggMenuItem The parent object or null
+         */
+        protected $parent = null;
+
+        /**
+         * @var array Array of children objects or empty array
+         */
+        protected $children = array();
+
+       /**
+        * ElggMenuItem constructor
+        *
+        * @param string $name  Identifier of the menu item
+        * @param string $title Title of the menu item
+        * @param string $url   URL of the menu item
+        */
+       public function __construct($name, $title, $url) {
+               $this->name = $name;
+               $this->title = $title;
+               $this->url = $url;
+       }
+
+       /**
+        * ElggMenuItem factory method
+        *
+        * This static method creates an ElggMenuItem from an associative array.
+        * Required keys are name, title, and url.
+        *
+        * @param array $options Option array of key value pairs
+        *
+        * @return ElggMenuItem or NULL on error
+        */
+       public static function factory($options) {
+               if (!isset($options['name']) || !isset($options['title']) || !isset($options['url'])) {
+                       return NULL;
+               }
+
+               $item = new ElggMenuItem($options['name'], $options['title'], $options['url']);
+
+               // special catch in case someone uses context rather than contexts
+               if (isset($options['context'])) {
+                       $options['contexts'] = $options['context'];
+                       unset($options['context']);
+               }
+
+               foreach ($options as $key => $value) {
+                       $item->$key = $value;
+               }
+
+               // make sure contexts is set correctly
+               if (isset($options['contexts'])) {
+                       $item->setContext($options['contexts']);
+               }
+
+               return $item;
+       }
+
+       /**
+        * Get the identifier of the menu item
+        *
+        * @return string
+        */
+       public function getName() {
+               return $this->name;
+       }
+
+       /**
+        * Get the display title of the menu
+        *
+        * @return string
+        */
+       public function getTitle() {
+               return $this->title;
+       }
+
+       /**
+        * Get the URL of the menu item
+        *
+        * @return string
+        */
+       public function getURL() {
+               return $this->url;
+       }
+
+       /**
+        * Set the contexts that this menu item is available for
+        *
+        * @param array $contexts An array of context strings
+        *
+        * @return void
+        */
+       public function setContext($contexts) {
+               if (is_string($contexts)) {
+                       $contexts = array($contexts);
+               }
+               $this->contexts = $contexts;
+       }
+
+       /**
+        * Get an array of context strings
+        *
+        * @return array
+        */
+       public function getContext() {
+               return $this->contexts;
+       }
+
+       /**
+        * Should this menu item be used given the current context
+        *
+        * @param string $context A context string (default is empty string for
+        *                        current context stack.
+        *
+        * @return bool
+        */
+       public function inContext($context = '') {
+               if ($context) {
+                       return in_array($context, $this->contexts);
+               }
+
+               if (in_array('all', $this->contexts)) {
+                       return true;
+               }
+
+               foreach ($this->contexts as $context) {
+                       if (elgg_in_context($context)) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       /**
+        * Set the selected flag
+        *
+        * @param bool $state Selected state (default is true)
+        *
+        * @return void
+        */
+       public function setSelected($state = true) {
+               $this->selected = $state;
+       }
+
+       /**
+        * Get selected state
+        *
+        * @return bool
+        */
+       public function getSelected() {
+               return $this->selected;
+       }
+
+       /**
+        * Set the tool tip text
+        *
+        * @param string $text The text of the tool tip
+        *
+        * @return void
+        */
+       public function setTooltip($text) {
+               $this->tooltip = $text;
+       }
+
+       /**
+        * Get the tool tip text
+        *
+        * @return string
+        */
+       public function getTooltip() {
+               return $this->tooltip;
+       }
+
+       /**
+        * Set the section identifier
+        *
+        * @param string $section The identifier of the section
+        *
+        * @return void
+        */
+       public function setSection($section) {
+               $this->section = $section;
+       }
+
+       /**
+        * Get the section identifier
+        *
+        * @return string
+        */
+       public function getSection() {
+               return $this->section;
+       }
+
+       /**
+        * Set the parent identifier
+        *
+        * @param string $parent_name The identifier of the parent ElggMenuItem
+        *
+        * @return void
+        */
+       public function setParentName($parent_name) {
+               $this->parent_name = $parent_name;
+       }
+
+       /**
+        * Get the parent identifier
+        *
+        * @return string
+        */
+       public function getParentName() {
+               return $this->parent_name;
+       }
+
+       /**
+        * Set the parent menu item
+        *
+        * @param ElggMenuItem $parent
+        *
+        * @return void
+        */
+       public function setParent($parent) {
+               $this->parent = $parent;
+       }
+
+       /**
+        * Get the parent menu item
+        *
+        * @return ElggMenuItem or null
+        */
+       public function getParent() {
+               return $this->parent;
+       }
+
+       /**
+        * Add a child menu item
+        *
+        * @param ElggMenuItem $item
+        *
+        * @return void
+        */
+       public function addChild($item) {
+               $this->children[] = $item;
+       }
+
+       /**
+        * Get the children menu items
+        *
+        * @return array
+        */
+       public function getChildren() {
+               return $this->children;
+       }
+
+       /**
+        * Sort the children
+        *
+        * @param string $sort_function
+        *
+        * @return void
+        */
+       public function sortChildren($sort_function) {
+               usort($this->children, $sort_function);
+       }
+
+       /**
+        * Get the menu link
+        *
+        * @todo add styling
+        *
+        * @return string
+        */
+       public function getLink() {
+               $vars = array(
+                       'href' => $this->url,
+                       'text' => $this->title
+               );
+               return elgg_view('output/url', $vars);
+       }
+}
index 75c5958f4cf015935924d1fecb2f5f1658c3e0fa..7b8c32f02e9f783b3417552e87e8e44d8135c5af 100644 (file)
@@ -7,6 +7,70 @@
  * @subpackage Navigation
  */
 
+/**
+ * Register an item for an Elgg menu
+ *
+ * @param string $menu_name The name of the menu: site, page, userhover,
+ *                          userprofile, groupprofile, or any custom menu
+ * @param mixed  $menu_item A ElggMenuItem object or an array of options in format:
+ *                          name        => STR  Menu item identifier (required)
+ *                          title       => STR  Menu item title (required)
+ *                          url         => STR  Menu item URL (required)
+ *                          contexts    => ARR  Page context strings
+ *                          section     => STR  Menu section identifier
+ *                          tooltip     => STR  Menu item tooltip
+ *                          selected    => BOOL Is this menu item currently selected
+ *                          parent_name => STR  Identifier of the parent menu item
+ *
+ *                          Custom options can be added as key value pairs.
+ *
+ * @return bool
+ * @since 1.8.0
+ */
+function elgg_register_menu_item($menu_name, $menu_item) {
+       global $CONFIG;
+
+       if (!isset($CONFIG->menus[$menu_name])) {
+               $CONFIG->menus[$menu_name] = array();
+       }
+
+       if (is_array($menu_item)) {
+               $menu_item = ElggMenuItem::factory($menu_item);
+               if (!$menu_item) {
+                       return false;
+               }
+       }
+
+       $CONFIG->menus[$menu_name][] = $menu_item;
+       return true;
+}
+
+/**
+ * Remove an item from a menu
+ *
+ * @param string $menu_name The name of the menu
+ * @param string $item_name The unique identifier for this menu item
+ *
+ * @return bool
+ * @since 1.8.0
+ */
+function elgg_unregister_menu_item($menu_name, $item_name) {
+       global $CONFIG;
+
+       if (!isset($CONFIG->menus[$menu_name])) {
+               return false;
+       }
+
+       foreach ($CONFIG->menus[$menu_name] as $index => $menu_object) {
+               if ($menu_object->name == $item_name) {
+                       unset($CONFIG->menus[$menu_name][$index]);
+                       return true;
+               }
+       }
+
+       return false;
+}
+
 /**
  * Deprecated by elgg_add_submenu_item()
  *
index ade5ff678526924e2d239b4296f1fe5c844e029d..71922cb6c3abd90f7d11dc786770c2e0b449d1a6 100644 (file)
@@ -643,6 +643,43 @@ function elgg_view_layout($layout_name, $vars = array()) {
        }
 }
 
+/**
+ * Render a menu
+ *
+ * @param string $menu_name The name of the menu
+ * @param array $vars An associative array of display options for the menu.
+ *                    Options include:
+ *                    sort_by => string or php callback
+ *                       string options: 'name', 'title' (default), 'order' (registration order)
+ *                       php callback: a compare function for usort
+ *
+ * @return string
+ * @since 1.8.0
+ */
+function elgg_view_menu($menu_name, array $vars = array()) {
+
+       $vars['name'] = $menu_name;
+
+       $sort_by = elgg_get_array_value('sort_by', $vars, 'title');
+
+    // Give plugins a chance to add menu items just before creation.
+       // This supports context sensitive menus (ex. user hover).
+    elgg_trigger_plugin_hook('register', "menu:$menu_name", $vars, NULL);
+
+       $builder = new ElggMenuBuilder($menu_name);
+       $vars['menu'] = $builder->getMenu($sort_by);
+       $vars['selected_item'] = $builder->getSelected();
+
+       // Let plugins modify the menu
+    $vars['menu'] = elgg_trigger_plugin_hook('prepare', "menu:$menu_name", $vars, $vars['menu']);
+
+    if (elgg_view_exists("navigation/menu/$menu_name")) {
+        return elgg_view("navigation/menu/$menu_name", $vars);
+    } else {
+        return elgg_view("navigation/menu/default", $vars);
+    }
+}
+
 /**
  * Returns a string of a rendered entity.
  *