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

Documentation generated by phpDocumentor 1.3.0RC3