1<?php 2/*********************************************************** 3 Copyright (C) 2008-2012 Hewlett-Packard Development Company, L.P. 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License version 2.1 as published by the Free Software Foundation. 8 9 This library is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 Lesser General Public License for more details. 13 14 You should have received a copy of the GNU Lesser General Public License 15 along with this library; if not, write to the Free Software Foundation, Inc.0 16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 ***********************************************************/ 18/** 19 * \file 20 * \brief Common menu functions 21 */ 22const MENU_PATH_SEPARATOR = "::"; ///< Separator used between menu paths 23const MENU_BREAK = "[BREAK]"; ///< Break menu at this 24 25/** 26 * \class menu 27 * \brief 28 * Code for creating a menu list (2D linked list) from a set of plugins. 29 */ 30class menu 31{ 32 var $Name = ""; ///< Name of the menu item 33 var $URI = NULL; ///< URI for the plugin (everything after the "?mod=") 34 var $HTML = NULL; ///< HTML to include (if provided, used in place of all else) 35 var $Order = 0; ///< Used for ordering menu items 36 var $Target = NULL; ///< Recommended name of window for showing results 37 var $MaxDepth = 0; ///< How deep is SubMenu? 38 var $SubMenu = NULL; ///< Sub menu to show 39 public $FullName; ///< List to submenu list 40 41 /** 42 * Return the name of the menu 43 * @param boolean $showFullName If true, return FullName and order, else 44 * return Name 45 * @return string 46 */ 47 public function getName($showFullName=false) 48 { 49 if ($showFullName) { 50 return $this->FullName . "(" . $this->Order . ")"; 51 } 52 return $this->Name; 53 } 54} 55 56/********************************* 57 Global array: don't touch! 58 *********************************/ 59$MenuList = array(); ///< Global menu list array 60$MenuMaxDepth = 0; ///< How deep is the tree (for UI display) 61/** 62 * \brief Create a "First Prev 1 2 ... Next Last" page links for paged output. 63 * 64 * \param int $Page Page number of the current page 65 * \param int $TotalPage Last page number 66 * \param string $Uri URL of the page being displayed. "&page=" will be 67 * appended to the URL 68 * 69 * \return String containing menu HTML 70 */ 71function MenuPage($Page, $TotalPage, $Uri = '') 72{ 73 $V = "<font class='text'><center>"; 74 if (empty($Uri)) { 75 $Uri = Traceback(); 76 } 77 $Uri = preg_replace("/&page=[^&]*/", "", $Uri); 78 /* Create first page */ 79 if ($Page > 0) { 80 $text = _("First"); 81 $text1 = _("Prev"); 82 $V.= "<a href='$Uri&page=0'>[$text]</a> "; 83 $V.= "<a href='$Uri&page=" . ($Page - 1) . "'>[$text1]</a> "; 84 if ($Page > 9) { 85 $V.= " ... "; 86 } 87 } 88 /* Create previous list page */ 89 for ($i = $Page - 9;$i < $Page;$i++) { 90 if ($i >= 0) { 91 $V.= "<a href='$Uri&page=$i'>" . ($i + 1) . "</a> "; 92 } 93 } 94 /* Show current page number */ 95 $V.= "<b>" . ($Page + 1) . "</b>"; 96 /* Create next page */ 97 for ($i = $Page + 1;($i <= $TotalPage) && ($i < $Page + 9);$i++) { 98 $V.= " <a href='$Uri&page=$i'>" . ($i + 1) . "</a>"; 99 } 100 if ($Page < $TotalPage) { 101 if ($Page < $TotalPage - 9) { 102 $V.= " ..."; 103 } 104 $text = _("Next"); 105 $text1 = _("Last"); 106 $V.= " <a href='$Uri&page=" . ($Page + 1) . "'>[$text]</a>"; 107 $V.= " <a href='$Uri&page=" . ($TotalPage) . "'>[$text1]</a>"; 108 } 109 $V.= "</center></font>"; 110 return ($V); 111} // MenuPage 112 113/** 114 * \brief Create a "First Prev 1 2 ... Next" page links for paged output. 115 * 116 * \param int $Page Page number of the current page 117 * \param bool $Next True display "Next" and false don't display 118 * \param string $Uri URL of the page being displayed. "&page=" will be appended to the URL 119 * 120 * \return String containing menu HTML 121 */ 122function MenuEndlessPage($Page, $Next = 1, $Uri = '') 123{ 124 $V = "<font class='text'><center>"; 125 if (empty($Uri)) { 126 $Uri = Traceback(); 127 } 128 $Uri = preg_replace("/&page=[^&]*/", "", $Uri); 129 /* Create first page */ 130 if ($Page > 0) { 131 $text = _("First"); 132 $text1 = _("Prev"); 133 $V.= "<a href='$Uri&page=0'>[$text]</a> "; 134 $V.= "<a href='$Uri&page=" . ($Page - 1) . "'>[$text1]</a> "; 135 if ($Page > 9) { 136 $V.= " ... "; 137 } 138 } 139 /* Create previous list page */ 140 for ($i = $Page - 9;$i < $Page;$i++) { 141 if ($i >= 0) { 142 $V.= "<a href='$Uri&page=$i'>" . ($i + 1) . "</a> "; 143 } 144 } 145 /* Show current page number */ 146 $V.= "<b>" . ($Page + 1) . "</b>"; 147 /* Create next page */ 148 if ($Next) { 149 $text = _("Next"); 150 $i = $Page + 1; 151 $V.= " <a href='$Uri&page=$i'>" . ($i + 1) . "</a>"; 152 $V.= " ... <a href='$Uri&page=$i'>[$text]</a>"; 153 } 154 $V.= "</center></font>"; 155 return ($V); 156} // MenuEndlessPage() 157 158/** 159 * \brief Compare two menu items for sorting. 160 * 161 * \param &$a menu a 162 * \param &$b menu b 163 * 164 * \return -1 a > b\n 165 * 1 a < b\n 166 * 0 a->Order = b->Order and a->Name = b->Name 167 */ 168function menu_cmp(&$a, &$b) 169{ 170 if ($a->Order > $b->Order) { 171 return (-1); 172 } 173 if ($a->Order < $b->Order) { 174 return (1); 175 } 176 $rc = strcmp($a->Name, $b->Name); 177 return (strcmp($a->Name, $b->Name)); 178} // menu_cmp() 179 180/** 181 * \brief Given a Path, order level for the last 182 * item, and a plugin name, insert the menu item. 183 * 184 * This is VERY recursive and returns the new menu. 185 * If $URI is blank, nothing is added. 186 * 187 * @param[in,out] array &$menuItems Array of menu items. If null is passed, 188 * new array is created. 189 * @param array $path Path of the menu item 190 * @param string $pathRemainder 191 * @param int $LastOrder Order (position) of last menu item 192 * @param string $Target Name of the Menu target 193 * @param string $URI URI of the menu 194 * @param string $HTML HTML of the menu 195 * @param string &$Title Title of the menu 196 * @return int The max depth of menu 197 */ 198function menu_insert_r(&$menuItems, $path, $pathRemainder, $LastOrder, $Target, $URI, $HTML, &$Title) 199{ 200 $splitPath = explode(MENU_PATH_SEPARATOR, $pathRemainder, 2); 201 $pathElement = count($splitPath) > 0 ? $splitPath[0] : null; 202 $pathRemainder = count($splitPath) > 1 ? $splitPath[1] : null; 203 $hasPathComponent = $pathElement !== null && $pathElement !== ""; 204 205 if (!$hasPathComponent) { 206 return 0; 207 } 208 209 $isLeaf = $pathRemainder === null; 210 $menuItemsExist = isset($menuItems) && is_array($menuItems); 211 212 $currentMenuItem = NULL; 213 if ($menuItemsExist) { 214 foreach ($menuItems as &$menuItem) { 215 // need to escape the [ ] or the string will not match 216 if (!strcmp($menuItem->Name, $pathElement) && strcmp($menuItem->Name, MENU_BREAK)) { 217 $currentMenuItem = $menuItem; 218 break; 219 } else if (!strcmp($menuItem->Name, MENU_BREAK) && ($menuItem->Order == $LastOrder)) { 220 $currentMenuItem = $menuItem; 221 break; 222 } 223 } 224 } 225 226 $path[] = $pathElement; 227 $FullName = str_replace(" ", "_", implode(MENU_PATH_SEPARATOR, $path)); 228 229 $sortItems = false; 230 $currentItemIsMissing = empty($currentMenuItem); 231 if ($currentItemIsMissing) { 232 $currentMenuItem = new menu; 233 $currentMenuItem->Name = $pathElement; 234 $currentMenuItem->FullName = $FullName; 235 236 if (! $menuItemsExist) { 237 $menuItems = array(); 238 } 239 array_push($menuItems, $currentMenuItem); 240 $sortItems = true; 241 } 242 243 /* $M is set! See if we need to traverse submenus */ 244 if ($isLeaf) { 245 if ($LastOrder != 0) { 246 if ($currentMenuItem->Order != $LastOrder) { 247 $sortItems = true; 248 } 249 $currentMenuItem->Order = $LastOrder; 250 } 251 $currentMenuItem->Target = $Target; 252 $currentMenuItem->URI = $URI; 253 $currentMenuItem->HTML = $HTML; 254 $currentMenuItem->Title = $Title; 255 } else { 256 $Depth = menu_insert_r($currentMenuItem->SubMenu, $path, $pathRemainder, $LastOrder, $Target, $URI, $HTML, $Title); 257 $currentMenuItem->MaxDepth = max ($currentMenuItem->MaxDepth, $Depth + 1); 258 } 259 260 if ($sortItems) { 261 usort($menuItems, 'menu_cmp'); 262 } 263 264 array_pop($path); 265 return ($currentMenuItem->MaxDepth); 266} // menu_insert_r() 267 268 269/** 270 * \brief Given a Path, order level for the last 271 * item, and optional plugin name, insert the menu item. 272 * 273 * \param string $Path Path of the new menu item 274 * \param int $LastOrder Is used for grouping items in order. 275 * \param string $URI URL link of the new menu item 276 * \param string $Title Title of the new menu item 277 * \param string $Target Target of the new menu item 278 * \param string $HTML HTML of the new menu item 279 */ 280function menu_insert($Path, $LastOrder = 0, $URI = NULL, $Title = NULL, $Target = NULL, $HTML = NULL) 281{ 282 global $MenuList; 283 menu_insert_r($MenuList, array(), $Path, $LastOrder, $Target, $URI, $HTML, $Title); 284} // menu_insert() 285 286 287/** 288 * \brief Given a top-level menu name, find 289 * the list of sub-menus below it and max depth of menu. 290 * 291 * \note this this function returns the sub menus of $Name, NOT the menu specified 292 * by $Name. 293 * 294 * \todo Rename this function to menu_find_submenus. 295 * 296 * \param string $Name Top-level menu name, may be a "::" separated list. 297 * \param[out] int &$MaxDepth Max depth of menu, returned value 298 * \param menu $Menu menu object array (default is global $MenuList) 299 * 300 * \return Array of sub-menus. $MaxDepth is also returned 301 */ 302function menu_find($Name, &$MaxDepth, $Menu = NULL) 303{ 304 global $MenuList; 305 if (empty($Menu)) { 306 $Menu = $MenuList; 307 } 308 if (empty($Name)) { 309 return ($Menu); 310 } 311 $PathParts = explode('::', $Name, 2); 312 foreach ($Menu as $Val) { 313 if ($Val->Name == $PathParts[0]) { 314 if (empty($PathParts[1])) { 315 $MaxDepth = $Val->MaxDepth; 316 return ($Val->SubMenu); 317 } else { 318 return (menu_find($PathParts[1], $MaxDepth, $Val->SubMenu)); 319 } 320 } 321 } 322 return (null); 323} // menu_find() 324 325 326$menu_to_1html_counter = 0; ///< Counter used by menu_to_1html() 327/** 328 * \brief Take a menu and render it as one HTML line. 329 * 330 * This ignores submenus! 331 * This is commonly called the "micro-menu". 332 * 333 * \param menu $Menu menu list need to show as HTML 334 * \param bool $ShowRefresh If true, show Refresh 335 * \param bool $ShowTraceback If true, show Tracback 336 * \param bool $ShowAll If false, then items without hyperlinks are hidden. 337 * 338 * \return HTML string 339 */ 340function menu_to_1html($Menu, $ShowRefresh = 1, $ShowTraceback = 0, $ShowAll = 1) 341{ 342 $showFullName = isset($_SESSION) && array_key_exists('fullmenudebug', $_SESSION) && $_SESSION['fullmenudebug'] == 1; 343 344 $V = ""; 345 $Std = ""; 346 global $menu_to_1html_counter; 347 if ($ShowTraceback) { 348 global $Plugins; 349 $Refresh = & $Plugins[plugin_find_id("refresh") ]; 350 if (!empty($Refresh)) { 351 $text = _("Traceback"); 352 $URL = Traceback_dir() . "?" . $Refresh->GetRefresh(); 353 $Std.= "<a href='$URL' target='_top'>$text</a>"; 354 } 355 } 356 if ($ShowRefresh) { 357 if (!empty($Std)) { 358 $Std.= " | "; 359 } 360 $text = _("Refresh"); 361 $Std.= "<a href='" . Traceback() . "'>$text</a>"; 362 } 363 $First = 1; 364 if (!empty($Menu)) { 365 foreach ($Menu as $Val) { 366 if ($Val->Name == MENU_BREAK) { 367 if (!$First) { 368 $V .= " •"; 369 if ($showFullName) { 370 $V .= getFullNameAddition($Val); 371 } 372 $V .= " "; 373 } 374 $First = 1; 375 } else if (!empty($Val->HTML)) { 376 $V.= $Val->HTML; 377 if ($showFullName) { 378 $V .= getFullNameAddition($Val); 379 380 } 381 $First = 0; 382 } else if (!empty($Val->URI)) { 383 if (!$First) { 384 $V.= " | "; 385 } 386 $V.= "<a href='" . Traceback_uri() . "?mod=" . $Val->URI . "'"; 387 if (!empty($Val->Title)) { 388 $V.= " title='" . htmlentities($Val->Title, ENT_QUOTES) . "'"; 389 } 390 $V.= ">"; 391 if ($showFullName) { 392 $V.= $Val->FullName . getFullNameAddition($Val); 393 } else { 394 $V.= $Val->Name; 395 } 396 $V.= "</a>"; 397 $First = 0; 398 } else if ($ShowAll) { 399 if (!$First) { 400 $V.= " | "; 401 } 402 if ($showFullName) { 403 $V.= $Val->FullName . getFullNameAddition($Val); 404 } else { 405 $V.= $Val->Name; 406 } 407 $First = 0; 408 } 409 } 410 } 411 if (!empty($Std)) { 412 if (!$First) { 413 $V.= " • "; 414 } 415 $V.= $Std; 416 $Std = null; 417 } 418 $menu_to_1html_counter++; 419 return ("<div id='menu1html-$menu_to_1html_counter' align='right' style='padding:0px 5px 0px 5px'><small>$V</small></div>"); 420} 421 422/** 423 * Get the additional string for menu full name 424 * @param menu $menu menu 425 * @return string 426 */ 427function getFullNameAddition(menu $menu) 428{ 429 return "(" . $menu->Order . ")"; 430} // menu_to_1html() 431 432 433/** 434 * \brief Take a menu and render it as 435 * one HTML line with items in a "[name]" list. 436 * 437 * \note This ignores submenus! 438 * 439 * \param menu $Menu menu list need to show as list 440 * \param string &$Parm A list of parameters to add to the URL. 441 * \param string $Pre String before "[name]" 442 * \param string $Post String after "[name]" 443 * \param bool $ShowAll If false, then items without hyperlinks are hidden. 444 * \param int $upload_id Upload id 445 * 446 * \return one HTML line with items in a "[name]" list 447 */ 448function menu_to_1list($Menu, &$Parm, $Pre = "", $Post = "", $ShowAll = 1, $upload_id = "") 449{ 450 if (empty($Menu)) { 451 return ''; 452 } 453 454 $showFullName = isset($_SESSION) && array_key_exists('fullmenudebug', $_SESSION) && $_SESSION['fullmenudebug'] == 1; 455 $V = ""; 456 457 foreach ($Menu as $Val) { 458 if (!empty($Val->HTML)) { 459 $entry = $Val->HTML; 460 } else if (!empty($Val->URI)) { 461 if (!empty($upload_id) && "tag" == $Val->URI) { 462 $tagstatus = TagStatus($upload_id); 463 if (0 == $tagstatus) { 464 break; // tagging on this upload is disabled 465 } 466 } 467 468 $entry = "[<a href='" . Traceback_uri() . "?mod=" . $Val->URI . "&" . $Parm . "'"; 469 if (!empty($Val->Title)) { 470 $entry .= " title='" . htmlentities($Val->Title, ENT_QUOTES) . "'"; 471 } 472 $entry .= ">" ; 473 $entry .= $Val->getName($showFullName); 474 $entry .= "</a>]"; 475 } else if ($ShowAll) { 476 $entry = "[" . $Val->getName($showFullName) . "]"; 477 } else { 478 continue; 479 } 480 $V .= $Pre . $entry . $Post; 481 } 482 return $V; 483} 484 485 486/** 487 * \brief Debugging code for printing the menu. 488 * 489 * \note This is recursive. 490 * 491 * \param menu &$Menu menu list to be printed 492 * \param int $Indent Indentations to add 493 */ 494function menu_print(&$Menu, $Indent) 495{ 496 if (!isset($Menu)) { 497 return; 498 } 499 foreach ($Menu as $Val) { 500 for ($i = 0;$i < $Indent;$i++) { 501 print " "; 502 } 503 print "$Val->Name ($Val->Order,$Val->URI)\n"; 504 menu_print($Val->SubMenu, $Indent + 1); 505 } 506} // menu_print() 507 508// DEBUG CODE 509/********** 510 if (0) 511 { 512 menu_insert("abc::def::",0,""); 513 menu_insert("Applications::Accessories::Dictionary",0,""); 514 menu_insert("Applications::Accessories::Ark",0,""); 515 menu_insert("Places::Computer",3,""); 516 menu_insert("Places::CD/DVD Creator",3,""); 517 menu_insert("Places::Home Folder",4,""); 518 menu_insert("Places::Network Servers",2,""); 519 menu_insert("Places::Search for Files...",0,""); 520 menu_insert("Places::Desktop",4,""); 521 menu_insert("Places::Recent Documents",0,""); 522 menu_insert("Places::Connect to Server...",2,""); 523 menu_insert("Applications::Accessories::Calculator",0,""); 524 menu_print($MenuList,0); 525 print "Max depth: $MenuMaxDepth\n"; 526 } 527 **********/ 528 529 530/** 531 * \brief Remove a menu object (based on an object name) 532 * from a menu list. 533 * 534 * For example, 535 * \code 536 * $mymenu = menu_find("Browse-Pfile", $MenuDepth); 537 * $myNewMenu = menu_remove($mymenu, "Compare"); 538 * \endcode 539 * 540 * \param menu $Menu menu list the menu item remove from 541 * \param string $RmName Remove name of menu 542 * 543 * \return A new menu list without $RmName 544 */ 545function menu_remove($Menu, $RmName) 546{ 547 $NewArray = array(); 548 foreach ($Menu as $MenuObj) { 549 if ($MenuObj->Name != $RmName) { 550 $NewArray[] = $MenuObj; 551 } 552 } 553 return $NewArray; 554} 555