Andrew's Web Libraries (AWL)
MenuSet.php
1 <?php
15 require_once("AWLUtilities.php");
16 
21 class MenuOption {
29  var $label;
30 
35  var $target;
36 
41  var $title;
42 
47  var $active;
48 
53  var $sortkey;
54 
59  var $style;
60 
65  var $submenu_set;
72  var $self;
73 
81  var $rendered;
92  function __construct( $label, $target, $title="", $style="menu", $sortkey=1000 ) {
93  $this->label = $label;
94  $this->target = $target;
95  $this->title = $title;
96  $this->style = $style;
97  $this->attributes = array();
98  $this->active = false;
99  $this->sortkey = $sortkey;
100 
101  $this->rendered = "";
102  $this->self =& $this;
103  }
104 
109  function Render( ) {
110  $r = sprintf('<a href="%s" class="%s" title="%s"%s>%s</a>',
111  $this->target, $this->style, htmlspecialchars($this->title), "%%attributes%%",
112  htmlspecialchars($this->label), $this->style );
113 
114  // Now process the generic attributes
115  $attribute_values = "";
116  foreach( $this->attributes AS $k => $v ) {
117  if ( substr($k, 0, 1) == '_' ) continue;
118  $attribute_values .= ' '.$k.'="'.htmlspecialchars($v).'"';
119  }
120  $r = str_replace( '%%attributes%%', $attribute_values, $r );
121 
122  $this->rendered = $r;
123  return "$r";
124  }
125 
131  function Set( $attribute, $value ) {
132  $this->attributes[$attribute] = $value;
133  }
134 
139  function Active( $style=false ) {
140  $this->active = true;
141  if ( $style ) $this->style = $style;
142  }
143 
147  function AddSubmenu( &$submenu_set ) {
148  $this->submenu_set = &$submenu_set;
149  }
150 
155  function IsActive( ) {
156  return ( $this->active );
157  }
158 
163  function MaybeActive( $test_pattern, $active_style ) {
164  if ( is_string($test_pattern) && preg_match($test_pattern,$_SERVER['REQUEST_URI']) ) {
165  $this->Active($active_style);
166  }
167  return ( $this->active );
168  }
169 }
170 
171 
179 function _CompareMenuSequence( $a, $b ) {
180  dbg_error_log("MenuSet", ":_CompareMenuSequence: Comparing %d with %d", $a->sortkey, $b->sortkey);
181  return ($a->sortkey - $b->sortkey);
182 }
183 
184 
185 
222 class MenuSet {
230  var $div_id;
231 
236  var $main_class;
237 
242  var $active_class;
243 
248  var $options;
249 
254  var $parent;
255 
260  var $last_sortkey;
261 
267  var $has_active_options;
276  function __construct( $div_id, $main_class = '', $active_class = 'active' ) {
277  $this->options = array();
278  $this->main_class = $main_class;
279  $this->active_class = $active_class;
280  $this->div_id = $div_id;
281  }
282 
295  function &AddOption( $label, $target, $title="", $active=false, $sortkey=null, $external=false ) {
296  if ( !isset($sortkey) ) {
297  $sortkey = (isset($this->last_sortkey) ? $this->last_sortkey + 100 : 1000);
298  }
299  $this->last_sortkey = $sortkey;
300  if ( version_compare(phpversion(), '5.0') < 0) {
301  $new_option = new MenuOption( $label, $target, $title, $this->main_class, $sortkey );
302  }
303  else {
304  $new_option = new MenuOption( $label, $target, $title, $this->main_class, $sortkey );
305  }
306  if ( ($old_option = $this->_OptionExists( $label )) === false ) {
307  $this->options[] = &$new_option ;
308  }
309  else {
310  dbg_error_log("MenuSet",":AddOption: Replacing existing option # $old_option ($label)");
311  $this->options[$old_option] = &$new_option; // Overwrite the existing option
312  }
313  if ( is_bool($active) && $active == false && $_SERVER['REQUEST_URI'] == $target ) {
314  // If $active is not set, then we look for an exact match to the current URL
315  $new_option->Active( $this->active_class );
316  }
317  else if ( is_bool($active) && $active ) {
318  // When active is specified as a boolean, the recognition has been done externally
319  $new_option->Active( $this->active_class );
320  }
321  else if ( is_string($active) && preg_match($active,$_SERVER['REQUEST_URI']) ) {
322  // If $active is a string, then we match the current URL to that as a Perl regex
323  $new_option->Active( $this->active_class );
324  }
325 
326  if ( $external == true ) $new_option->Set('target', '_blank');
327 
328  return $new_option ;
329  }
330 
341  function &AddSubMenu( &$submenu_set, $label, $target, $title="", $active=false, $sortkey=2000 ) {
342  $new_option =& $this->AddOption( $label, $target, $title, $active, $sortkey );
343  $submenu_set->parent = &$new_option ;
344  $new_option->AddSubmenu( $submenu_set );
345  return $new_option ;
346  }
347 
354  function _HasActive( ) {
355  if ( isset($this->has_active_options) ) {
356  return $this->has_active_options;
357  }
358  foreach( $this->options AS $k => $v ) {
359  if ( $v->IsActive() ) {
360  $rc = true;
361  return $rc;
362  }
363  }
364  $rc = false;
365  return $rc;
366  }
367 
372  function Size( ) {
373  return count($this->options);
374  }
375 
380  function _OptionExists( $newlabel ) {
381  $rc = false;
382  foreach( $this->options AS $k => $v ) {
383  if ( $newlabel == $v->label ) return $k;
384  }
385  return $rc;
386  }
387 
395  function LinkActiveSubMenus( ) {
396  $this->has_active_options = false;
397  foreach( $this->options AS $k => $v ) {
398  if ( isset($v->submenu_set) && $v->submenu_set->_HasActive() ) {
399  // Note that we need to do it this way, since $v is a copy, not a reference
400  $this->options[$k]->Active( $this->active_class );
401  $this->has_active_options = true;
402  }
403  }
404  }
405 
413  function MakeSomethingActive( $test_pattern ) {
414  if ( $this->has_active_options ) return; // Already true.
415  foreach( $this->options AS $k => $v ) {
416  if ( isset($v->submenu_set) && $v->submenu_set->_HasActive() ) {
417  // Note that we need to do it this way, since $v is a copy, not a reference
418  $this->options[$k]->Active( $this->active_class );
419  $this->has_active_options = true;
420  return $this->has_active_options;
421  }
422  }
423 
424  foreach( $this->options AS $k => $v ) {
425  if ( isset($v->submenu_set) && $v->submenu_set->MakeSomethingActive($test_pattern) ) {
426  // Note that we need to do it this way, since $v is a copy, not a reference
427  $this->options[$k]->Active( $this->active_class );
428  $this->has_active_options = true;
429  return $this->has_active_options;
430  }
431  else {
432  if ( $this->options[$k]->MaybeActive( $test_pattern, $this->active_class ) ) {
433  $this->has_active_options = true;
434  return $this->has_active_options;
435  }
436  }
437  }
438  return false;
439  }
440 
448  function _CompareSequence( $a, $b ) {
449  dbg_error_log("MenuSet",":_CompareSequence: Comparing %d with %d", $a->sortkey, $b->sortkey);
450  return ($a->sortkey - $b->sortkey);
451  }
452 
453 
462  function Render( $submenus_inline = false ) {
463  if ( !isset($this->has_active_options) ) {
464  $this->LinkActiveSubMenus();
465  }
466  $options = $this->options;
467  usort($options,"_CompareMenuSequence");
468  $render_sub_menus = false;
469  $r = "<div id=\"$this->div_id\">\n";
470  foreach( $options AS $k => $v ) {
471  $r .= $v->Render();
472  if ( $v->IsActive() && isset($v->submenu_set) && $v->submenu_set->Size() > 0 ) {
473  $render_sub_menus = $v->submenu_set;
474  if ( $submenus_inline )
475  $r .= $render_sub_menus->Render();
476  }
477  }
478  $r .="</div>\n";
479  if ( !$submenus_inline && $render_sub_menus != false ) {
480  $r .= $render_sub_menus->Render();
481  }
482  return $r;
483  }
484 
485 
494  function RenderAsCSS( $depth = 0, $skip_empty = true ) {
495  $this->LinkActiveSubMenus();
496 
497  if ( $depth > 0 )
498  $class = "submenu" . $depth;
499  else
500  $class = "menu";
501 
502  $options = $this->options;
503  usort($options,"_CompareMenuSequence");
504 
505  $r = "<div id=\"$this->div_id\" class=\"$class\">\n<ul>\n";
506  foreach( $options AS $k => $v ) {
507  if ( $skip_empty && isset($v->submenu_set) && $v->submenu_set->Size() < 1 ) continue;
508  $r .= "<li>".$v->Render();
509  if ( isset($v->submenu_set) && $v->submenu_set->Size() > 0 ) {
510  $r .= $v->submenu_set->RenderAsCSS($depth+1);
511  }
512  $r .= "</li>\n";
513  }
514  $r .="</ul></div>\n";
515  return $r;
516  }
517 }
MenuSet
Definition: MenuSet.php:222
MenuSet\Size
Size()
Definition: MenuSet.php:372
MenuSet\AddSubMenu
& AddSubMenu(&$submenu_set, $label, $target, $title="", $active=false, $sortkey=2000)
Definition: MenuSet.php:341
MenuOption\__construct
__construct( $label, $target, $title="", $style="menu", $sortkey=1000)
Definition: MenuSet.php:92
MenuSet\__construct
__construct( $div_id, $main_class='', $active_class='active')
Definition: MenuSet.php:276
MenuOption\Set
Set( $attribute, $value)
Definition: MenuSet.php:131
MenuSet\RenderAsCSS
RenderAsCSS( $depth=0, $skip_empty=true)
Definition: MenuSet.php:494
MenuOption
Definition: MenuSet.php:21
MenuSet\AddOption
& AddOption( $label, $target, $title="", $active=false, $sortkey=null, $external=false)
Definition: MenuSet.php:295
MenuSet\_OptionExists
_OptionExists( $newlabel)
Definition: MenuSet.php:380
MenuOption\Active
Active( $style=false)
Definition: MenuSet.php:139
MenuSet\MakeSomethingActive
MakeSomethingActive( $test_pattern)
Definition: MenuSet.php:413
MenuSet\_HasActive
_HasActive()
Definition: MenuSet.php:354
MenuOption\AddSubmenu
AddSubmenu(&$submenu_set)
Definition: MenuSet.php:147
MenuOption\MaybeActive
MaybeActive( $test_pattern, $active_style)
Definition: MenuSet.php:163
MenuSet\Render
Render( $submenus_inline=false)
Definition: MenuSet.php:462
MenuSet\LinkActiveSubMenus
LinkActiveSubMenus()
Definition: MenuSet.php:395
MenuOption\IsActive
IsActive()
Definition: MenuSet.php:155
MenuSet\_CompareSequence
_CompareSequence( $a, $b)
Definition: MenuSet.php:448
MenuOption\Render
Render()
Definition: MenuSet.php:109