<?php
/*
* Filename.....: class_infobox.php
* Aufgabe......: Generate floating infobox tips as seen at http://www.knoppix.de
* Parameter....: none
* Erstellt am..: Dienstag, 1. März 2005
* _ __ _ _
* ||| | |/ / (_) | Wirtschaftsinformatiker IHK
* \. ./| ' / _ __ _| |_ ___ www.ingoknito.de
* - ^ -| < | '_ \| | __/ _ \
* / - \| . \| | | | | || (_) | Peter Klauer
* ||| |_|\_\_| |_|_|\__\___/ 06131-651236
* mailto.......: hide@address.com
*
* Makes use of infobox.js (C) 2002 Klaus Knopper <hide@address.com>
* distributed under the GNU GENERAL PUBLIC LICENSE Version 2.
*
* The class generates screenreader friendly floating infoboxes.
* This class frees the programmer from the hazzle of thinking of
* a new name (which is never shown anywhere) for every single infobox.
* It collects all the infos straightforward into an array and generates
* the boxes at the end of the page.
* Transforms boxes to standard title attributes when switched off per cookie.
*
* Some error checking is done via $called_head and $called_generate.
*
* History:
* 2006-07-19: Bugfix: Had to rename infobox.dummy to infobox.html because IE wanted
* to download it.
* 2006-07-18: Bugfix: <select> Problem solved: Infobox floated UNDER select boxes
* in MSIE. This is fixed now with an <iframe>-hack submitted by
* Oleg Baranovsky. Thank you, Mr. Baranovsky!
* The new EMPTY file "infobox.dummy" is only used to prevent server
* error messages when trying to read the src of the iframe.
* 2006-04-28: onoff(): global $_SERVER instead of global $PHP_SELF
* 2006-04-20: Bugfix from Mike White (mike [at] white [minus] home [dot] com)
* for scrolled position in netscape and Mozilla
* 2005-03-25: Changed onoff() howto: Clean the resulting page code if infoboxes
* are switched off by the user. Only infobox.js is included via
* the <script> statement because of "setcookie"
* 2005-03-23: Changed onoff() link
* 2005-03-17: infobox::onoff corrected to infobox::onoff_onoff
* 2005-03-15: After a mouseclick on a infobox-link sometimes the mouseout-event
* does not hide the infobox layer away. It stays visible at position
* top=0, left=0. Giving the "infodiv" and div.infobox in infobox.css
* a "left" position of -10000px moves it out of sight.
* Head only holds js function showtip().
* maketip(), getScrollXY() and SetCookie() have moved to infobox.js.
* 2005-03-13: New: onoff link for enhanced screenreader compatibility or "calmer"
* pages switch infoboxes off using a cookie named "infobox"
* 2005-03-10: Generated HTML Code (strict!) did not validate because of
* LANGUAGE=\"JavaScript\" in the <script> sections of infobox::head()
* and infobox::generate()
* 2005-03-09: JS maketip() is also replaced when $replace_javascript is true.
* Var $replace_showtip is renamed to $replace_javascript.
* The new js function maketip() does not use many tables but 3 div sections.
* Changed infobox.css to hold meaningful infobox classes that work.
* 2005-03-08: infobox::newtip() replaces </ with <\/ to have w3c-html-tidy-proof javascript code
*
*/
class infobox
{
#
# user vars
#
var $before = ''; // output this before a link is done
var $after = ' '; // output this after a link is done
var $showinfobox = true; // show them infoboxes, really?
var $debug = false; // show debugging status line
var $pathtoinfobox = ''; // path to infobox parts
#
# highlighting css class or inline style for infoboxed elements
#
var $class = '';
var $style = '';
var $onoff_linktext = 'InfoBox';
var $onoff_onoff = array( 'ON', 'OFF' );
var $onoff_caption = 'Infobox';
var $onoff_description = 'Switch infobox ';
var $onoff_written = false; // Flag for ScreenReader friendlyness
var $onoff_days = 30; // Number of days for infobox cookie expiration
var $lockx = -1; // any positive value including 0 will lock x position
var $locky = -1; // any positive value including 0 will lock y position
var $width = 250; // set IWIDTH of infobox
################################################################################
# internal variables
# starting from here the following vars should not be changed from
#
var $ib_arr = array(); // collects all the infoboxes
var $counter = 0; // internal counter for the infoboxes
var $last_tip = -1;
#
# error checking variables
#
var $called_head = 0;
var $called_generate = 0;
#
####################################################################eof internal
/**
* class constructor
*/
function infobox()
{
if( isset( $_COOKIE['infobox'] ))
{
if( $this->debug) echo $_COOKIE['infobox'];
$this->showinfobox = ( $_COOKIE['infobox'] == 'ON' );
}
}
/**
* inserts loading of infobox.js into head section of html page
* inserts loading of infobox.css into head section of html page
* replaces js function showtip() and sets var IWIDTH to infobox::width
*
* head() is to be called in the head section of the page
*
* @param string $pathtoinfobox = path to infobox.js and infobox.css
* @return void
**/
function head($pathtoinfobox='')
{
$this->pathtoinfobox = $pathtoinfobox;
if( $this->called_head > 0 )
{
$this->error('head(): Was already called '.$this->called_head++.' times.');
return;
}
$this->onoff_description .= $this->onoff_onoff[ ($this->showinfobox*1) ];
// There is SetCookie in it, we need it always!
echo "
<SCRIPT TYPE=\"text/javascript\" SRC=\"$pathtoinfobox"."infobox.js\"></SCRIPT>
";
if( $this->showinfobox )
{
echo "<link rel='Stylesheet' type='text/css' href='$pathtoinfobox"."infobox.css'>
";
echo "
<SCRIPT TYPE=\"text/javascript\">
<!--
var IWIDTH=$this->width ; // set IWIDTH to infobox::width
";
echo "function showtip(){
// this function replaces the original infobox.js::showtip() which was loaded before
// using getScrollXY() it is capable of respecting scrolled positions
// knito - at - knito - dot - de 2005-03-03 http://www.ingoknito.de
// iframe hack submitted by Oleg Baranovsky in July 2006
var xy;
xy = getScrollXY();
";
if( $this->lockx == -1 )
{
echo " idiv.left=(((x+IWIDTH+20)<winW)?x+12:x-IWIDTH-5)+xy[0]+px;
";
}
else
{
echo " idiv.left=".$this->lockx."+px;
";
}
if( $this->locky == -1 )
{
// Code added 4/18/06 by Mike White
echo " y=y>window.innerHeight?window.innerHeight-(winH-y):y;
";
// End code added
echo " idiv.top=(((y+90)<winH)?y+12: y-90)+xy[1]+px;
";
}
else
{
echo " idiv.top=".$this->locky."+px;
";
}
echo " idiv.visibility=ns4?\"show\":\"visible\";
";
echo "
/**
* now we need to reposition the hidden iframe underneath our idiv
* and resize it to the same size as idiv.
* also set it up with z-index smaller than for idiv
*/
if( ie4 || ie5 )
{
idivif=document.getElementById('infodivif');
if (idivif)
{
idivif.style.width = idiv1.offsetWidth;
idivif.style.height = idiv1.offsetHeight;
idivif.style.top = idiv.top;
idivif.style.left = idiv.left;
idivif.style.visibility = 'visible';
}
}
";
if( $this->debug)
{
echo " window.status = 'winH: '+winH+ ' y: '+y+' xy[1]:'+xy[1]+' idiv.top:'+idiv.top;
";
}
echo "}
// -->
</script>
"; // end of echo the javascript functions
} // showinfobox == true
$this->called_head++;
} // eof head()
/**
* writes a hyperlink and fills an array and increases a static counter
*
* @param string $url = url where to go to
* @param string $text = text (img) to click upon
* @param string $caption = caption in infobox
* @param string $description = descriptive text to appear in infobox
* @param string $target = target window for hyperlink, empty by default
* @return void
**/
function link( $url, $text, $caption, $description, $target='' )
{
$t = $target == '' ? '' : " target='$target'";
echo $this->before;
echo "<a href='$url'".$this->newtip($caption,$description)."$t>$text</a>";
echo $this->after;
} // eof link()
/**
* returns a string that contains onMouseOver and onMouseOut for a certain infobox
* @param integer $number = number of the tip to output
* @return string
**/
function thistip( $number )
{
$c = $this->class == '' ? '' : ' class="'.$this->class.'"';
$s = $this->style == '' ? '' : ' style="'.$this->style.'"';
$result = "$c$s onMouseOver=\"tip('infobox$number')\" onMouseOut=\"untip()\"";
return $result;
} // eof thistip()
/**
* generates a new infobox and
* returns a string that contains onMouseOver and onMouseOut for this infobox
* If you need quotes in $caption or $description always use
* "double quotes".
*
* @param string $caption = caption of the infobox
* @param string $description = descriptive text in body of infobox, may contain html code
* @return string
**/
function newtip( $caption, $description )
{
$ok = true;
$result = '';
if( $this->debug )
{
$caption = '#'.$this->counter.': '.$caption;
}
if( ( $this->called_head == 0 ) and ($this->showinfobox ))
{
$this->error('newtip(): please call infobox::head() in the head-section of this page!');
$ok = false;
}
if( ( $this->called_generate == 1 ) and ($this->showinfobox ))
{
$this->error( 'newtip(): please call infobox::generate() <b>after</b> all calls to infobox::link()');
$ok = false;
}
if( $ok )
{
#
# Generate screenreader friendly topmost onoff link unvisible to
# normal browsers.
#
if( $this->last_tip == -1 )
{
$this->last_tip = 0; // no Stack overflow, please!
echo "\n".'<div '.$this->unvisiblestyle().'>';
$this->onoff('', true );
echo '</div>';
}
$description = str_replace( "\n", ' ', $description );
$description = str_replace( "\r", ' ', $description );
if( $this->showinfobox )
{
// making it tidy proof 2005-03-08 knito
$caption = str_replace('</','<\\/', $caption);
$description = str_replace( '</','<\\/', $description);
$this->ib_arr[$this->counter] = array( $caption, $description );
$result = $this->thistip($this->counter);
$this->last_tip = $this->counter;
$this->counter++;
}
else
{
$caption = strip_tags( $caption );
$description = strip_tags($description);
$result = " title='$caption: $description' ";
}
}
return $result;
} // eof newtip()
/**
* returns a string that contains onMouseOver and onMouseOut for the last created infobox
* @return string
**/
function lasttip()
{
return $this->thistip($this->last_tip);
} // eof lasttip()
/**
* Generate the div used for infobox,
* generate all tips in a script section.
* This script has to be called at the end of the body section
* after all visible output to the page is done.
* @return void
**/
function generate()
{
#if( !$this->showinfobox ) return;
if( !$this->onoff_written )
{
echo "\n".'<div '.$this->unvisiblestyle().'>';
$this->onoff('', true );
echo '</div>';
}
if( ($this->last_tip == -1 ) and ($this->showinfobox))
{
$this->error( 'generate(): Please call all infobox::newtip()s/link()s before calling me!');
}
else
{
if( $this->showinfobox )
{
echo '<DIV ID="infodiv" STYLE="position:absolute; visibility:hidden; z-index:20; top:0px; left:-10000px;"></DIV>';
#
# workaround for MSIE to show hints over <select> items
# Now we need to use the hidden <iframe> and show it underneath
# our <div> layer in the showtip() function
# As this is only for IE, we use a IE-ONLY comment construct
#
# ... it stops firefox from "shivering" when the iframe moves
# ... and like that it may be always tidy proof!
#
echo '
<!--[if IE]>
<iframe id="infodivif" src="'.$this->pathtoinfobox.'infobox.html" scrolling="no" frameborder="0" style="position:absolute; top:0px; left:0px; visibility:hidden; z-index:19;"></iframe>
<![endif]-->
';
echo "
<SCRIPT TYPE=\"text/javascript\">
<!--
";
for( $i = 0; $i < count( $this->ib_arr ); $i++ )
{
echo "maketip('infobox$i','".$this->ib_arr[$i][0]."', '".$this->ib_arr[$i][1]."');\n";
}
echo "// -->
</SCRIPT>
";
} // showinfobox == true
$this->called_generate = 1;
} // end of else $this->last_tip unlike -1
} // eof generate()
/**
* return a style string for a div section to move it out of sight from normal browsers.
* Screenreaders shall "display" it because the style attribute "visibility" is not set
* to "hidden".
*
* @return string
**/
function unvisiblestyle()
{
return ' style="position:absolute; left:-10000px; top:0; height:0; width:0; overflow:hidden"';
}
/**
* generate a link that sets a cookie to switch infoboxes on or off.
* This link always has a infobox.
*
* @param string $url = $PHP_SELF per default
* @param boolean $hidden = Hide this link away if set to true
* @return void
**/
function onoff($url='', $hidden=false)
{
global $_SERVER;
$PHP_SELF = $_SERVER['PHP_SELF'];
if( $url == '' ) $url = $PHP_SELF;
$newvalue = ($this->showinfobox==false) ? $this->onoff_onoff[0] : $this->onoff_onoff[1];
$title = $this->showinfobox ?
' title=\'ScreenReaders: Please set infobox to OFF. Cookies must be enabled.\'' : '';
$expiring = date( 'D, d M Y H:i:s', mktime( date('h'), date('i'), 0, date('m'), (date( 'd')+$this->onoff_days) , date('Y'))). ' GMT';
$mouse = $this->newtip($this->onoff_caption, $this->onoff_description ).$title;
$style = $hidden ? $this->unvisiblestyle() : '';
echo "<a $mouse $style href='$PHP_SELF' onclick='setCookie(\"infobox\", \"$newvalue\", \"$expiring\")'>".
$this->onoff_linktext." $newvalue</a>";
$this->onoff_written = true;
}
/**
* internal error reporting function formats text to look ugly to be sure to be seen
* @param string $message = descriptive text what error it was
**/
function error( $message )
{
echo '<div style="color:red;font-weight:bold;font-size:12pt;font-family:monospace">'.
"infobox::$message</div>";
} // eof error()
}
?>