Zurück zur PHP-Seite

<?php
/**
* Bilingual Cascading Navigation Class
* Requires PHP >= 4.1 (or small changes) since super-global array
*   $_SERVER is used
* Requires data file catdata.inc, defining:
*   $cat: array of page key names (main categories) and sub-arrays at
*     $cat[page] (main categories with sub-pages) that are defined like
*     $cat (i.e., recursively). Names must all be different.
*   $size: array with page key names of all categories with sub-pages
*     as keys and the corresponding page count as values
*   $data: 2D array $data[page key name][name|link], values are arrays
*     with values (de,en). Links are homepage-relative when they start
*     with a slash (page relativity calculation relys on that!),
*     otherwise they have to be complete URLs.
* Simplified design customization through CSS
* Another language should be easy to implement
* Tree init. tests for file existence, thus data file can hold complete
*   structure for all languages without the need to have all translated
*   versions of the files present.
* @author 2005,2006 Jens Hatlak <jh@junetz.de>
* @version 1.12 2006-02-20
*/
class CascadeNav {
/**
  * Array of categories
  * @var array
  */
  
var $cat;
/**
  * Array of category sizes
  * @var array
  */
  
var $size;
/**
  * Array of category data
  * @var array
  */
  
var $data;
/**
  * Key name of current page
  * @var string
  */
  
var $page;
/**
  * Language (0=de, 1=en)
  * @var int
  */
  
var $lang;
/**
  * Array of compiled tree ready to be read row-wise
  * @var array
  */
  
var $tree;
/**
  * Max depth of categories,
  * at least enough space for main categories plus
  * language switch (flag)
  * @var int
  */
  
var $depth;
/**
  * Relative path from HP root to current page
  * @var string
  */
  
var $relpath;
/**
  * Homepage root
  * @var string
  */
  
var $hpRoot;

/**
  * Constructor, determines current page, language and relative path
  * (including trailing slash!) according to $hpRoot, $fileExt
  * (optional parameters), $_SERVER["SCRIPT_NAME"] and data from file
  * ./catdata.inc; initializes internal tree
  * @param string $hpRoot Homepage root path relative to server root
  * @param string $fileExt Extension for homepage
  * files (pages)
  */
  
function CascadeNav($hpRoot=""$fileExt="php4") {
    if (empty(
$hpRoot)) {
      switch (
$_SERVER["HTTP_HOST"]) {
        case 
"localhost":
          
$hpRoot "/online/Homepage";
          break;
        case 
"jens.hatlak.de":
        case 
"jh.junetz.de":
          
$hpRoot "";
          break;
        default:
          
$hpRoot "/members/jh";
      }
    }
    
$this->hpRoot $hpRoot;
    include(
dirname(__FILE__)."/catdata.inc");
    
$this->cat  =& $cat;
    
$this->size =& $size;
    
$this->data =& $data;

    
$pattern "/".str_replace("/","\/",$hpRoot)."((.*\/).*\.".$fileExt.")/";
    
preg_match($pattern$_SERVER["PHP_SELF"], $matches);
    
$this->relpath $matches[2];
    foreach (
$this->data as $name=>$page) {
      for (
$i=0;$i<count($page["link"]);$i++) {
        if (
$page["link"][$i]==$matches[1]) {
          
$this->page $name;
          
$this->lang $i;
        }
      }
    }
    if (!isset(
$this->page))
      die(
"Could not find '".$matches[1]."' in data array!");

    
$this->initTree();
    
// ensure there's enough space for the language switch (flag)
    
$lssp $this->size["cat"]+3;
    if (
$this->depth $lssp)
      
$this->depth $lssp;
  }

/**
  * Determines alternate language depending on current language
  * @return int Alternate language (0=de, 1=en)
  */
  
function altLang() {
    switch (
$this->lang) {
      case 
1: return 0;
      case 
0: default: return 1;
    }
  }

/**
  * Recursively checks if current page is (under)
  * one of the categories in $cats
  * @param array $cats Array of category key names
  * @return boolean Result
  */
  
function sub($cats) {
    if (!
is_array($cats)) return false;
    foreach (
$cats as $cat) {
      if (!
is_array($cat) &&
          (
$this->page==$cat ||
           
is_array($cats[$cat]) && $this->sub($cats[$cat])))
        return 
true;
    }
    return 
false;
  }

/**
  * Checks wether a path exists (as part of the HP or as URL)
  * @param string $file Path absolute to homepage root or URL
  * @return boolean TRUE, if path is valid or a URL
  */
  
function exists($path) {
    if (
ereg("://"$path)) return true;
    if (empty(
$path)) return false;
    return 
file_exists($_SERVER["DOCUMENT_ROOT"].$this->hpRoot.$path);
  }

/**
  * Recursively initializes internal tree.
  * Files that don't exists result in their
  * category entry and sub-entries not to be displayed.
  * @param array $cats Array of category key names
  * or NULL (start with top category level)
  * @param int $i Row offset
  */
  
function initTree($cats=NULL$i=0) {
    if (
$cats==NULL)
      
$cats $this->cat;
    if (!
is_array($cats))
      return;
    foreach (
$cats as $cat) {
      if (!
is_array($cat) &&
          !empty(
$this->data[$cat]["link"][$this->lang]) &&
          
$this->exists($this->data[$cat]["link"][$this->lang])) {
        
$col[$i] = $cat;
        if (
is_array($cats[$cat]) && ($this->sub($cats[$cat]) ||
            
$this->page==$cat))
          
$this->initTree($cats[$cat], $i);
        
$i++;
      }
    }
    if (
$i>$this->depth)
      
$this->depth $i;
    if (!isset(
$this->tree))
      
$this->tree = array();
    
// queue at the front
    
array_unshift($this->tree$col);
  }


/**
  * Recursively determines path of $link relative to current page.
  * @param string $link Some URL
  * @param string $relpath If NULL, equals relative path from HP root
  * to current page. Being shortened by the last directory at the end
  * of each recursion level, this is what is tried to be found at the
  * front of $link.
  * @param string $backstr Accumulation for "../" strings
  * @return string Relative path
  */
  
function rel($link$relpath=NULL$backstr="") {
    if (
substr($link01)!='/' || strstr($link"://"))
      return;
    if (
$relpath==NULL)
      
$relpath $this->relpath;
    if (empty(
$link) || strpos($link$relpath)===0)
      return 
$backstr.substr($link,strlen($relpath));

    
// one level up
    
$relpath substr($relpath0, -1);
    
$relpath substr($relpath0strrpos($relpath'/')+1);
    
$backstr .= "../";
    return 
$this->rel($link$relpath$backstr);
  }

/**
  * Get language switch link of current page
  * @return string Absolute path of the counterpart
  * of the current page in the other language
  */
  
function getLangSwitchLink() {
    
$links $this->data[$this->page]["link"];
    
$altLang $this->altLang();
    if (
count($links) <= $altLang)
      return 
null;
    return 
$links[$altLang];
  }

/**
  * Guess accept language from HTTP information:
  * Result is German (de) or English (en)
  * Default is English (en)
  * @return int Language (0: de, 1: en)
  */
  
function getAcceptLang() {
    
$accept_langs explode(","$_SERVER["HTTP_ACCEPT_LANGUAGE"]);
    foreach (
$accept_langs as $lang) {
      
// filter out weightings
      
if (($pos=strpos($lang";")) !== false)
        
$lang substr($lang0$pos);

      if (
$lang=="de" || strpos($lang"de-")!==false)
        return 
0// de
      
if ($lang=="en" || strpos($lang"en-")!==false)
        return 
1// en
    
}
    return 
1;
  }

/**
  * Prints one full HTML row of the navigation table.
  * The language switch flag is only displayed if the
  * translated page (file) exists.
  * Images used: /images/flags/flagger.gif, /images/flags/flageng.gif
  * (both 35x22) and /images/separator.gif (13x13)
  * CSS classes used: 'sectionpath' (for parentcategories of current
  * page), 'sectionsel' for current page and 'sectionX' for all
  * categories of column/level X.
  * @param int $i Number of row to be printed
  * @param string $target Optional HTML link target (for all links)
  */
  
function printLine($i$target="") {
    if (empty(
$this->tree))
      return 
false;

    
// German
    
$title[0] = "Diese Seite\nin deutsch";
    
$src[0] = "/images/flags/flagger.gif";
    
// English
    
$title[1] = "This page\nin English";
    
$src[1] = "/images/flags/flageng.gif";

    
$langswlink $this->getLangSwitchLink();

    echo 
"<tr>\n";
    
// loop through all columns/levels
    
for ($j=0;$j<count($this->tree);$j++) {
      
$cat $this->tree[$j][$i];
      
$name $this->data[$cat]["name"][$this->lang];
      
$link $this->data[$cat]["link"][$this->lang];
      if (
substr($link01)=="/")
        
$link = (strlen($link)=="." $this->rel($link));

      
// section path
      
if ($j+1<count($this->tree) && isset($this->tree[$j+1][$i]) &&
          (
$i==|| !isset($this->tree[$j+1][$i-1]))) {
        
printf("  <td class=\"sectionpath\"><a href=\"%s\">%s</a></td>\n",
               
$link$name);
        
printf("  <td><img src=\"%s\" width=\"13\" height=\"13\" alt=\"/\"></td>\n",
               
$this->rel("/images/separator.gif"));
      } else

      if (isset(
$cat)) {
        if (
$cat==$this->page)
          
// current page
          
printf("  <td class=\"sectionsel\">%s</td>\n"$name);
        else
          
// level entry
          
printf("  <td class=\"section%d\"><a href=\"%s\"%s>%s</a></td>\n",
                 
$j+1$link, ($target!="" " target=\"$target\"" ""), $name);
        echo 
"  <td>&nbsp;</td>\n";
      } else

      
// first column: space for language switch (reserved in constructor)
      
if ($j==&& $i==$this->size["cat"]+1) {
        if (
$this->exists($langswlink)) {
          
printf("  <td rowspan=\"2\" class=\"langswitch\"><a href=\"%1\$s\"%2\$s><img ".
                 
"src=\"%3\$s\" width=\"35\" height=\"22\" border=\"0\" ".
                 
"alt=\"%4\$s\" title=\"%4\$s\"></a>\n%5\$s</td>\n",
                 
$this->rel($langswlink),
                 (
$target!="" " target=\"$target\"" ""),
                 
$this->rel($src[$this->altLang()]),
                 
str_replace("\n"" "$title[$this->altLang()]),
                 
nl2br($title[$this->altLang()]));
           echo 
"  <td rowspan=\"2\">&nbsp;</td>\n";
        } else
          echo 
"  <td colspan=\"2\">&nbsp;</td>\n";
      } else

      
// no entry
      
if ($j!=|| !$this->exists($langswlink) || $i!=$this->size["cat"]+2)
        echo 
"  <td colspan=\"2\">&nbsp;</td>\n";
    }
    echo 
"</tr>\n";
  }

/**
  * Print naviagtion table
  * @param boolean $tableTag print complete table
  * with opening/closing tags and alternative language note where applicable
  * @param string $target Optional HTML link target (for all links)
  */
  
function printNav($tableTag=true$target="") {
    if (empty(
$this->tree)) return false;
    if (
$tableTag)
      echo 
"<table border=\"0\" summary=\"Navigation\">\n";
    for (
$i=0;$i<$this->depth;$i++)
      
$this->printLine($i$target);
    if (
$tableTag) {
      echo 
"</table>\n";
      
$this->printAltLangNote($target);
    }
  }

  function 
printAltLangNote($target="") {
    if (
$this->lang != $this->getAcceptLang()) {
      
$langswlink $this->getLangSwitchLink();
      if (
$this->exists($langswlink)) {
        if (
$this->lang==0) { // de
          
$text "Do you prefer reading pages in English?";
          
$linktext "This page is also available in English.";
        } else
        if (
$this->lang==1) { // en
          
$text "Bevorzugen Sie Texte in deutscher Sprache?";
          
$linktext "Diese Seite ist auch auf Deutsch verf&uuml;gbar.";
        }
        
printf("<p class=\"altlangnote\">%s\n<a href=\"%s\">%s</a></p>\n",
          
$text$this->rel($langswlink), $linktext);
      }
    }
  }
}
?>