Back to index

awl  0.53
MenuSet.php
Go to the documentation of this file.
00001 <?php
00015 require_once("AWLUtilities.php");
00016 
00021 class MenuOption {
00029   var $label;
00030 
00035   var $target;
00036 
00041   var $title;
00042 
00047   var $active;
00048 
00053   var $sortkey;
00054 
00059   var $style;
00060 
00065   var $submenu_set;
00072   var $self;
00073 
00081   var $rendered;
00092   function MenuOption( $label, $target, $title="", $style="menu", $sortkey=1000 ) {
00093     $this->label  = $label;
00094     $this->target = $target;
00095     $this->title  = $title;
00096     $this->style  = $style;
00097     $this->attributes = array();
00098     $this->active = false;
00099     $this->sortkey = $sortkey;
00100 
00101     $this->rendered = "";
00102     $this->self  =& $this;
00103   }
00104 
00109   function Render( ) {
00110     $r = sprintf('<a href="%s" class="%s" title="%s"%s>%s</a>',
00111             $this->target, $this->style, htmlspecialchars($this->title), "%%attributes%%",
00112             htmlspecialchars($this->label), $this->style );
00113 
00114     // Now process the generic attributes
00115     $attribute_values = "";
00116     foreach( $this->attributes AS $k => $v ) {
00117       if ( substr($k, 0, 1) == '_' ) continue;
00118       $attribute_values .= ' '.$k.'="'.htmlspecialchars($v).'"';
00119     }
00120     $r = str_replace( '%%attributes%%', $attribute_values, $r );
00121 
00122     $this->rendered = $r;
00123     return "$r";
00124   }
00125 
00131   function Set( $attribute, $value ) {
00132     $this->attributes[$attribute] = $value;
00133   }
00134 
00139   function Active( $style=false ) {
00140     $this->active = true;
00141     if ( $style ) $this->style = $style;
00142   }
00143 
00147   function AddSubmenu( &$submenu_set ) {
00148     $this->submenu_set = &$submenu_set;
00149   }
00150 
00155   function IsActive( ) {
00156     return ( $this->active );
00157   }
00158 
00163   function MaybeActive( $test_pattern, $active_style ) {
00164     if ( is_string($test_pattern) && preg_match($test_pattern,$_SERVER['REQUEST_URI']) ) {
00165       $this->Active($active_style);
00166     }
00167     return ( $this->active );
00168   }
00169 }
00170 
00171 
00179 function _CompareMenuSequence( $a, $b ) {
00180   dbg_error_log("MenuSet", ":_CompareMenuSequence: Comparing %d with %d", $a->sortkey, $b->sortkey);
00181   return ($a->sortkey - $b->sortkey);
00182 }
00183 
00184 
00185 
00222 class MenuSet {
00230   var $div_id;
00231 
00236   var $main_class;
00237 
00242   var $active_class;
00243 
00248   var $options;
00249 
00254   var $parent;
00255 
00260   var $last_sortkey;
00261 
00267   var $has_active_options;
00276   function MenuSet( $div_id, $main_class = '', $active_class = 'active' ) {
00277     $this->options = array();
00278     $this->main_class = $main_class;
00279     $this->active_class = $active_class;
00280     $this->div_id = $div_id;
00281   }
00282 
00295   function &AddOption( $label, $target, $title="", $active=false, $sortkey=null, $external=false ) {
00296     if ( !isset($sortkey) ) {
00297       $sortkey = (isset($this->last_sortkey) ? $this->last_sortkey + 100 : 1000);
00298     }
00299     $this->last_sortkey = $sortkey;
00300     if ( version_compare(phpversion(), '5.0') < 0) {
00301       $new_option = new MenuOption( $label, $target, $title, $this->main_class, $sortkey );
00302     }
00303     else {
00304       $new_option = new MenuOption( $label, $target, $title, $this->main_class, $sortkey );
00305     }
00306     if ( ($old_option = $this->_OptionExists( $label )) === false ) {
00307       $this->options[] = &$new_option ;
00308     }
00309     else {
00310       dbg_error_log("MenuSet",":AddOption: Replacing existing option # $old_option ($label)");
00311       $this->options[$old_option] = &$new_option;  // Overwrite the existing option
00312     }
00313     if ( is_bool($active) && $active == false && $_SERVER['REQUEST_URI'] == $target ) {
00314       // If $active is not set, then we look for an exact match to the current URL
00315       $new_option->Active( $this->active_class );
00316     }
00317     else if ( is_bool($active) && $active ) {
00318       // When active is specified as a boolean, the recognition has been done externally
00319       $new_option->Active( $this->active_class );
00320     }
00321     else if ( is_string($active) && preg_match($active,$_SERVER['REQUEST_URI']) ) {
00322       // If $active is a string, then we match the current URL to that as a Perl regex
00323       $new_option->Active( $this->active_class );
00324     }
00325 
00326     if ( $external == true ) $new_option->Set('target', '_blank');
00327 
00328     return $new_option ;
00329   }
00330 
00341   function &AddSubMenu( &$submenu_set, $label, $target, $title="", $active=false, $sortkey=2000 ) {
00342     $new_option =& $this->AddOption( $label, $target, $title, $active, $sortkey );
00343     $submenu_set->parent = &$new_option ;
00344     $new_option->AddSubmenu( $submenu_set );
00345     return $new_option ;
00346   }
00347 
00354   function _HasActive( ) {
00355     if ( isset($this->has_active_options) ) {
00356       return $this->has_active_options;
00357     }
00358     foreach( $this->options AS $k => $v ) {
00359       if ( $v->IsActive() ) {
00360         $rc = true;
00361         return $rc;
00362       }
00363     }
00364     $rc = false;
00365     return $rc;
00366   }
00367 
00372   function Size( ) {
00373     return count($this->options);
00374   }
00375 
00380   function _OptionExists( $newlabel ) {
00381     $rc = false;
00382     foreach( $this->options AS $k => $v ) {
00383       if ( $newlabel == $v->label ) return $k;
00384     }
00385     return $rc;
00386   }
00387 
00395   function LinkActiveSubMenus( ) {
00396     $this->has_active_options = false;
00397     foreach( $this->options AS $k => $v ) {
00398       if ( isset($v->submenu_set) && $v->submenu_set->_HasActive() ) {
00399         // Note that we need to do it this way, since $v is a copy, not a reference
00400         $this->options[$k]->Active( $this->active_class );
00401         $this->has_active_options = true;
00402       }
00403     }
00404   }
00405 
00413   function MakeSomethingActive( $test_pattern ) {
00414     if ( $this->has_active_options ) return;  // Already true.
00415     foreach( $this->options AS $k => $v ) {
00416       if ( isset($v->submenu_set) && $v->submenu_set->_HasActive() ) {
00417         // Note that we need to do it this way, since $v is a copy, not a reference
00418         $this->options[$k]->Active( $this->active_class );
00419         $this->has_active_options = true;
00420         return $this->has_active_options;
00421       }
00422     }
00423 
00424     foreach( $this->options AS $k => $v ) {
00425       if ( isset($v->submenu_set) && $v->submenu_set->MakeSomethingActive($test_pattern) ) {
00426         // Note that we need to do it this way, since $v is a copy, not a reference
00427         $this->options[$k]->Active( $this->active_class );
00428         $this->has_active_options = true;
00429         return $this->has_active_options;
00430       }
00431       else {
00432         if ( $this->options[$k]->MaybeActive( $test_pattern, $this->active_class ) ) {
00433           $this->has_active_options = true;
00434           return $this->has_active_options;
00435         }
00436       }
00437     }
00438     return false;
00439   }
00440 
00448   function _CompareSequence( $a, $b ) {
00449     dbg_error_log("MenuSet",":_CompareSequence: Comparing %d with %d", $a->sortkey, $b->sortkey);
00450     return ($a->sortkey - $b->sortkey);
00451   }
00452 
00453 
00462   function Render( $submenus_inline = false ) {
00463     if ( !isset($this->has_active_options) ) {
00464       $this->LinkActiveSubMenus();
00465     }
00466     $options = $this->options;
00467     usort($options,"_CompareMenuSequence");
00468     $render_sub_menus = false;
00469     $r = "<div id=\"$this->div_id\">\n";
00470     foreach( $options AS $k => $v ) {
00471       $r .= $v->Render();
00472       if ( $v->IsActive() && isset($v->submenu_set) && $v->submenu_set->Size() > 0 ) {
00473         $render_sub_menus = $v->submenu_set;
00474         if ( $submenus_inline )
00475           $r .= $render_sub_menus->Render();
00476       }
00477     }
00478     $r .="</div>\n";
00479     if ( !$submenus_inline && $render_sub_menus != false ) {
00480       $r .= $render_sub_menus->Render();
00481     }
00482     return $r;
00483   }
00484 
00485 
00494   function RenderAsCSS( $depth = 0, $skip_empty = true ) {
00495     $this->LinkActiveSubMenus();
00496 
00497     if ( $depth > 0 )
00498       $class = "submenu" . $depth;
00499     else
00500       $class = "menu";
00501 
00502     $options = $this->options;
00503     usort($options,"_CompareMenuSequence");
00504 
00505     $r = "<div id=\"$this->div_id\" class=\"$class\">\n<ul>\n";
00506     foreach( $options AS $k => $v ) {
00507       if ( $skip_empty && isset($v->submenu_set) && $v->submenu_set->Size() < 1 ) continue;
00508       $r .= "<li>".$v->Render();
00509       if ( isset($v->submenu_set) && $v->submenu_set->Size() > 0 ) {
00510         $r .= $v->submenu_set->RenderAsCSS($depth+1);
00511       }
00512       $r .= "</li>\n";
00513     }
00514     $r .="</ul></div>\n";
00515     return $r;
00516   }
00517 }