Source for file menu-defs.php

Documentation is available at menu-defs.php

  1. <?php
  2. /* ******************************************************************** */
  3. /* CATALYST PHP Source Code */
  4. /* -------------------------------------------------------------------- */
  5. /* This program is free software; you can redistribute it and/or modify */
  6. /* it under the terms of the GNU General Public License as published by */
  7. /* the Free Software Foundation; either version 2 of the License, or */
  8. /* (at your option) any later version. */
  9. /* */
  10. /* This program is distributed in the hope that it will be useful, */
  11. /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
  12. /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
  13. /* GNU General Public License for more details. */
  14. /* */
  15. /* You should have received a copy of the GNU General Public License */
  16. /* along with this program; if not, write to: */
  17. /* The Free Software Foundation, Inc., 59 Temple Place, Suite 330, */
  18. /* Boston, MA 02111-1307 USA */
  19. /* -------------------------------------------------------------------- */
  20. /* */
  21. /* Filename: menu-defs.php */
  22. /* Author: Paul Waite */
  23. /* Description: Definitions for managing MENUS */
  24. /* */
  25. /* ******************************************************************** */
  26. /** @package menu */
  27. include_once("button-defs.php");
  28. /** Form elements */
  29. ("form-defs.php");
  30. /** User management */
  31. ("user-defs.php");
  32.  
  33. // ----------------------------------------------------------------------
  34. // DEFINITIONS
  35.  
  36. /** Menu orientation set to horizontal */
  37. ("HORIZONTAL", 1);
  38. /** Menu orientation set to vertical */
  39. ("VERTICAL", 2);
  40.  
  41. // Separators for horizontal menus. Note, usage of at least
  42. // one real space, so that we allow wrapping in cells..
  43.  
  44. /** Menu item separator: " " (space) */
  45. ("SEP_SPACE", " ");
  46. /** Menu item separator: "|" (pipe) */
  47. ("SEP_BAR", "&nbsp;| ");
  48. /** Menu item separator: " " (double-space) */
  49. ("SEP_DBLSPACE", "&nbsp; ");
  50.  
  51. // Some menu levels..
  52. /** Main menu level (0) */
  53. ("MENU_LEVEL0", 0);
  54. /** Menu level 1 */
  55. ("MENU_LEVEL1", 1);
  56. /** Menu level 2 */
  57. ("MENU_LEVEL2", 2);
  58. /** Menu level 3 */
  59. ("MENU_LEVEL3", 3);
  60. /** Menu level 4 */
  61. ("MENU_LEVEL4", 4);
  62. /** All menu levels */
  63. ("MENU_LEVEL_ALL", -1);
  64.  
  65. // Patterns for special-function menu items. These are really
  66. // psuedo menu items, rather than real ones which navigate
  67. // the user to a web-page target.
  68.  
  69. /** The menu item is a sub-menu heading */
  70. ("MENU_ITEM_SUBMENU", "(sub-menu only)");
  71. /** The menu item is a spacer */
  72. ("MENU_ITEM_SPACER", "(menu spacer)");
  73. /** The menu item is a separator line */
  74. ("MENU_ITEM_SEPARATOR", "(menu separator)");
  75.  
  76. // ----------------------------------------------------------------------
  77. /**
  78. * Label class
  79. * A class for managing a simple label. This is just a piece of text
  80. * with some font settings.
  81. * @package menu
  82. * @access private
  83. */
  84. class label extends RenderableObject {
  85. /** Text of the label */
  86.  
  87. var $text = "";
  88. /** Font setting for the label */
  89.  
  90. var $font = "";
  91. //.....................................................................
  92. /**
  93. * Constructor
  94. * Creates the basic label object.
  95. * @param string $text Text of the label
  96. * @param string $font Font settings to apply to the label
  97. */
  98. function label($text="", $font="") {
  99. $this->text = $text;
  100. $this->font = $font;
  101. }
  102. //.....................................................................
  103. /**
  104. * Set the label font
  105. * @param string $font Font settings to apply to the label
  106. */
  107. function set_font($font) {
  108. $this->font = $font;
  109. return $this;
  110. }
  111. // ....................................................................
  112. /**
  113. * Use render() to render this element in your page.
  114. * This renders the field as WML.
  115. * @see render()
  116. * @return string The field as WML.
  117. */
  118. function wml() {
  119. return $this->text;
  120. }
  121. // ....................................................................
  122. /**
  123. * Use render() to render this element in your page.
  124. * This renders the field as HTML.
  125. * @see render()
  126. * @return string The field as HTML.
  127. */
  128. function html() {
  129. $html = "";
  130. if (isset($this->font)) $html .= "<font " . $this->font . ">";
  131. $html .= $this->text;
  132. if (isset($this->font)) $html .= "</font>";
  133. return $html;
  134. }
  135. } // label
  136. // ----------------------------------------------------------------------
  137.  
  138. /**
  139. * Standard menu item. Takes a link object as the item in the menu.
  140. * @package menu
  141. */
  142. class menuitem extends RenderableObject {
  143. // Public
  144. /** Link object to associate with menu item */
  145.  
  146. var $link;
  147. /** Label for this menu item */
  148.  
  149. var $label = "";
  150.  
  151. // Private
  152. /** True if menu item is highlighted
  153. @access private */
  154. var $highlighted = false;
  155. /** ID of parent menuitem of this menuitem
  156. @access private */
  157. var $parent_id = 0;
  158. /** Menu level of this item
  159. @access private */
  160. var $menu_level = 0;
  161. //.....................................................................
  162. /**
  163. * Constructor
  164. * Creates the menu item object.
  165. * @param object $link Link object to associate with menu item
  166. * @param boolean $highlighted Whether item is highlighted or not
  167. * @param integer $parent_id ID of parent menuitem (or 0 if none)
  168. * @param integer $menu_level Level of this item (zero-based)
  169. */
  170. function menuitem($link, $highlighted=false, $parent_id=0, $menu_level=0) {
  171. $this->link = $link;
  172. $this->label = new label($link->label);
  173. $this->highlighted = $highlighted;
  174. $this->parent_id = $parent_id;
  175. $this->menu_level = $menu_level;
  176. } // menuitem
  177. //.....................................................................
  178. /**
  179. * Set the menu item font
  180. * @param string $font Font settings to apply to the menu item
  181. */
  182. function set_font($font) {
  183. $this->link = $this->link->set_font($font);
  184. $this->label = $this->label->set_font($font);
  185. return $this;
  186. } // set_font
  187. // ....................................................................
  188. /**
  189. * This renders the field as WML.
  190. * @return string The field as WML.
  191. */
  192. function wml() {
  193. return "<small>" . $this->link->wml() . "</small>";
  194. } // wml
  195. // ....................................................................
  196. /**
  197. * This renders the field as HTML.
  198. * @return string The field as HTML.
  199. */
  200. function html() {
  201. return $this->link->html();
  202. } // html
  203.  
  204. } // menuitem class
  205. // ----------------------------------------------------------------------
  206.  
  207. /**
  208. * A menu, which is a container for menu items. This class encapsulates
  209. * what is essentially a list of links which can be displayed as a
  210. * 'menu'. Orientation can be VERTICAL or HORIZONTAL. A 'wrap threshold'
  211. * can be defined. If it's a vertical menu, this represents the max no.
  212. * of items down the page. Extra columns are generated to the right to
  213. * accomodate the items list. In the horizontal case, the threshold
  214. * represents the max no. of items across the page. Extra rows are
  215. * generated to hold the menu items list.
  216. * @package menu
  217. */
  218. class menu extends StylableObject {
  219. // Public
  220. /** Name of the menu */
  221.  
  222. var $name = "";
  223. /** Title/banner for this menu */
  224.  
  225. var $title = "";
  226. /** Menu orientation: HORIZONTAL or VERTICAL */
  227.  
  228. var $orientation = VERTICAL;
  229. /** Separator character between items */
  230.  
  231. var $separator = SEP_SPACE;
  232. /** Stylesheet class to use for highlighting */
  233.  
  234. var $highlightclass = "";
  235.  
  236. // Private
  237. /** Array of items in this menu
  238. @access private */
  239. var $items;
  240. /** Number of items in the menu
  241. @access private */
  242. var $item_count = 0;
  243. /** Font settings for the title/banner
  244. @access private */
  245. var $title_font = "";
  246. /** Max. number of menu items before wrapping the menu
  247. @access private */
  248. var $wrap_threshold = 0;
  249. // ....................................................................
  250. /**
  251. * Constructor
  252. * Creates the menu object.
  253. * @param string $name Name of the menu
  254. * @param string $title Title/benner for the menu
  255. * @param string $orientation HORIZONTAL or VERTICAL
  256. * @param integer $wrap_threshold Max. number of menu items before menu wraps
  257. */
  258. function menu($name, $title="", $orientation=VERTICAL, $wrap_threshold=0) {
  259. $this->name = $name;
  260. $this->title = $title;
  261. $this->item_count = 0;
  262. $this->orientation = $orientation;
  263. $this->wrap_threshold = $wrap_threshold;
  264.  
  265. // Default separator string..
  266. $this->separator = SEP_SPACE;
  267.  
  268. // A default style for highlighted items. Define this
  269. // in your stylesheet to see items highlighted..
  270. $this->highlightclass = "menuitemHL";
  271. } // menu
  272. // ....................................................................
  273. /**
  274. * Add menu item
  275. * Adds a ready-made menuitem to the menu.
  276. * @param object $item The menu item to add to the menu
  277. */
  278. function add_menuitem($item) {
  279. $this->items[] = $item;
  280. $this->item_count += 1;
  281. return $this;
  282. } // add_menuitem
  283. // ....................................................................
  284. /**
  285. * Create new menu item
  286. * Makes a new menuitem from a given label and URL
  287. * and adds it to the menu.
  288. * @param string $label Label to display
  289. * @param string $url URl for the menu item link
  290. * @param string $linkover_text Text to display in status bar when mouseover
  291. * @param bool $highlighted True if menu item should be highlighted
  292. * @param integer $parent_id Parent ID of this new item
  293. * @param integer $menu_level menu level of this new item
  294. */
  295. function additem($label, $url, $linkover_text="", $highlighted=false, $parent_id=0, $menu_level=0) {
  296. $link = new Link($url, $label);
  297. if ($linkover_text != "") {
  298. $link->set_linkover_text($linkover_text);
  299. }
  300. $item = new menuitem($link, $highlighted, $parent_id, $menu_level);
  301. $this->add_menuitem($item);
  302. return $this;
  303. } // additem
  304. //.....................................................................
  305. /**
  306. * Set the font of all menu items
  307. * @param string $font Font settings to apply to all menu items
  308. */
  309. function set_itemfont($font) {
  310. for ($i=0; $i < $this->item_count; $i++) {
  311. $item = $this->items[$i];
  312. $this->items[$i] = $item->set_font($font);
  313. }
  314. return $this;
  315. } // set_itemfont
  316. //.....................................................................
  317. /**
  318. * Set the menu tite font
  319. * @param string $font Font settings for menu title
  320. */
  321. function set_titlefont($font) {
  322. $this->title_font = $font;
  323. return $this;
  324. } // set_titlefont
  325. // ....................................................................
  326. /**
  327. * This renders the menu as WML (w/Phone.com extns) in a paged mode
  328. * with a number of menuitems/page defined by $wrap_threshold.
  329. * WAP phone with Phone.com extensions. We always create vertical
  330. * menus using a jump-menu in this particular case.
  331. * @return string The menu as WML.
  332. */
  333. function wmlup() {
  334. global $RESPONSE;
  335. global $ipg;
  336. if (!isset($ipg)) $ipg = 1;
  337.  
  338. $s = "";
  339. if ($this->title != "") {
  340. $s .= "<b>" . $this->title . "</b><br/>";
  341. }
  342. // Initialise..
  343. $paged = false;
  344. $start = 0;
  345. $finish = $this->item_count - 1;
  346.  
  347. // Determine page if paged menu..
  348. if ($this->wrap_threshold > 0) {
  349. $paged = true;
  350. $start = ($ipg - 1) * $this->wrap_threshold;
  351. $finish = $start + $this->wrap_threshold - 1;
  352. if ($finish > ($this->item_count - 1)) {
  353. $finish = $this->item_count - 1;
  354. }
  355. }
  356. // Grab menu options we want, assemble jump-menu..
  357. $jump = new form_jumpmenu($this->name, $this->title);
  358. for ($ix=$start; $ix <= $finish; $ix++) {
  359. $item = $this->items[$ix];
  360. $link = $item->link;
  361. $jump->additem($link->label, $link->href);
  362. }
  363. // More.. link
  364. if ($paged) {
  365. $pglabel = ""; $nextlabel = ""; $nexthref = "";
  366. $this->wml_morelink($ipg, $pglabel, $nextlabel, $nexthref);
  367. if ($nexthref != "") {
  368. $jump->additem($nextlabel, $nexthref);
  369. }
  370. }
  371. // Render the menu options..
  372. $s .= $jump->render();
  373.  
  374. if ($paged) {
  375. $s .= $pglabel;
  376. }
  377. // Return menu..
  378. return $s;
  379. } // wmlup
  380. // ....................................................................
  381. /**
  382. * This renders the field as WML.
  383. * @return string The field as WML.
  384. */
  385. function wml() {
  386. global $RESPONSE;
  387. global $ipg;
  388. if (!isset($ipg)) $ipg = 1;
  389. $s = "";
  390. if ($this->title != "") {
  391. $s .= "<b>" . $this->title . "</b><br/>";
  392. }
  393. // Initialise..
  394. $paged = false;
  395. $start = 0;
  396. $finish = $this->item_count - 1;
  397.  
  398. // Determine page if paged menu..
  399. if ($this->wrap_threshold > 0) {
  400. $paged = true;
  401. $start = ($ipg - 1) * $this->wrap_threshold;
  402. $finish = $start + $this->wrap_threshold - 1;
  403. if ($finish > ($this->item_count - 1)) {
  404. $finish = $this->item_count - 1;
  405. }
  406. }
  407. // Grab menu options we want, assemble jump-menu..
  408. $jump = new form_jumpmenu($this->name, $this->title);
  409. for ($ix=$start; $ix <= $finish; $ix++) {
  410. $item = $this->items[$ix];
  411. $s .= $item->wml() . "<br/>";
  412. }
  413. if ($paged) {
  414. $pglabel = ""; $nextlabel = ""; $nexthref = "";
  415. $this->wml_morelink($ipg, $pglabel, $nextlabel, $nexthref);
  416. $s .= $pglabel;
  417. if ($nexthref != "") {
  418. $nextlink = new Link($nexthref, $nextlabel);
  419. $s .= $nextlink->render();
  420. }
  421. }
  422. // Return menu
  423. return $s;
  424. } // wml
  425. // ....................................................................
  426. /**
  427. * Given a page number of the current page, this method returns the
  428. * appropriate label and link HREF for the next page link.
  429. * @param integer $page Page number of current page
  430. * @param string $pagepos Reference to string to contain current page pos
  431. * @param string $nextlabel Reference to string to contain next page link
  432. * @param string $nexthref Reference to string to contain HREF to next page
  433. */
  434. function wml_morelink($page, &$pagepos, &$nextlabel, &$nexthref) {
  435. global $RESPONSE;
  436. $nextpage = $page;
  437. $totpages = ceil($this->item_count / $this->wrap_threshold);
  438. $pagepos = " [$page/$totpages] ";
  439. $nextlabel = ""; $nexthref = "";
  440. if ($this->item_count > $this->wrap_threshold) {
  441. if ($page * $this->wrap_threshold > $this->item_count) {
  442. $nextpage = 1;
  443. $nextlabel = "First..";
  444. }
  445. else {
  446. $nextpage = $page + 1;
  447. $nextlabel = "More..";
  448. }
  449. $nexthref = $RESPONSE->requested;
  450. if (substr($nexthref, 0, 1) == "/") $nexthref = substr($nexthref, 1);
  451. if ($RESPONSE->requested_query != "") {
  452. $nexthref .= "?" . str_replace("&", "&amp;", $RESPONSE->requested_query);
  453. if (strstr($nexthref, "ipg=")) {
  454. $nexthref = preg_replace("/ipg=[0-9]+/", "ipg=$nextpage", $nexthref);
  455. }
  456. else {
  457. $nexthref .= "&amp;ipg=$nextpage";
  458. }
  459. }
  460. else {
  461. $nexthref .= "?ipg=$nextpage";
  462. }
  463. }
  464. return $nextpage;
  465. } // wml_morelink
  466. // ....................................................................
  467. /**
  468. * This renders the field as HTML.
  469. * @return string The field as HTML.
  470. */
  471. function html() {
  472. if ($this->orientation == VERTICAL) {
  473. // The only feasible way of doing vertical menus is in a table..
  474. $Tm = new table($this->name);
  475. $Tm->inherit_attributes($this);
  476. // Metrics..
  477. if ($this->wrap_threshold > 0 && $this->item_count > $this->wrap_threshold) {
  478. $cols = (int) ($this->item_count / $this->wrap_threshold);
  479. $tail = $this->item_count % $this->wrap_threshold;
  480. if($tail > 0) $cols += 1;
  481. }
  482. else {
  483. $cols = 1;
  484. }
  485. // Title text at top-left..
  486. if ($this->title != "") {
  487. $Tm->tr();
  488. $title .= $this->title;
  489. if ( isset($this->title_font) ) $title = "<font " . $this->title_font . ">$title</font>";
  490. $Tm->td($title);
  491. $Tm->td_colspan($cols * 2);
  492. }
  493. // The items..
  494. $items_left = $this->item_count;
  495. $row = 0;
  496. while ($items_left > 0) {
  497. $Tm->tr();
  498. for ($c=0; $c < $cols; $c++) {
  499. $item_index = $row + ($c * $this->wrap_threshold);
  500. if ($item_index < $this->item_count) {
  501. $item = $this->items[$item_index];
  502. if ($item->highlighted) {
  503. $item->link->highlightclass = $this->highlightclass;
  504. }
  505. $Tm->td($item->html());
  506. $html .= "<td>";
  507. if (isset($item->button)) {
  508. $Tm->td($item->label->html());
  509. }
  510. else {
  511. $Tm->td();
  512. }
  513. $items_left -= 1;
  514. }
  515. } // for
  516. $row += 1;
  517. } // while
  518. }
  519. else { // HORIZONTAL
  520. // Title text at top-left..
  521. if ($this->title != "") {
  522. $html .= "<p>";
  523. if ( isset($this->title_font) ) $html .= "<font " . $this->title_font . ">";
  524. $html .= $this->title;
  525. if ( isset($this->title_font) ) $html .= "</font>";
  526. $html .= "</p>";
  527. }
  528. // The menu items..
  529. $items_left = $this->item_count;
  530. $row = 0;
  531. $html .= "<span";
  532. if ($this->class != "") {
  533. $html .= " class=\"$this->class\"";
  534. }
  535. if ($this->style != "") {
  536. $html .= " style=\"$this->style\"";
  537. }
  538. $html .= ">";
  539. while ($items_left > 0) {
  540. for ($c=0; ($this->wrap_threshold == 0 || $c < $this->wrap_threshold) && ($items_left > 0); $c++) {
  541. $item_index = $c + ($row * $this->wrap_threshold);
  542. $item = $this->items[$item_index];
  543. if ($items_left > 0) {
  544. if ($item->highlighted) {
  545. $item->link->highlightclass = $this->highlightclass;
  546. }
  547. $html .= $item->html();
  548. if ( isset($item->button) ) $html .= "&nbsp;" . $item->label->html();
  549. }
  550. $items_left -= 1;
  551. if ($items_left > 0) $html .= $this->separator;
  552. }
  553. $row += 1;
  554. $html .= "<br>";
  555. }
  556. $html .= "</span>";
  557. }
  558. return $html;
  559. } // html
  560.  
  561. } // menu class
  562. // ----------------------------------------------------------------------
  563.  
  564. /**
  565. * Site Menu class - a database-enabled extension of the menu class.
  566. * The menu is built from the standard library database menu structure. This
  567. * database structure comprises two tables: 'menu' and 'menuoption'. Use this
  568. * menu renderer for simple single-row or single-column menus. It is rendered
  569. * as a simple list of items as clickable links. It also automatically applies
  570. * highlighting to the option which has an 'action' which matches the current
  571. * $RESPONSE page.
  572. * @package menu
  573. */
  574. class sitemenu extends menu {
  575. /** Name of this menu eg: 'main' */
  576.  
  577. var $menu_name = "";
  578. /** Level of menuitems to return */
  579.  
  580. var $menu_level = MENU_LEVEL_ALL;
  581. /** Language variant of this menu eg: 'fr' */
  582.  
  583. var $language = 0;
  584. // ....................................................................
  585. /**
  586. * Constructor
  587. * The name is used when rendering jump menu select boxes, the level is the menu
  588. * level starting at zero (default), the title is rendered above the list if specified,
  589. * orientation is VERTICAL or HORIZONTAL, wrap_threshold tells it where to wrap
  590. * to the next row (HORIZONTAL) or column (VERTICAL).
  591. * @param string $name Menu name used to identify the menu
  592. * @param integer $menu_level Level of menuitems to return
  593. * @param string $title Title/benner for this menu
  594. * @param integer $orientation HORIZONTAL or VERTICAL
  595. * @param integer $wrap_threshold Number of items before wrapping occurs
  596. * @param integer $lang Language variant for menu (or default if zero)
  597. */
  598. function sitemenu(
  599. $menuname="main",
  600. $menu_level=MENU_LEVEL_ALL,
  601. $title="",
  602. $orientation=VERTICAL,
  603. $wrap_threshold=0,
  604. $lang=-1
  605. ) {
  606. global $RESPONSE;
  607. $this->menu_name = $menuname;
  608. $this->menu_level = $menu_level;
  609. $this->menu($menuname, $title, $orientation, $wrap_threshold);
  610. // Set language..
  611. if ($lang != -1) {
  612. $this->language = $lang;
  613. }
  614. elseif (isset($RESPONSE) && $RESPONSE->multilang && isset($RESPONSE->languages[0])) {
  615. $this->language = $RESPONSE->languages[0];
  616. }
  617. // Get the menu definition..
  618. $this->getmenu();
  619. } // sitemenu
  620. // ....................................................................
  621. /**
  622. * Get the menu
  623. * Read the menuitems in from database and apply security..
  624. * @param string $id Unique database menu identifier
  625. */
  626. function getmenu($name="", $lang=-1) {
  627. global $RESPONSE;
  628.  
  629. debug_trace($this);
  630. // Specific menu given..
  631. if ($name != "") $this->menu_name = $name;
  632. if ($lang != -1) $this->language = $lang;
  633.  
  634. // Get menu, fall back to default if not found..
  635. $tryagain = true;
  636. do {
  637. $tryagain = ($this->language != 0);
  638. $q = "SELECT *";
  639. $q .= " FROM ax_menu m, ax_menuoption mo";
  640. $q .= " WHERE m.menu_name='" . addslashes($this->menu_name) . "'";
  641. $q .= " AND m.lang_id=$this->language";
  642. $q .= " AND mo.menu_id=m.menu_id";
  643. if ($this->menu_level != MENU_LEVEL_ALL) {
  644. $q .= " AND mo.menu_level=$this->menu_level";
  645. }
  646. $q .= " AND m.active=TRUE";
  647. $q .= " AND mo.active=TRUE";
  648. $q .= " ORDER BY mo.display_order";
  649. $item = dbrecordset($q);
  650. if ($item->hasdata) {
  651. $tryagain = false;
  652. }
  653. else {
  654. debugbr("menu language not found ($this->language): falling back to default", DBG_DEBUG);
  655. $this->language = 0;
  656. }
  657. } while ($tryagain);
  658.  
  659. if ($item->hasdata) {
  660. $mnu_ugroups = $item->field("mnu_ugroups");
  661. if ($mnu_ugroups == "" || $RESPONSE->ismemberof_group_in($mnu_ugroups)) {
  662. do {
  663. // Only add it if item group membership satisfied..
  664. $item_ugroups = $item->field("user_groups");
  665. $item_usertype = $item->field("user_type");
  666. if ($item_ugroups == "" || $RESPONSE->ismemberof_group_in($item_ugroups)) {
  667. if ($item_usertype == "" || ($RESPONSE->user_type == $item_usertype)) {
  668. $auth_required = $item->istrue("auth_code");
  669. $action = $item->field("action");
  670. $label = $item->field("label");
  671. $desc = $item->field("description");
  672. $parent_id = $item->field("parent_id");
  673. $menu_level = $item->field("menu_level");
  674.  
  675. // Build the menu URL..
  676. $href = $item->field("action");
  677. if ($auth_required) {
  678. if (strstr($href, "?")) $href .= "&";
  679. else $href .= "?";
  680. $href .= "auth_code=" . $RESPONSE->get_auth_code();
  681. }
  682. // Highlight if the current script name occurs in the item action..
  683. if (isset($action) && $action != "") {
  684. $highlighted = stristr(basename($RESPONSE->requested), $action);
  685. }
  686. // Add to our menu..
  687. $this->additem($label, $href, $desc, $highlighted, $parent_id, $menu_level);
  688. } // user type check
  689. } // item groups allowed
  690.  
  691. } while ($item->get_next());
  692.  
  693. } // menu groups allowed
  694. }
  695. debug_trace();
  696. } // getmenu
  697.  
  698. } // sitemenu class
  699. // ----------------------------------------------------------------------
  700.  
  701. /**
  702. * The menuoption is a class which contains the properties of a single
  703. * option on a menu.
  704. * @package menu
  705. */
  706. class menuoption extends RenderableObject {
  707. // Public
  708. /** Menuoption displayed label */
  709.  
  710. var $label = "(new item)";
  711. /** Menu option descriptive text */
  712.  
  713. var $description = "(new item)";
  714. /** Menu option level */
  715.  
  716. var $menu_level = 0;
  717. /** Width of option in pixels */
  718.  
  719. var $width = 100;
  720. /** Height of option in pixels */
  721.  
  722. var $height = 18;
  723.  
  724. // Private
  725. /** Whether menuoption exists in database
  726. @access private */
  727. var $exists = false;
  728. /** menuoption ID
  729. @access private */
  730. var $menuoptionid;
  731. /** menu ID the option belongs to
  732. @access private */
  733. var $menu_id;
  734. /** Parent ID of this menu option
  735. @access private */
  736. var $parent_id = 0;
  737. /** Array of user groups allowed to access this menuoption
  738. @access private */
  739. var $user_groups = array();
  740. /** User type restriction
  741. @access private */
  742. var $user_type = "";
  743. /** Order of display
  744. @access private */
  745. var $display_order = 0;
  746. /** Internal field which combines the sitepage
  747. and the sitepage_parms into an action.
  748. @access private */
  749. var $action = "";
  750. /** Target site webpage when clicked
  751. @access private */
  752. var $sitepage = MENU_ITEM_SUBMENU;
  753. /** Paramter string to pass on webpage URL
  754. @access private */
  755. var $sitepage_parms = "";
  756. /** Whether to apply auth code
  757. @access private */
  758. var $auth_code = false;
  759. /** Whether menuoption is active (displayed)
  760. @access private */
  761. var $active = true;
  762. /** When menu option was last modified (datetime)
  763. @access private */
  764. var $last_modified;
  765. /** True if this menu option is the parent of sub-menu options
  766. @access private */
  767. var $is_parent = false;
  768. // ....................................................................
  769. /**
  770. * Constructor
  771. * Create a new menuoption object.
  772. * @param string $id The unique identity of the menuoption.
  773. */
  774. function menuoption($id=NEW_MENUOPTION) {
  775. $this->menuoptionid = $id;
  776. $this->get($id);
  777. } // menuoption
  778. // ....................................................................
  779. /**
  780. * Get the menuoption.
  781. * Retrieves the specified menuoption from database.
  782. * @param string $id The unique integer identity of the menuoption to get.
  783. */
  784. function get($id) {
  785. debug_trace($this);
  786. $this->exists = false;
  787. if ($id != NEW_MENUOPTION) {
  788. // Try and read in existing menuoption info..
  789. $q = "SELECT * FROM ax_menuoption";
  790. $q .= " WHERE menuoption_id=$id";
  791. $mnoQ = dbrecordset($q);
  792. if ($mnoQ->hasdata) {
  793. $this->menu_id = $mnoQ->field("menu_id");
  794. $this->parent_id = $mnoQ->field("parent_id");
  795. $this->user_groups = explode(",", $mnoQ->field("user_groups"));
  796. $this->user_type = $mnoQ->field("user_type");
  797. $this->menu_level = $mnoQ->field("menu_level");
  798. $this->label = $mnoQ->field("label");
  799. $this->description = $mnoQ->field("description");
  800. $this->display_order = $mnoQ->field("display_order");
  801. $this->action = $mnoQ->field("action");
  802. $this->sitepage = $mnoQ->field("sitepage");
  803. $this->sitepage_parms = $mnoQ->field("sitepage_parms");
  804. $this->auth_code = $mnoQ->istrue("auth_code");
  805. $this->active = $mnoQ->istrue("active");
  806. $this->last_modified = $mnoQ->field("last_modified");
  807. $this->width = $mnoQ->field("width");
  808. $this->height = $mnoQ->field("height");
  809. $this->is_parent = $mnoQ->istrue("is_parent");
  810. $this->exists = true;
  811. }
  812. }
  813. debug_trace();
  814. // Return true if at least the menuoption exists..
  815. return $this->exists;
  816. } // get
  817. // ....................................................................
  818. /**
  819. * Synchronise sitepage parameters with manually edited values. This
  820. * check ensures that if people have added stuff directly into the
  821. * ax_menuoption.action table field, we pick it up and sync it to our
  822. * sitepage_parms field. However this only occurs if there is nothing
  823. * defined in the sitepage_parms field.
  824. */
  825. function syncparms() {
  826. if ($this->action != "") {
  827. $actbits = explode("?", $this->action);
  828. $changed = false;
  829. if ($this->sitepage == "") {
  830. if (isset($actbits[0]) && $actbits[0] != "") {
  831. $this->sitepage = $actbits[0];
  832. $changed = true;
  833. }
  834. }
  835. if ($this->sitepage_parms == "") {
  836. if (isset($actbits[1]) && $actbits[1] != "") {
  837. $this->sitepage_parms = $actbits[1];
  838. $changed = true;
  839. }
  840. }
  841. if ($changed) $this->put();
  842. }
  843. } // syncparms
  844. // ....................................................................
  845. /**
  846. * Save the menuoption.
  847. * Save this menuoption to the database. Create a new one if it
  848. * doesn't already exist.
  849. */
  850. function put() {
  851. debug_trace($this);
  852. // Deal with brand new menuoption..
  853. if (!$this->exists) {
  854. // If we are in need of a new ID, then get one..
  855. if ($this->menuoptionid == NEW_MENUOPTION) {
  856. $this->menuoptionid =
  857. get_next_sequencevalue(
  858. "seq_menuoption_id",
  859. "ax_menuoption",
  860. "menuoption_id"
  861. );
  862. }
  863. $mnoQ = new dbinsert("ax_menuoption");
  864. $mnoQ->set("menuoption_id", $this->menuoptionid);
  865. }
  866. else {
  867. $mnoQ = new dbupdate("ax_menuoption");
  868. $mnoQ->where("menuoption_id=$this->menuoptionid");
  869. }
  870. $mnoQ->set("menu_id", $this->menu_id);
  871. $mnoQ->set("parent_id", defaulted($this->parent_id, 0));
  872. $mnoQ->set("user_groups", implode(",", $this->user_groups));
  873. $mnoQ->set("user_type", $this->user_type);
  874. $mnoQ->set("menu_level", defaulted($this->menu_level, MENU_LEVEL0));
  875. $mnoQ->set("label", $this->label);
  876. $mnoQ->set("description", $this->description);
  877. $mnoQ->set("display_order", defaulted($this->display_order, 0));
  878. $mnoQ->set("sitepage", $this->sitepage);
  879. $mnoQ->set("sitepage_parms", $this->sitepage_parms);
  880. $mnoQ->set("auth_code", $this->auth_code);
  881. $mnoQ->set("active", $this->active);
  882. $mnoQ->set("width", defaulted($this->width, 100));
  883. $mnoQ->set("height", defaulted($this->height, 18));
  884. $mnoQ->set("is_parent", $this->is_parent);
  885. if ($this->sitepage_parms != "") {
  886. $mnoQ->set("action", $this->sitepage . "?" . $this->sitepage_parms);
  887. }
  888. else {
  889. $mnoQ->set("action", $this->sitepage);
  890. }
  891. $mnoQ->set("last_modified", 'now()');
  892. $this->exists = $mnoQ->execute();
  893. debug_trace();
  894.  
  895. } // put
  896. // ....................................................................
  897. /**
  898. * Delete the menuoption.
  899. * Delete this menuoption from the database.
  900. */
  901. function delete() {
  902. debug_trace($this);
  903. dbcommand("DELETE FROM ax_menuoption WHERE menuoption_id=$this->menuoptionid");
  904. debug_trace();
  905. } // delete
  906.  
  907. } // menuoption class
  908. // ----------------------------------------------------------------------
  909.  
  910. /**
  911. * The Menu Option Instance
  912. * This class encapsulates an instance of a menuoption, including all the
  913. * various properties (parent, menu_level, description etc. that a menu option
  914. * might have.
  915. * @package menu
  916. * @access private
  917. */
  918. class menuop_instance {
  919. var $id = "";
  920. var $menu_level = 0;
  921. var $label = "";
  922. var $desc = "";
  923. var $action = "";
  924. var $authcode = false;
  925. var $parent = "";
  926. var $children = "";
  927. var $expanded = false;
  928. var $menu_heading = false;
  929. // ....................................................................
  930. /**
  931. * Create a new menu option.
  932. * @param integer $id The unique menu option ID
  933. * @param integer $menu_level The level this menu option is at (0 = top)
  934. * @param string $label The menu option label
  935. * @param string $desc The menu option long description
  936. * @param string $act The menu option action (eg. path to webpage)
  937. * @param boolean $auth Whether to apply auth_code or not true or false
  938. * @param integer $parent The menu option ID of the parent of this menu option
  939. * @param boolean $is_parent Whether this option is parent of other options
  940. */
  941. function menuop_instance($id, $menu_level, $label="", $desc="", $act="", $authcode=false, $parent="", $is_parent=false) {
  942. $this->id = $id;
  943. $this->menu_level = $menu_level;
  944. $this->label = $label;
  945. $this->desc = $desc;
  946. $this->action = $act;
  947. $this->authcode = $auth;
  948. $this->parent = $parent;
  949. $this->is_parent = $is_parent;
  950. } // menuop_instance
  951. // ....................................................................
  952. /**
  953. * Return menu option details string.
  954. * Return the menu option details as a "|" delimited string
  955. * @return string The details packed into a "|" delimited string
  956. */
  957. function details() {
  958. return "$this->menu_level"
  959. . "|$this->label"
  960. . "|$this->desc"
  961. . "|$this->action"
  962. . "|" . ($this->authcode ? "t" : "f")
  963. ;
  964. } // details
  965. // ....................................................................
  966. /** Return true if this menu option is a sub-menu heading option, ie.
  967. * not an option which targets a webpage, but one which is a heading
  968. * for further sub-menu options.
  969. * @return boolean True if this menu option is a menu heading.
  970. */
  971. function is_submenuheading() {
  972. return ($this->is_parent);
  973. } // is_submenuheading
  974. // ....................................................................
  975. /** Return true if this menu option is a special-function pseudo menu
  976. * item such as a spacer or a line separator.
  977. * @return boolean True if this menu option is a special-function one
  978. */
  979. function is_pseudo() {
  980. return (
  981. $this->label == MENU_ITEM_SPACER
  982. || $this->label == MENU_ITEM_SEPARATOR
  983. );
  984. } // is_pseudo
  985.  
  986. } // menuop_instance
  987. // ----------------------------------------------------------------------
  988.  
  989. /**
  990. * A Menu Instance
  991. * This class encapsulates an instance of a menu, including its present
  992. * state in terms of expanded/collapsed headings, what is visible and
  993. * what is not, and the currently active (selected) menu-option.This class
  994. * is used by classes treemenu, and by hvmenu as a common container of menu
  995. * structure data, in a form most useful to them. This class is also apt
  996. * for serialization, in order to save menu structure state - eg. in the
  997. * ax_wwwsession.menu_state field.
  998. * @package menu
  999. * @access private
  1000. */
  1001. class menu_instance {
  1002. /** The ID of the menu */
  1003.  
  1004. var $menu_id = "";
  1005. /** The name of the menu */
  1006.  
  1007. var $menu_name = "";
  1008. /** The language of the menu (0 = default) */
  1009.  
  1010. var $language = 0;
  1011. /** Array of menuop_instance objects */
  1012.  
  1013. var $menu_ops = array();
  1014. /** Current menu option (selected) */
  1015.  
  1016. var $current_menu_option = "";
  1017. /** Array of IDs of top-level menu options */
  1018.  
  1019. var $menu_top = array();
  1020. /** Timestamp last read from DB */
  1021.  
  1022. var $last_readts = 0;
  1023. /** Overall validity flag */
  1024.  
  1025. var $valid = false;
  1026. /** Max. no. of levels in this menu */
  1027.  
  1028. var $level_depth = 0;
  1029. /** Max width of menu items per level in pixels
  1030. @access private */
  1031. var $level_widths = array();
  1032. /** Max height of menu items per level in pixels
  1033. @access private */
  1034. var $level_heights = array();
  1035. // ....................................................................
  1036. /** Create a menu instance.
  1037. * This constructor gets the complete menu structure from the database
  1038. * and populates menu options arrays etc.
  1039. * @param string $menu_name The name of the menu to instantiate.
  1040. * @param string $lang The optional language variant of this menu.
  1041. */
  1042. function menu_instance($menu_name, $lang=-1) {
  1043. global $RESPONSE;
  1044. $this->menu_name = $menu_name;
  1045. // Set the language..
  1046. if ($lang != -1) {
  1047. $this->language = $lang;
  1048. }
  1049. elseif (isset($RESPONSE) && $RESPONSE->multilang && isset($RESPONSE->languages[0])) {
  1050. $this->language = $RESPONSE->languages[0];
  1051. }
  1052. $this->get();
  1053. } // menu_instance
  1054. // ....................................................................
  1055. /** Return count of total menuoptions in this menu */
  1056.  
  1057. function menuop_count() {
  1058. return count($this->menu_ops);
  1059. } // menuop_count
  1060. // ....................................................................
  1061. /**
  1062. * Create a new menu option instance and stash it in our menu under
  1063. * the given id.
  1064. * @param integer $id The unique menu option ID
  1065. * @param integer $menu_level The level this menu option is at (0 = top)
  1066. * @param string $label The menu option label
  1067. * @param string $desc The menu option long description
  1068. * @param string $act The menu option action (eg. path to webpage)
  1069. * @param string $authcode Whether to apply auth_code or not true or false
  1070. * @param integer $parent The menu option ID of the parent of this menu option
  1071. * @param boolean $is_parent Whether this option is parent of other options
  1072. */
  1073. function add_menuop($id, $menu_level, $label="", $desc="", $act="", $authcode=false, $parent="", $is_parent=false) {
  1074. $this->menu_ops[$id] =
  1075. new menuop_instance($id, $menu_level, $label, $desc, $act, $authcode, $parent, $is_parent);
  1076. } // add_menuop
  1077. // ....................................................................
  1078. /** Return true if menu option exists.
  1079. * @param integer $id The unique menu option ID
  1080. * @return boolean True if the menu option of given ID exists
  1081. */
  1082. function menuop_exists($id) {
  1083. return isset($this->menu_ops[$id]);
  1084. } // menuop_exists
  1085. // ....................................................................
  1086. /** Return the menu option object.
  1087. * Returns the menuoption object of the given ID, or false if it
  1088. * doesn't exist.
  1089. * @param integer $id The unique menu option ID
  1090. * @return object The menu option object of the given ID, or false
  1091. */
  1092. function menuop($id) {
  1093. if (isset($this->menu_ops[$id])) {
  1094. return $this->menu_ops[$id];
  1095. }
  1096. else {
  1097. return false;
  1098. }
  1099. } // menuop
  1100. // ....................................................................
  1101. /** Return menu option details string.
  1102. * The details string returned contains the menu level, label, desc,
  1103. * action and authcode flag in a string all delimited by "|".
  1104. * @param integer $id The unique menu option ID
  1105. * @return string The details packed into a "|" delimited string
  1106. */
  1107. function menuop_details($id) {
  1108. $s = "";
  1109. if ($this->menuop_exists($id)) {
  1110. $mop = $this->menu_ops[$id];
  1111. $s = $mop->details();
  1112. }
  1113. return $s;
  1114. } // menuop_details
  1115. // ....................................................................
  1116. /**
  1117. * Get menu data if modified.
  1118. * Gets all the menu data from database if modified since last time we
  1119. * read it.
  1120. * @return boolean True if the menu was modified, and hence got.
  1121. */
  1122. function get_if_modified() {
  1123. // Now check last read time vs database mod times..
  1124. $modified = false;
  1125. $last_read = timestamp_to_datetime($this->last_readts);
  1126. $q = "SELECT COUNT(*) AS tot FROM ax_menuoption";
  1127. $q .= " WHERE menu_id=$this->menu_id";
  1128. $q .= " AND last_modified > '$last_read'";
  1129. $modQ = dbrecordset($q);
  1130. if ($modQ->field("tot") > 0) {
  1131. $modified = true;
  1132. }
  1133. if (!$modified) {
  1134. $q = "SELECT COUNT(*) AS tot FROM ax_menu";
  1135. $q .= " WHERE menu_id=$this->menu_id";
  1136. $q .= " AND last_modified > '$last_read'";
  1137. $modQ = dbrecordset($q);
  1138. if ($modQ->field("tot") > 0) {
  1139. $modified = true;
  1140. }
  1141. }
  1142. if ($modified) {
  1143. $this->get();
  1144. }
  1145. return $modified;
  1146. } // get_if_modified
  1147. // ....................................................................
  1148. /**
  1149. * Get menu last modified timestamp.
  1150. * @return integer Unix timestamp when menu was last modified.
  1151. */
  1152. function get_lastmodified_ts() {
  1153. $lastmodified = 0;
  1154. $q = "SELECT MAX(last_modified) FROM ax_menuoption";
  1155. $q .= " WHERE menu_id=$this->menu_id";
  1156. $modQ = dbrecordset($q);
  1157. $ts1 = datetime_to_timestamp($modQ->field("last_modified"));
  1158. $q = "SELECT last_modified FROM ax_menu";
  1159. $q .= " WHERE menu_id=$this->menu_id";
  1160. $modQ = dbrecordset($q);
  1161. $ts2 = datetime_to_timestamp($modQ->field("last_modified"));
  1162. if ($ts2 > $ts1) $lastmodified = $ts2;
  1163. else $lastmodified = $ts1;
  1164. return $lastmodified;
  1165. } // get_lastmodified_ts
  1166. // ....................................................................
  1167. /**
  1168. * Get menu data.
  1169. * Populates the complete menu data instance vars from the database.
  1170. */
  1171. function get() {
  1172. global $RESPONSE;
  1173. // MENU ITEM DETAIL..
  1174. $this->valid = false;
  1175. $this->menu_ops = array();
  1176. $this->menu_top = array();
  1177. $mno_children = array();
  1178. // Get menu, fall back to default if not found..
  1179. $tryagain = true;
  1180. do {
  1181. $tryagain = ($this->language != 0);
  1182. $q = "SELECT *";
  1183. $q .= " FROM ax_menu m, ax_menuoption mo";
  1184. $q .= " WHERE m.menu_name='" . addslashes($this->menu_name) . "'";
  1185. $q .= " AND m.lang_id=$this->language";
  1186. $q .= " AND mo.menu_id=m.menu_id";
  1187. $q .= " AND m.active=TRUE";
  1188. $q .= " AND mo.active=TRUE";
  1189. $q .= " ORDER BY mo.menu_level,mo.parent_id,mo.display_order";
  1190. $item = dbrecordset($q);
  1191. if ($item->hasdata) {
  1192. $tryagain = false;
  1193. }
  1194. else {
  1195. debugbr("menu language not found ($this->language): falling back to default", DBG_DEBUG);
  1196. $this->language = 0;
  1197. }
  1198. } while ($tryagain);
  1199. if ($item->hasdata) {
  1200. $this->valid = true;
  1201. $this->menu_id = $item->field("menu_id");
  1202. $topcount = 0;
  1203. do {
  1204. $mopid = $item->field("menuoption_id");
  1205. $mnu_ugroups = $item->field("user_groups");
  1206. $mnu_usertype = $item->field("user_type");
  1207. if ($mnu_ugroups == ""
  1208. || (!isset($RESPONSE) || $RESPONSE->ismemberof_group_in($mnu_ugroups))) {
  1209. if ($mnu_usertype == ""
  1210. || (!isset($RESPONSE) || ($RESPONSE->user_type == $mnu_usertype))) {
  1211. $parent_id = $item->field("parent_id");
  1212. $menu_level = $item->field("menu_level");
  1213. $label = $item->field("label");
  1214. $desc = $item->field("description");
  1215. $action = $item->field("action");
  1216. $authcode = $item->istrue("auth_code");
  1217. $is_parent = $item->istrue("is_parent");
  1218. if ($menu_level == 0) {
  1219. $topcount += 1;
  1220. $this->menu_top[$topcount] = $mopid;
  1221. }
  1222. if ($parent_id != "" && $parent_id != 0) {
  1223. if (isset($mno_children[$parent_id])) {
  1224. $mno_children[$parent_id] .= "|";
  1225. }
  1226. $mno_children[$parent_id] .= $mopid;
  1227. }
  1228. // Store menuoption..
  1229. $this->add_menuop(
  1230. $mopid,
  1231. $menu_level,
  1232. $label,
  1233. $desc,
  1234. $action,
  1235. $authcode,
  1236. $parent_id,
  1237. $is_parent
  1238. );
  1239. // Level depth recording..
  1240. if ($menu_level > $this->level_depth) {
  1241. $this->level_depth = $menu_level;
  1242. }
  1243. } // user type check
  1244. } // memberof
  1245. } while ($item->get_next());
  1246.  
  1247. // Assign children lists
  1248. foreach ($mno_children as $mopid => $childlist) {
  1249. $menuitem = $this->menu_ops[$mopid];
  1250. $menuitem->children = $childlist;
  1251. $this->menu_ops[$mopid] = $menuitem;
  1252. }
  1253. // Register last time we read it..
  1254. $this->last_readts = time() + 10;
  1255.  
  1256. // Get max widths and heights for each level..
  1257. $this->level_widths = array();
  1258. $this->level_heights = array();
  1259. for ($level = 0; $level <= $this->level_depth; $level++) {
  1260. $q = "SELECT MAX(width) AS maxw, MAX(height) AS maxh";
  1261. $q .= " FROM ax_menuoption";
  1262. $q .= " WHERE menu_id=$this->menu_id";
  1263. $q .= " AND menu_level=$level";
  1264. $moQ = dbrecordset($q);
  1265. if ($moQ->hasdata) {
  1266. $this->level_widths[$level] = $moQ->field("maxw");
  1267. $this->level_heights[$level] = $moQ->field("maxh");
  1268. }
  1269. } // for
  1270.  
  1271. } // hasdata
  1272. } // get
  1273.  
  1274.  
  1275.  
  1276. } // menu_instance class
  1277.  
  1278. ?>

Documentation generated by phpDocumentor 1.3.0RC3