PageRenderTime 54ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/php-getid3-2.0.0b5/extras/abstraction.php

#
PHP | 2597 lines | 1532 code | 512 blank | 553 comment | 275 complexity | cefb82678fdba53a31702d5a194bf756 MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. // +----------------------------------------------------------------------+
  3. // | PHP version 5.1.4 |
  4. // +----------------------------------------------------------------------+
  5. // | Placed in public domain by Allan Hansen, 2003-2006. |
  6. // | Share and enjoy! |
  7. // +----------------------------------------------------------------------+
  8. // | Updates and other scripts by Allan Hansen here: |
  9. // | http://www.artemis.dk/php/ |
  10. // +----------------------------------------------------------------------+
  11. // | abstraction.php |
  12. // | Abstract PHP classes to generate and output HTML/XML. |
  13. // +----------------------------------------------------------------------+
  14. // | Authors: Allan Hansen <ah@artemis.dk> |
  15. // +----------------------------------------------------------------------+
  16. //
  17. // $Id: abstraction.php,v 1.3 2007/01/08 09:41:11 ah Exp $
  18. /**
  19. * HTML/XML Generator.
  20. *
  21. * @version 1
  22. */
  23. class xml_gen
  24. {
  25. /**
  26. * Generate XML for plain link.
  27. *
  28. * If $uri is false a grey text will be displayed instead.
  29. *
  30. * @param string uri URI to open
  31. * @param string text Text or HTML used for linking
  32. * @param string attr Additional HTML attributes, e.g. "target=main width='100%'".
  33. */
  34. public static function a($uri, $text, $attr = false)
  35. {
  36. if (!$uri) {
  37. return "<span style=\"color: #999999\" $attr><font color=\"#999999\">$text</font></span>";
  38. }
  39. // Replace & with &amp; in uri
  40. $uri = str_replace('&', '&amp;', $uri);
  41. return "<a href=\"$uri\" $attr>$text</a>";
  42. }
  43. /**
  44. * Generate XML code for image.
  45. *
  46. * Automatically locates file- looks for it in any ../ (max 20 levels)
  47. * Can extract width and height automatically.
  48. * Border defaults to 0. Can be overridden with $attr
  49. *
  50. * @param string filename Relative filename of picture or uri.
  51. * @param string width Forced width of picture.
  52. * @param string height Forced height of picture.
  53. * @param string attr Additional HTML attributes, e.g. "target=main width='100%'".
  54. * @return string Generated XML.
  55. */
  56. public static function img($filename, $attr = false, $width = false, $height = false)
  57. {
  58. // If filename is a local file, locate it somewhere in (../)*
  59. if (!strstr($filename, "http://") && !strstr($filename, "?")) {
  60. $name = preg_replace("/^\//", "", $filename);
  61. $i= 21;
  62. while (--$i && !file_exists($name)) {
  63. $name = '../'.$name;
  64. }
  65. if (!file_exists($name)) {
  66. return false;
  67. }
  68. $fn_size = $name;
  69. // Replace relative filename with correct path
  70. if (@$filename[0] != "/") {
  71. $filename = $name;
  72. }
  73. }
  74. // Get height and width
  75. if (!empty($fn_size) && (!$height || !$width)) {
  76. $sz = GetImageSize($fn_size);
  77. if (!$width) {
  78. $width= $sz[0];
  79. }
  80. if (!$height) {
  81. $height= $sz[1];
  82. }
  83. }
  84. // Add border code?
  85. $border= (stristr(" $attr", " border=")) ? '' : "border='0'";
  86. // Add alt code?
  87. $alt= (stristr(" $attr", " alt=")) ? '' : 'alt=""';
  88. // Replace & with &amp; in filename
  89. $filename = str_replace('&', '&amp;', $filename);
  90. // Output
  91. $result = "<img src=\"$filename\"";
  92. if ($width) {
  93. $result .= " width=\"$width\"";
  94. }
  95. if ($height) {
  96. $result .= " height=\"$height\"";
  97. }
  98. $result .= " $attr $border $alt />";
  99. return $result;
  100. }
  101. /**
  102. * Generate XML for pictorial link with image swapping.
  103. *
  104. * If uri is null, plain picture is displayed
  105. * Width and height of images are auto detected.
  106. * If using image swapping, images are preloaded with javascript.
  107. *
  108. * @param string uri URI to open
  109. * @param string filename Filename for image to display.
  110. * @param string attr Additional HTML attributes, e.g. "target=main width='100%'"
  111. * @param string m_over Filename for image to display when mouse is over image.
  112. * Can contain onmouse* -- will merge with our code (our code
  113. * will be executed first!). Except for onmouse* $attr is only
  114. * added to <img tag. Cannot contain onmouse* code. Refer to $onmouse_merge
  115. * @param array otherswap Swap other image: array ($name, $normal, $m_over).
  116. * @param array onmouse_merge Addition onmouseover/out code to merge with our:
  117. * array ($m_name_merge, $m_out_merge).
  118. */
  119. public static function a_img($uri, $filename, $attr = false, $m_over = false, $otherswap = false, $onmouse_merge = false)
  120. {
  121. // $uri is false, just output picture
  122. if (!$uri) {
  123. return xml_gen::img($filename);
  124. }
  125. // Number of times xml_gen::a_img() has been called with $m_over.
  126. static $called;
  127. // Init
  128. $swap_out = false;
  129. $swap_over = false;
  130. // Generate onmouse* code
  131. if ($m_over || $otherswap) {
  132. // Increment called var
  133. $called++;
  134. // Has mouse over?
  135. if ($m_over) {
  136. $swap_out = "swp('spluf$called','spl_f$called'); ";
  137. $swap_over = "swp('spluf$called','splof$called'); ";
  138. }
  139. // Otherswap?
  140. if ($otherswap) {
  141. list($os_name, $os_normal, $os_m_over)= $otherswap;
  142. if (!$os_name || !$os_normal || !$os_m_over) {
  143. die("$otherswap requires array with three string.");
  144. }
  145. $swap_out .= "swp('$os_name','spl_q$called'); ";
  146. $swap_over .= "swp('$os_name','sploq$called'); ";
  147. }
  148. }
  149. // Onmouse* merge`?
  150. if ($onmouse_merge) {
  151. list($merge_over, $merge_out)= $onmouse_merge;
  152. if (!$merge_over || !$merge_out) {
  153. die("$onmouse_merge requires array with two strings.");
  154. }
  155. $swap_out .= $merge_out;
  156. $swap_over .= $merge_over;
  157. }
  158. // Set name only if swapping
  159. $name = ($m_over || $otherswap) ? "name='spluf$called'" : "";
  160. // Output link and picture
  161. $result = xml_gen::a($uri, xml_gen::img($filename, "$name $attr"), "onclick='this.blur()' onmouseout=\"$swap_out\" onmouseover=\"$swap_over\"");
  162. // If no m_over, return result
  163. if (!$m_over && !$otherswap) {
  164. return $result;
  165. }
  166. // Else preload images
  167. $result .= "<script type='text/javascript'>\n<!--\n\n";
  168. // On first a_img() call, we insert the swp() javascript function.
  169. if ($called == 1) {
  170. $result .= "function swp(id,name) { if (document.images) document.images[id].src = eval(name+'.src'); }\n\n";
  171. }
  172. // Insert preload code.
  173. if ($m_over) {
  174. $result .= "if (document.images) {
  175. spl_f$called = new Image; spl_f$called.src = '$filename';
  176. splof$called = new Image; splof$called.src = '$m_over';
  177. }";
  178. }
  179. // Insert preload code - otherswap
  180. if ($otherswap) {
  181. $result .= "if (document.images) {
  182. spl_q$called = new Image; spl_q$called.src = '$os_normal';
  183. sploq$called = new Image; sploq$called.src = '$os_m_over';
  184. }";
  185. }
  186. return $result . "\n\n// -->\n</script>";
  187. }
  188. /**
  189. * Generate XML for pictorial link with image swapping -or- Simple picture -depending- on $condition.
  190. *
  191. * @param bool condition Show Picture or xml_gen::a_img?
  192. * @param string selected Filename for image to display if $condition == true. - use m_over if set to null
  193. * @param string uri URI to open
  194. * @param string filename Filename for image to display if $condition == false.
  195. * @param string m_over Filename for image to display when mouse is over image.
  196. * @param string attr Additional HTML attributes, e.g. "target=main width='100%'".
  197. * Except for onmouse* $attr is only added to <img tag.
  198. * @param string[] otherswap Swap other image: array ($name, $normal, $m_over).
  199. * @see xml_gen::a_img
  200. */
  201. public static function a_img_cond($condition, $selected=null, $uri, $filename, $m_over = false, $attr = false, $otherswap = false)
  202. {
  203. if ($condition) {
  204. if (is_null($selected)) {
  205. return xml_gen::a_img($uri, $m_over, $attr, $m_over, $otherswap);
  206. }
  207. else {
  208. return xml_gen::a_img($uri, $selected, $attr, $m_over, $otherswap);
  209. }
  210. }
  211. else {
  212. return xml_gen::a_img($uri, $filename, $attr, $m_over, $otherswap);
  213. }
  214. }
  215. /**
  216. * Generate XML code for flash object.
  217. */
  218. function flash($filename, $width = false, $height = false, $attr = null, $bgcolor = '#ffffff', $requied_flash_version = 6, $use_swfobject = true, $swfobject_name = "mymovie")
  219. {
  220. // If filename is a local file, locate it somewhere in (../)*
  221. if (!strstr($filename, "http://") && !strstr($filename, "?")) {
  222. $name = preg_replace("/^\//", "", $filename);
  223. $i = 21;
  224. while (--$i && !file_exists($name)) {
  225. $name = '../'.$name;
  226. }
  227. if (!file_exists($name)) {
  228. return false;
  229. }
  230. $fn_size = $name;
  231. // Replace relative filename with correct path
  232. if (@$filename[0] != '/') {
  233. $filename = $name;
  234. }
  235. }
  236. // Get height and width
  237. if (!empty($fn_size) && (!$height || !$width)) {
  238. $sz = GetImageSize($fn_size);
  239. $width = ($width ? $width : $sz[0]);
  240. $height = ($height ? $height : $sz[1]);
  241. }
  242. if ($use_swfobject) {
  243. $div_name = 'flashcontent_'.strtr($filename, '/.=?%;', '______');
  244. $flashObjectString = '<div width="'.$width.'" height="'.$height.'" id="'.$div_name.'"><table cellpadding="5" cellspacing="0" border="0" width="'.$width.'" height="'.$height.'"></tr><td bgcolor="'.$bgcolor.'"><b>Requires flash version '.$requied_flash_version.'</b></td></tr></table></div>';
  245. $flashObjectString .= '<script type="text/javascript">';
  246. $flashObjectString .= '<!--';
  247. $flashObjectString .= 'var so = new SWFObject("'.$filename.'", "'.$swfobject_name.'", "'.$width.'", "'.$height.'", "'.$requied_flash_version.'", "'.$bgcolor.'");';
  248. $flashObjectString .= 'so.addParam("quality", "high");';
  249. $flashObjectString .= 'so.write("'.$div_name.'");';
  250. $flashObjectString .= '// -->';
  251. $flashObjectString .= '</script>';
  252. } else {
  253. $flashObjectString = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=$requied_flash_version,0,0,0" width="'.$width.'" height="'.$height.'" '.$attr.'>';
  254. $flashObjectString .= '<param name="movie" value="'.$filename.'">';
  255. $flashObjectString .= '<param name="quality" value="high">';
  256. $flashObjectString .= '<param name="bgcolor" value="'.$bgcolor.'">';
  257. $flashObjectString .= '<embed src="'.$filename.'" quality="high" bgcolor="'.$bgcolor.'" width="'.$width.'" height="'.$height.'" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer"></embed>';
  258. $flashObjectString .= '</object>';
  259. }
  260. return $flashObjectString;
  261. }
  262. /**
  263. * Generate XML for <span>.
  264. */
  265. public static function span($content, $attr = null)
  266. {
  267. return "<span $attr>$content</span>";
  268. }
  269. /**
  270. * Generate XML for <div>.
  271. */
  272. public static function div($content, $attr = null)
  273. {
  274. return "<div $attr>$content</div>";
  275. }
  276. /**
  277. * Generate XML for bold text.
  278. */
  279. public static function b($text)
  280. {
  281. return "<b>$text</b>";
  282. }
  283. /**
  284. * Generate XML for italic text.
  285. */
  286. public static function i($text)
  287. {
  288. return "<i>$text</i>";
  289. }
  290. /**
  291. * Generate XML for pre formatted text.
  292. */
  293. public static function pre($text, $attr = null)
  294. {
  295. return "<pre $attr>$text</pre>\n";
  296. }
  297. /**
  298. * Generate XML for paragraph.
  299. */
  300. public static function p($text, $attr = null)
  301. {
  302. if (is_array($text)) {
  303. $text = implode("<br>", $text);
  304. }
  305. return "<p $attr>$text</p>\n";
  306. }
  307. /**
  308. * Generate XML for error paragraph.
  309. */
  310. public static function p_err($text)
  311. {
  312. if (is_array($text)) {
  313. $text = implode("<br>", $text);
  314. }
  315. return xml_gen::p($text, "class='error'");
  316. }
  317. /**
  318. * Generate XML for text as heading 1.
  319. */
  320. public static function h1($text, $attr='')
  321. {
  322. return "<h1 $attr>$text</h1>";
  323. }
  324. /**
  325. * Generate XML for text as heading 2.
  326. */
  327. public static function h2($text, $attr='')
  328. {
  329. return "<h2 $attr>$text</h2>";
  330. }
  331. /**
  332. * Generate XML for text as heading 3.
  333. */
  334. public static function h3($text, $attr='')
  335. {
  336. return "<h3 $attr>$text</h3>";
  337. }
  338. /**
  339. * Generate XML for text as heading 4.
  340. */
  341. public static function h4($text, $attr='')
  342. {
  343. return "<h4 $attr>$text</h4>";
  344. }
  345. /**
  346. * Generate XML for spaces.
  347. */
  348. public static function space($n=1)
  349. {
  350. return str_repeat("&nbsp;", $n);
  351. }
  352. /**
  353. * Generate XML for linefeeds.
  354. */
  355. public static function br($n = 1, $abs = null)
  356. {
  357. if ($abs) {
  358. $abs= " clear=all";
  359. }
  360. return str_repeat("<br$abs />\n", $n);
  361. }
  362. /**
  363. * Generate XML for hr tag.
  364. */
  365. public static function hr($attr = null)
  366. {
  367. return "<hr $attr />";
  368. }
  369. /**
  370. * Generate XML for unordered list.
  371. */
  372. public static function ul($elements, $attr = null)
  373. {
  374. return "<ul $attr>$elements</ul>\n";
  375. }
  376. /**
  377. * Generate XML for list index.
  378. */
  379. public static function li($text, $attr = null)
  380. {
  381. return "<li $attr />$text\n";
  382. }
  383. /**
  384. * Generate XML for iframe
  385. *
  386. * Defaults to no scrolling and no frameborder.
  387. * Automatic height and width possible for local uris only.
  388. *
  389. * @param string src Iframe source (src)
  390. * @param mixed width Iframe width - set to 'auto' to automatically adjust width.
  391. * @param mixed height Iframe height - set to 'auto' to automatically adjust height
  392. * @param string attr Additional HTML attributes, e.g. "target=main width='100%'".
  393. */
  394. public static function iframe($src, $width=null, $height=null, $attr=null)
  395. {
  396. if (!strstr($attr, 'frameborder')) {
  397. $attr .= " frameborder='0'";
  398. }
  399. if (!strstr($attr, 'scrolling')) {
  400. $attr .= " scrolling='no'";
  401. }
  402. if ($width == 'auto' || $height == 'auto') {
  403. $on_load = '';
  404. if ($width == 'auto') {
  405. $on_load .= 'this.width=this.contentWindow ? this.contentWindow.document.body.scrollWidth : this.document.body.scrollWidth;';
  406. }
  407. if ($height == 'auto') {
  408. $on_load .= 'this.height=this.contentWindow ? this.contentWindow.document.body.scrollHeight : this.document.body.scrollHeight;';
  409. }
  410. $attr .= "onLoad='$on_load'";
  411. }
  412. $result = "<iframe src='$src'";
  413. if ($width) {
  414. $result .= " width='$width'";
  415. }
  416. if ($height) {
  417. $result .= " height='$height'";
  418. }
  419. return "$result $attr>An iframe capable browser is required to view this web site</iframe>";
  420. }
  421. /**
  422. * Generate XML for invisible table with desired width and height.
  423. */
  424. public static function spacer($width, $height)
  425. {
  426. return "<table cellpadding='0' cellspacing='0' border='0' width='$width' style='height:${height}px'><tr><td style='Font: 1px Arial'>&nbsp;</td></tr></table>";
  427. }
  428. /**
  429. * Generate js onclick for confirmations for <a
  430. */
  431. public static function js_confirm($str)
  432. {
  433. $str = xml_gen::js_string($str);
  434. return "onclick='return confirm(\"$str\");'";
  435. }
  436. /**
  437. * Generate js onclick for confirmations for <input type=button
  438. */
  439. public static function button_js_confirm_href($str, $url)
  440. {
  441. $str = xml_gen::js_string($str);
  442. return "onclick='if (confirm(\"$str\")) location.href=\"$url\";'";
  443. }
  444. /**
  445. * Prepare string for javascript
  446. */
  447. public static function js_string($str)
  448. {
  449. $str = str_replace('"', '\"', $str);
  450. $str = str_replace("'", '"+String.fromCharCode(39)+"', $str);
  451. return $str;
  452. }
  453. }
  454. //////////////////////////////////////////////////////////////////////////////
  455. // Tables ////////////////////////////////////////////////////////////////////
  456. //////////////////////////////////////////////////////////////////////////////
  457. /**
  458. * HTML Table Generator.
  459. *
  460. * @version 2
  461. */
  462. class table
  463. {
  464. protected $curr_col; // Current column we are in
  465. protected $curr_row; // Current row we are in
  466. protected $rowspan; // Array to handle rowspan
  467. protected $closed; // Is current cell closed?
  468. protected $columns; // Number of column in table
  469. protected $aligns; // Alignments from constructor
  470. protected $widths; // widths from constructor
  471. protected $classes; // classes from constructor
  472. protected $header; // Does table has header row
  473. protected $set_widths; // Set only widths on first row with no colspan
  474. protected $next_row_attr = ''; // Set id= on next <tr>
  475. /**
  476. * Constructor - define table layout here.
  477. *
  478. * @param int colums Number of colums in table
  479. * @param string attr Additional HTML attributes. cellpadding, cellspacing and border all defaults to 0.
  480. * @param string classes classes (set on <tr>) to alternate. "header;alternate" or ";alternate".
  481. * @param string aligns Alignments of columns. List seperated by ;. I.e. "left;right;center;left".
  482. * @param string widths widths of columns. List seperated by ;. I.e. "100;20%;20".
  483. * Alternate is ; seperated too, I.e. "header;odd;even".
  484. */
  485. public function __construct($columns, $attr=false, $classes=false, $aligns=false, $widths=false)
  486. {
  487. echo "\n\n".'<table';
  488. // Default cellpadding: 0
  489. if (!stristr(' '.$attr, ' cellpadding=')) {
  490. echo ' cellpadding="0"';
  491. }
  492. // Default cellspacing: 0
  493. if (!stristr(' '.$attr, ' cellspacing=')) {
  494. echo ' cellspacing="0"';
  495. }
  496. // Default border: 0
  497. if (!stristr(' '.$attr, ' border=')) {
  498. echo ' border="0"';
  499. }
  500. echo ' '.$attr.'>';
  501. $this->closed = true; // Table is closed
  502. $this->curr_col = -1; // We are at column -1 (before <tr>)
  503. $this->curr_row = 0; // We are in row 0
  504. $this->columns = $columns;
  505. $this->header = $classes && ($classes[0] != ';');
  506. $this->aligns = explode(';', $aligns);
  507. $this->widths = explode(';', $widths);
  508. $this->classes = explode(';', $classes);
  509. $this->set_widths = 1;
  510. $this->rowspan = array();
  511. }
  512. /**
  513. * Destructor - finalise table.
  514. */
  515. public function done()
  516. {
  517. $this->end_row();
  518. echo "</table>\n\n";
  519. }
  520. /**
  521. * Output data cell(s).
  522. *
  523. * @param mixed data String: Data to output. Can be blank... just output after function call.
  524. * Array: Each element will be output in a new cell.
  525. * @param string attr Additional HTML attributes. Set col/rowspan, override/set class, width, align...
  526. */
  527. public function data($data = '', $attr = false)
  528. {
  529. if (is_array($data)) {
  530. foreach ($data as $element) {
  531. $this->data($element);
  532. }
  533. return;
  534. }
  535. // Before <tr>?
  536. if ($this->curr_col == -1) {
  537. $this->new_row();
  538. }
  539. // After last column?
  540. elseif ($this->curr_col + $this->rowspan[0] >= $this->columns) {
  541. $this->end_row();
  542. $this->new_row();
  543. }
  544. // After <td>?
  545. if ($this->curr_col > 0) {
  546. echo '</td>'."\n";
  547. $this->closed = true;
  548. }
  549. // Begin new cell
  550. echo '<td';
  551. $this->closed= false;
  552. // Override width
  553. if (!stristr(" $attr", ' width=') && !stristr(" $attr", ' colspan=')) {
  554. if ($this->curr_row == $this->set_widths && sizeof($this->widths > $this->curr_col) && !empty($this->widths[$this->curr_col])) {
  555. echo " width='".$this->widths[$this->curr_col]."'";
  556. }
  557. }
  558. // Override alignment
  559. if (!stristr(" $attr", ' align=')) {
  560. if (sizeof($this->aligns > $this->curr_col) && !empty($this->aligns[$this->curr_col])) {
  561. echo ' align="'.$this->aligns[$this->curr_col].'"';
  562. }
  563. }
  564. // Output data
  565. echo ' '.$attr.'>'.$data;
  566. // Advance internal pointer
  567. $this->curr_col++;
  568. // Colspan?
  569. $colspan = 1;
  570. if (eregi(' colspan=(["\'0-9]+) ', ' '.$attr.' ', $regs)) {
  571. $colspan = str_replace("'", '', str_replace('"', '', $regs[1]));
  572. if ($colspan > 1) {
  573. $this->curr_col += $colspan - 1;
  574. }
  575. if ($this->curr_row == $this->set_widths) {
  576. $this->set_widths++;
  577. }
  578. }
  579. // rowspan?
  580. if (eregi(' rowspan=(["\'0-9]+) ', ' '.$attr.' ', $regs)) {
  581. $rowspan = str_replace("'", '', str_replace('"', '', $regs[1]));
  582. while ($rowspan > 1) {
  583. array_push($this->rowspan, 0); // add a elements to our array... we may not need it... who cares?
  584. @$this->rowspan[$rowspan - 1] += $colspan;
  585. $rowspan--;
  586. }
  587. }
  588. }
  589. /**
  590. * Set attributes on next <tr>.
  591. */
  592. public function row_attr($attr)
  593. {
  594. $this->next_row_attr = ' '.$attr;
  595. }
  596. /**
  597. * Finalise current row. Fill with empty cells if needed.
  598. */
  599. public function end_row()
  600. {
  601. if (($this->curr_col == -1) && $this->closed) {
  602. return;
  603. }
  604. // Before last column?
  605. if ($this->curr_col + @$this->rowspan[0] < $this->columns) {
  606. $colspan = $this->columns - $this->curr_col - @$this->rowspan[0] + 1;
  607. $this->data('', 'colspan="'.$colspan.'"');
  608. }
  609. if (!$this->closed) {
  610. echo '</td>'."\n";
  611. }
  612. echo '</tr>'."\n";
  613. $this->curr_col = -1;
  614. ksort($this->rowspan);
  615. array_shift($this->rowspan);
  616. }
  617. /**
  618. * Advance to new row.
  619. */
  620. protected function new_row()
  621. {
  622. echo "\n".'<tr';
  623. // Override class
  624. if (!stristr(' '.$this->next_row_attr, ' class=')) {
  625. echo $this->get_class();
  626. }
  627. echo $this->next_row_attr;
  628. $this->next_row_attr = '';
  629. echo '>'."\n";
  630. $this->curr_row++;
  631. $this->curr_col = 0;
  632. array_push($this->rowspan, 0);
  633. }
  634. /**
  635. * Get class for current row.
  636. */
  637. protected function get_class()
  638. {
  639. $sz = sizeof($this->classes);
  640. if (!$sz) {
  641. return;
  642. }
  643. $class = $this->classes[0];
  644. if (($this->curr_row == 0) && $this->header && $class) {
  645. return ' class="'.$class.'"';
  646. }
  647. $offset = 1;
  648. if ($this->header) {
  649. $offset--;
  650. }
  651. $offs = (($sz > 1) ? 1 + (($offset + $this->curr_row - 1) % ($sz - 1)) : 1);
  652. $class = isset($this->classes[$offs]) ? $this->classes[$offs] : null;
  653. if ($class) {
  654. return ' class="'.$class.'"';
  655. }
  656. }
  657. }
  658. //////////////////////////////////////////////////////////////////////////////
  659. // Forms /////////////////////////////////////////////////////////////////////
  660. //////////////////////////////////////////////////////////////////////////////
  661. /**
  662. * HTML Form Generator.
  663. *
  664. * @version 3
  665. */
  666. class form
  667. {
  668. protected $elements; // Array of elements: array ( array("fisk", "radio"), ...
  669. protected $last_date_type; // YMD order of last date field
  670. protected $focus_element = -1; // Element on which to focus with javascript.
  671. protected $check_code; // Javascript code for CheckFormX()
  672. protected $extra_code_pre; // Extra javascript when drawing form
  673. protected $extra_code_post; // Extra javascript before submit
  674. protected $values; // Object or array containing default values.
  675. public $name; // Name of form.
  676. public $class_fields = "field"; // Standard class for textfields, textareas
  677. public $class_fields_readonly = "field_readonly"; // Standard class for readonly fields
  678. public $class_fields_disabled = "field_disabled"; // Standard class for disabled fields
  679. public $class_selects = "select"; // Standard class for selectboxes
  680. public $class_selects_readonly = "select_readonly"; // Standard class for readonly selectboxes
  681. public $class_selects_disabled = "select_disabled"; // Standard class for disabled selectboxes
  682. public $class_buttons = "button"; // Standard class for buttons
  683. public $class_checkboxes = "checkbox"; // Standard class for checkboxes
  684. public $class_radiobuttons = "radiobutton"; // Standard class for radiobuttons
  685. public $class_labels = "label"; // Standard class for labels (checkboxes and radiobuttons)
  686. public $class_labels_readonly = "label_readonly"; // Standard class for "readonly" labels
  687. public $class_datefields = "datefield"; // Standard class for datefield combi - do not set width
  688. public $class_dual_select_marked = "marked"; // Standard class for dual select - marked option
  689. public $option_dhtml_options = false; // Add options to <select> with DHTML. Faster when number of
  690. // options exceeds some 2000-4000.
  691. /**
  692. * Constructor - define form here.
  693. *
  694. * @param string action URL to POST or GET - defaults to $_SERVER["REQUEST_URI"]
  695. * @param string name HTML name of form.
  696. * @param string attr Additional HTML attributes, e.g. "target=main"
  697. */
  698. public function __construct($action = null, $name = null, $attr = null)
  699. {
  700. // Default
  701. if (is_null($action)) {
  702. $action = $_SERVER["REQUEST_URI"];
  703. }
  704. // Init
  705. $this->elements = array ();
  706. // Generate name if none is specified.
  707. if (!$name) {
  708. $name = "Form" . uniqid(42);
  709. }
  710. $this->name = $name;
  711. // Determine method - look for method='get' in $attr, set to post if not present
  712. if (!stristr(" $attr", " method='get'") && !stristr(" $attr", ' method="get"') && !stristr(" $attr", ' method=get')) {
  713. $attr = "method='post' enctype='multipart/form-data' $attr";
  714. $this->values = &$_POST;
  715. }
  716. else {
  717. $this->values = &$_GET;
  718. }
  719. // Output form header
  720. echo "\n\n<form action=\"$action\" name='$name' $attr onsubmit=\"return Check$name();\">\n";
  721. // Output hidden field to fix msie error
  722. $this->hidden("field_to_fix_msie_bug_on_post_special_chars", 42);
  723. }
  724. /**
  725. * Destructor - finalise form.
  726. */
  727. public function done()
  728. {
  729. // Output form footer
  730. echo "\n</form>\n\n";
  731. // Output javascript
  732. echo "<script type='text/javascript'>\n<!--\n\n";
  733. // Focus
  734. if ($this->focus_element != -1) {
  735. // Get element name from focus_element number
  736. foreach ($this->elements as $element_num => $array) {
  737. list($element, $type) = $array;
  738. if (!$this->focus_element) {
  739. break;
  740. }
  741. $this->focus_element--;
  742. }
  743. // Set focus on selected or first element in form
  744. echo "if (!document.$this->name.elements[$element_num].disabled)\n";
  745. echo " document.$this->name.elements[$element_num].focus();\n\n";
  746. }
  747. // Output Additional code
  748. echo $this->extra_code_pre;
  749. // Output CheckForm code
  750. echo "function Check" . $this->name . "()\n{\n";
  751. echo $this->check_code;
  752. echo "\n";
  753. echo $this->extra_code_post;
  754. echo "\n";
  755. echo " return true;\n";
  756. echo "}\n\n\n// -->\n</script>\n\n";
  757. }
  758. /**
  759. * Set object or array to get default values from.
  760. *
  761. * Defaults to $_REQUEST.
  762. *
  763. * @param mixed from Array or object.
  764. */
  765. public function values(&$from)
  766. {
  767. $this->values = &$from;
  768. }
  769. /**
  770. * Output a hidden field.
  771. *
  772. * Value comes from array or object defined with values.
  773. * Default from $_REQUEST[$name].
  774. *
  775. * @param string name Name of hidden field.
  776. * @param string value Static value, ignore $_REQUEST[$name] and $GLOBALS[$name]
  777. */
  778. public function hidden($name, $value = null, $attr = null)
  779. {
  780. // Get value
  781. if (is_null($value)) {
  782. $value = $this->get($name);
  783. }
  784. // Value is array - make multiple hidden fields
  785. if (strstr($name, "[]")) {
  786. // no empty arrays
  787. if (is_array($value)) {
  788. foreach ($value as $key => $val) {
  789. $this->hidden(str_replace("[]", "[$key]", $name), $val);
  790. }
  791. }
  792. return;
  793. }
  794. // Convert " to HTML
  795. $value = str_replace('"', '&quot;', $value);
  796. // Output hidden field
  797. echo "<input type='hidden' name='$name' value=\"$value\" $attr />";
  798. // Store element in elements array
  799. array_push($this->elements, array ($name, "hidden"));
  800. }
  801. /**
  802. * Output a radio button.
  803. *
  804. * Checked button comes from array or object defined with values.
  805. * Default from $_REQUEST[$name].
  806. *
  807. * @param string name Name of radio group.
  808. * @param string value Value for this radio button.
  809. * @param string label Text label.
  810. * @param string attr Additional HTML attributes, e.g. "id=main"
  811. */
  812. public function radio($name, $value, $label = null, $attr = false)
  813. {
  814. // Get value from name
  815. $val = $this->get($name);
  816. $check = $val == $value;
  817. // Convert $check to HTML
  818. $check = ($check) ? "checked" : "";
  819. if ($label) {
  820. // Render label grey if attr contains "disabled".
  821. if (stristr(" $attr ", " disabled ")) {
  822. $label = "<span style=\"color: #999999\"><font color=\"#999999\">$label</font></span>";
  823. }
  824. elseif ($this->class_labels) {
  825. $label = "<span class='$this->class_labels'>$label</span>";
  826. }
  827. }
  828. // Get box class
  829. $class = empty($this->class_radiobuttons) ? "" : "class='$this->class_radiobuttons'";
  830. // Output radio button
  831. echo "\n<input type='radio' name='$name' value=\"$value\" $check $class $attr />$label";
  832. // Store element in elements array
  833. array_push($this->elements, array ($name, "radio"));
  834. }
  835. /**
  836. * Output a checkbox
  837. *
  838. * Checked comes from array or object defined with values.
  839. * Default from $_REQUEST[$name].
  840. *
  841. * @param string name Name of check box.
  842. * @param string label Text label.
  843. * @param string attr Additional HTML attributes, e.g. "id=main"
  844. */
  845. public function checkbox($name, $label = null, $attr = false)
  846. {
  847. $value = $this->get($name);
  848. $value = !empty($value);
  849. // Convert $check and value to HTML
  850. $check = $value ? "checked" : "";
  851. // Render label grey if attr contains "disabled".
  852. if ($label) {
  853. if (stristr(" $attr ", " disabled ")) {
  854. $label = "<span style=\"color: #999999\"><font color=\"#999999\">$label</font></span>";
  855. }
  856. elseif ($this->class_labels) {
  857. $label = "<span class='$this->class_labels'>$label</span>";
  858. }
  859. }
  860. // Get box class
  861. $class = empty($this->class_checkboxes) ? "" : "class='$this->class_checkboxes'";
  862. // Output checkbox
  863. echo "\n<input type='checkbox' name='$name' $check $attr $class />$label";
  864. // Store element in elements array
  865. array_push($this->elements, array ($name, "checkbox"));
  866. }
  867. /**
  868. * Output a select box
  869. *
  870. * Selected element comes from array or object defined with values.
  871. * Default from $_REQUEST[$name].
  872. *
  873. * @param string name Name of select box.
  874. * @param array items Associative array with items: $value => $label.
  875. * @param string attr Additional HTML attributes, e.g. "id=main"
  876. */
  877. public function select($name, $items, $attr = false)
  878. {
  879. $select = $this->get($name);
  880. // convert select to array
  881. if (!is_array($select)) {
  882. $select = array (0 => $select);
  883. }
  884. // Use class_select_disabled if no class or style is specified in attr and field readonly.
  885. if ($this->class_selects_disabled && stristr(" $attr", " disabled") && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  886. $attr .= " class='$this->class_selects_disabled'";
  887. }
  888. // Use class_select_readonly if no class or style is specified in attr and field readonly.
  889. if ($this->class_selects_readonly && stristr(" $attr", " readonly") && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  890. $attr .= " class='$this->class_selects_readonly'";
  891. }
  892. // Use class_selects if no class or style is specified in attr.
  893. if ($this->class_selects && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  894. $attr .= " class='$this->class_selects'";
  895. }
  896. // Output select - the normal HTML way
  897. if (!$this->option_dhtml_options) {
  898. echo "<select name='$name' $attr>";
  899. // Output box elements
  900. foreach ($items as $value => $label) {
  901. $selected = in_array($value, $select) ? "selected='selected'" : "";
  902. echo "<option value=\"$value\" $selected>$label</option>";
  903. }
  904. echo "</select>";
  905. }
  906. // Output box elements - the DHTML way
  907. else {
  908. echo "<select name='$name' $attr></select>\n";
  909. echo "<script type='text/javascript'>\n";
  910. // Generate box elements
  911. $i = 0;
  912. foreach ($items as $value => $label) {
  913. $value = str_replace('"', '\"', $value);
  914. $value = str_replace("'", '"+String.fromCharCode(39)+"', $value);
  915. $label = str_replace('"', '\"', $label);
  916. $label = str_replace("'", '"+String.fromCharCode(39)+"', $label);
  917. echo "document.$this->name.${name}[$i]= new Option(\"$label\",\"$value\");\n";
  918. if (in_array($value, $select)) {
  919. echo "document.$this->name.$name.selectedIndex = $i;\n";
  920. }
  921. $i++;
  922. }
  923. echo "\n</script>";
  924. }
  925. // Store element in elements array
  926. array_push($this->elements, array ($name, "select"));
  927. }
  928. /**
  929. * Output a submit button.
  930. *
  931. * @param string label Label on button.
  932. * @param string attr Additional HTML attributes, e.g. "id=main"
  933. * @param string $change_action Change action to this value before submit.
  934. */
  935. public function submit($label, $attr = false, $change_action = false)
  936. {
  937. // Use class_buttons if no class or style is specified in attr.
  938. if ($this->class_buttons && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  939. $attr .= " class='$this->class_buttons'";
  940. }
  941. // Change form action
  942. if ($change_action) {
  943. $change_action = "onclick=\"$this->name.action='$change_action';\"";
  944. }
  945. // Output button
  946. echo "<input type='submit' value=\"$label\" $attr $change_action />";
  947. }
  948. /**
  949. * Output a reset button.
  950. *
  951. * @param string label Label on button.
  952. * @param string attr Additional HTML attributes, e.g. "id=main"
  953. */
  954. public function reset($label, $attr = false)
  955. {
  956. // Use class_buttons if no class or style is specified in attr.
  957. if ($this->class_buttons && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  958. $attr .= " class='$this->class_buttons'";
  959. }
  960. // Output button
  961. echo "<input type='reset' value=\"$label\" $attr />";
  962. }
  963. /**
  964. * Output a button.
  965. *
  966. * @param string label Label on button.
  967. * @param string attr Additional HTML attributes, e.g. "id=main"
  968. */
  969. public function button($label, $attr = false)
  970. {
  971. // Use class_buttons if no class or style is specified in attr.
  972. if ($this->class_buttons && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  973. $attr .= " class='$this->class_buttons'";
  974. }
  975. // Output button
  976. echo "<input type='button' value=\"$label\" $attr />";
  977. }
  978. /**
  979. * Output an image submit button.
  980. *
  981. * @param string label Label on button.
  982. * @param string attr Additional HTML attributes, e.g. "id=main"
  983. * @param string $change_action Change action to this value before submit.
  984. */
  985. public function image($image, $text, $attr = false, $change_action = false)
  986. {
  987. // Change form action
  988. if ($change_action) {
  989. $change_action = "onclick=\"$this->name.action='$change_action';\"";
  990. }
  991. // Output button
  992. echo "<input type='image' value='$text' src='$image' $attr $change_action />";
  993. }
  994. /**
  995. * Output a text field.
  996. *
  997. * Value comes from array or object defined with values.
  998. * Default from $_REQUEST[$name].
  999. *
  1000. * @param string name Name of text field.
  1001. * @param string attr Additional HTML attributes, e.g. "id=main"
  1002. */
  1003. public function text($name, $attr = false)
  1004. {
  1005. $value = $this->get($name);
  1006. // Convert " to HTML
  1007. $value = str_replace('"', '&quot;', $value);
  1008. // Use class_fields_disabled if no class or style is specified in attr and field readonly.
  1009. if ($this->class_fields_disabled && stristr(" $attr", " disabled") && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  1010. $attr .= " class='$this->class_fields_disabled'";
  1011. }
  1012. // Use class_fields_readonly if no class or style is specified in attr and field readonly.
  1013. if ($this->class_fields_readonly && stristr(" $attr", " readonly") && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  1014. $attr .= " class='$this->class_fields_readonly'";
  1015. }
  1016. // Use class_fields if no class or style is specified in attr.
  1017. if ($this->class_fields && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  1018. $attr .= " class='$this->class_fields'";
  1019. }
  1020. // Output text field
  1021. echo "<input type='text' name='$name' value=\"$value\" $attr />";
  1022. // Store element in elements array
  1023. array_push($this->elements, array ($name, "text"));
  1024. }
  1025. /**
  1026. * Output a password field.
  1027. *
  1028. * Value comes from array or object defined with values.
  1029. * Default from $_REQUEST[$name].
  1030. *
  1031. * @param string name Name of password field.
  1032. * @param string attr Additional HTML attributes, e.g. "id=main"
  1033. */
  1034. public function password($name, $attr = false)
  1035. {
  1036. // Get value
  1037. $value = $this->get($name);
  1038. // Convert " to HTML
  1039. $value = str_replace('"', '&quot;', $value);
  1040. // Use class_fields_disabled if no class or style is specified in attr and field readonly.
  1041. if ($this->class_fields_disabled && stristr(" $attr", " disabled") && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  1042. $attr .= " class='$this->class_fields_disabled'";
  1043. }
  1044. // Use class_fields_readonly if no class or style is specified in attr and field readonly.
  1045. if ($this->class_fields_readonly && stristr(" $attr", " readonly") && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  1046. $attr .= " class='$this->class_fields_readonly'";
  1047. }
  1048. // Use class_fields if no class or style is specified in attr.
  1049. if ($this->class_fields && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  1050. $attr .= " class='".$this->class_fields."'";
  1051. }
  1052. // Output text field
  1053. echo "<input type='password' name='$name' value=\"$value\" $attr />";
  1054. // Store element in elements array
  1055. array_push($this->elements, array ($name, "password"));
  1056. }
  1057. /**
  1058. * Output a text area.
  1059. *
  1060. * Value comes from array or object defined with values.
  1061. * Default from $_REQUEST[$name].
  1062. *
  1063. * @param string name Name of text area.
  1064. * @param string attr Additional HTML attributes, e.g. "id=main"
  1065. */
  1066. public function textarea($name, $attr = false)
  1067. {
  1068. // Get value
  1069. $value = $this->get($name);
  1070. // Convert " to HTML
  1071. $value = str_replace('"', '&quot;', $value);
  1072. // Use class_fields_disabled if no class or style is specified in attr and field readonly.
  1073. if ($this->class_fields_disabled && stristr(" $attr", " disabled") && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  1074. $attr .= " class='$this->class_fields_disabled'";
  1075. }
  1076. // Use class_fields_readonly if no class or style is specified in attr and field readonly.
  1077. if ($this->class_fields_readonly && stristr(" $attr", " readonly") && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  1078. $attr .= " class='$this->class_fields_readonly'";
  1079. }
  1080. // Use class_fields if no class or style is specified in attr.
  1081. if ($this->class_fields && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  1082. $attr .= " class='$this->class_fields'";
  1083. }
  1084. // Add required rows attribute if not specified in attr
  1085. if (!stristr(" $attr", " rows=")) {
  1086. $attr .= " rows='3'";
  1087. }
  1088. // Add required cols attribute if not specified in attr
  1089. if (!stristr(" $attr", " cols=")) {
  1090. $attr .= " cols='40'";
  1091. }
  1092. // Output text field
  1093. echo "<textarea name='$name' $attr>$value</textarea>";
  1094. // Store element in elements array
  1095. array_push($this->elements, array ($name, "textarea"));
  1096. }
  1097. /**
  1098. * Output a file upload field.
  1099. *
  1100. * @param string name Name of file upload field.
  1101. * @param string attr Additional HTML attributes, e.g. "id=main"
  1102. */
  1103. public function file_upload($name, $attr = false)
  1104. {
  1105. // Use class_fields_disabled if no class or style is specified in attr and field readonly.
  1106. if ($this->class_fields_disabled && stristr(" $attr", " disabled") && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  1107. $attr .= " class='$this->class_fields_disabled'";
  1108. }
  1109. // Use class_fields_readonly if no class or style is specified in attr and field readonly.
  1110. if ($this->class_fields_readonly && stristr(" $attr", " readonly") && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  1111. $attr .= " class='$this->class_fields_readonly'";
  1112. }
  1113. // Use class_fields if no class or style is specified in attr.
  1114. if ($this->class_fields && !stristr(" $attr", " class=") && !stristr(" $attr", " style=")) {
  1115. $attr .= " class='$this->class_fields'";
  1116. }
  1117. // Output text field
  1118. echo "<input type='file' name='$name' $attr />";
  1119. // Store element in elements array
  1120. array_push($this->elements, array ($name, "file"));
  1121. }
  1122. /**
  1123. * Output a two field dual select box for multiple choices
  1124. *
  1125. * @param string name Name of hidden field receiving selected values.
  1126. * @param array items Associative array with items: $value => $label.
  1127. * @param string attr Additional HTML attributes for <select
  1128. *
  1129. * Note: After posting $_POST[$name] will contain comma separated list of selected keys in $items.
  1130. * Input (selected values at start) in form->values->$name can be comma separated like above or array like normal select.
  1131. */
  1132. public function dual_select($name, $items, $attr = false)
  1133. {
  1134. // Build array of selected values
  1135. $select = $this->get($name);
  1136. if (!is_array($select) && $select) {
  1137. foreach (explode(',', $select) as $id) {
  1138. $array[$id] = $id;
  1139. }
  1140. $select = &$array;
  1141. }
  1142. $selected = array ();
  1143. foreach ($items as $value => $label) {
  1144. if (isset($select[$value])) {
  1145. $selected[$value] = $label;
  1146. }
  1147. }
  1148. $this->hidden($name, '');
  1149. $this->select($name.'_1', $items, $attr . " id='dual_${name}_a' onChange='${name}_dual_select_source_onChange()'");
  1150. $this->select($name.'_2', $selected, $attr . " id='dual_${name}_b' onClick='${name}_dual_select_dest_onClick()'");
  1151. echo "
  1152. <script type='text/javascript'>
  1153. <!--
  1154. function ${name}_dual_select_source_onChange() {
  1155. var boxLength = document.$this->name.${name}_2.length;
  1156. var selectedItem = document.$this->name.${name}_1.selectedIndex;
  1157. var selectedText = document.$this->name.${name}_1.options[selectedItem].text;
  1158. var selectedValue = document.$this->name.${name}_1.options[selectedItem].value;
  1159. var isNew = true;
  1160. var i;
  1161. for (i = 0; i < boxLength; i++) {
  1162. if (document.$this->name.${name}_2.options[i].value == selectedValue) {
  1163. isNew = false;
  1164. break;
  1165. }
  1166. }
  1167. if (isNew) {
  1168. newoption = new Option(selectedText, selectedValue, false, false);
  1169. document.$this->name.${name}_2.options[boxLength] = newoption;
  1170. }
  1171. document.$this->name.${name}_1.options[selectedItem].className = '$this->class_dual_select_marked';
  1172. ${name}_dual_select_save();
  1173. }
  1174. function ${name}_dual_select_dest_onClick() {
  1175. var boxLength = document.$this->name.${name}_2.length;
  1176. var arrSelected = new Array();
  1177. var count = 0;
  1178. var i;
  1179. for (i = 0; i < boxLength; i++) {
  1180. if (document.$this->name.${name}_2.options[i].selected) {
  1181. arrSelected[count] = document.$this->name.${name}_2.options[i].value;
  1182. }
  1183. count++;
  1184. }
  1185. for (i = 0; i < boxLength; i++) {
  1186. var x;
  1187. for (x = 0; x < arrSelected.length; x++) {
  1188. if (document.$this->name.${name}_2.options[i].value == arrSelected[x]) {
  1189. ${name}_dual_select_mark(document.$this->name.${name}_2.options[i].value, '');
  1190. document.$this->name.${name}_2.options[i] = null;
  1191. }
  1192. }
  1193. boxLength = document.$this->name.${name}_2.length;
  1194. }
  1195. ${name}_dual_select_save();
  1196. }
  1197. function ${name}_dual_select_mark(selectedValue, className) {
  1198. var boxLength = document.$this->name.${name}_1.length;
  1199. var i;
  1200. for (i = 0; i < boxLength; i++) {
  1201. if (document.$this->name.${name}_1.options[i].value == selectedValue) {
  1202. document.$this->name.${name}_1.options[i].className = className;
  1203. return;
  1204. }
  1205. }
  1206. }
  1207. function ${name}_dual_select_save() {
  1208. var strValues = '';
  1209. var boxLength = document.$this->name.${name}_2.length;
  1210. var count = 0;
  1211. if (boxLength != 0) {
  1212. for (i = 0; i < boxLength; i++) {
  1213. if (count == 0) {
  1214. strValues = document.$this->name.${name}_2.options[i].value;
  1215. }
  1216. else {
  1217. strValues = strValues + ',' + document.$this->name.${name}_2.options[i].value;
  1218. }
  1219. count++;
  1220. }
  1221. }
  1222. document.$this->name.$name.value= strValues;
  1223. }
  1224. ${name}_dual_select_save();
  1225. ";
  1226. // mark selected options
  1227. foreach ($selected as $key => $value) {
  1228. echo "
  1229. ${name}_dual_select_mark($key, '$this->class_dual_select_marked');
  1230. ";
  1231. }
  1232. echo "
  1233. // -->
  1234. </script>
  1235. ";
  1236. }
  1237. /**
  1238. * Output three form fields that act as a date contruction with javascript validation.
  1239. *
  1240. * type: ISO YYYY-MM-DD
  1241. * UK/US/EN MM/DD/YYYY
  1242. * DK/DA DD-MM-YYYY
  1243. *
  1244. * validation: NONE no validation.
  1245. * NORMAL require valid date.
  1246. * EMPTY require valid date or empty.
  1247. *
  1248. * Define the following constants before for non-English error messages:
  1249. * FORM_INCORRECT_DATE
  1250. * FORM_INCORRECT_MONTH
  1251. * FORM_INCORRECT_YEAR
  1252. * FORM_INCORRECT_DATEMONTH
  1253. * FORM_MUST_SPECIFY_DATE
  1254. *
  1255. * @param string name Name of file upload field.
  1256. * @param integer type Type of field.
  1257. * @param integer validation Type of validation.
  1258. * @param string attr Additional HTML attributes, e.g. "id=main"
  1259. */
  1260. public function date3($name, $type = "ISO", $validate = "NORMAL", $attr = false)
  1261. {
  1262. // Define constants for validation
  1263. @define("FORM_INCORRECT_DATE", "Specified date is incorrect.");
  1264. @define("FORM_INCORRECT_MONTH", "Specified month is incorrect.");
  1265. @define("FORM_INCORRECT_YEAR", "Specified year is incorrect.");
  1266. @define("FORM_INCORRECT_DATEMONTH", "Specified month/date is incorrect.");
  1267. @define("FORM_MUST_SPECIFY_DATE", "Date must be specified.");
  1268. // Get value
  1269. $value = $this->get($name);
  1270. // Extract parts and save
  1271. $this->set("${name}__yy", substr($value, 0, 4));
  1272. $this->set("${name}__mm", substr($value, 5, 2));
  1273. $this->set("${name}__dd", substr($value, 8, 2));
  1274. // Output a hidden field that will contain date afterwards. Require javascript.
  1275. $this->hidden($name, '');
  1276. $fname = $this->name;
  1277. $this->extra_code_post .= "if (document.$fname.${name}__yy.value) document.$fname.$name.value = ('0000' + document.$fname.${name}__yy.value).substr(document.$fname.${name}__yy.value.length, 4) + '-' + ('00' + document.$fname.${name}__mm.value).substr(document.$fname.${name}__mm.value.length, 2) + '-' + ('00' + document.$fname.${name}__dd.value).substr(document.$fname.${name}__dd.value.length, 2);";
  1278. // Save old field class
  1279. $class_fields = $this->class_fields;
  1280. // Replace class_fields
  1281. $this->class_fields = $this->class_datefields;
  1282. // Output fields according to type
  1283. switch ($type) {
  1284. case 'ISO':
  1285. // Save order for validation
  1286. list($y, $m, $d) = array ("¤¤¤", "¤¤", "¤");
  1287. // Output fields
  1288. $this->text("${name}__yy", "size=4");
  1289. echo " - ";
  1290. $this->text("${name}__mm", "size=2");
  1291. echo " - ";
  1292. $this->text("{$name}__dd", "size=2");
  1293. break;
  1294. case 'DK':
  1295. case 'DA':
  1296. // Save order for validation
  1297. list($y, $m, $d) = array ("¤", "¤¤", "¤¤¤");
  1298. // Output fields
  1299. $this->text("{$name}__dd", "size=2");
  1300. echo " - ";
  1301. $this->text("${name}__mm", "size=2");
  1302. echo " - ";
  1303. $this->text("${name}__yy", "size=4");
  1304. break;
  1305. case 'UK':
  1306. case 'US':
  1307. case 'EN':
  1308. // Save order for validation
  1309. list($y, $m, $d) = array ("¤", "¤¤¤", "¤¤");
  1310. // Output fields
  1311. $this->text("${name}__mm", "size=2");
  1312. echo " / ";
  1313. $this->text("{$name}__dd", "size=2");
  1314. echo " / ";
  1315. $this->text("${name}__yy", "size=4");
  1316. break;
  1317. default:
  1318. die('invalid type');
  1319. }
  1320. // Restore old field class
  1321. $this->class_fields = $class_fields;
  1322. // Validate, correct date or empty
  1323. if ($validate != "NONE") {
  1324. // Validate in correct order
  1325. for ($i = 3; $i >= 1; $i--) {
  1326. if (strlen($y) == $i) {
  1327. $this->validate("!((!$d.value.length && !$m.value.length & !$y.value.length) || ($y.value >= 1900 && $y.value <= 2100))", FORM_INCORRECT_YEAR, $y);
  1328. }
  1329. if (strlen($m) == $i) {
  1330. $this->validate("!((!$d.value.length && !$m.value.length & !$y.value.length) || ($m.value > 0 && $m.value < 13))", FORM_INCORRECT_MONTH, $m);
  1331. }
  1332. if (strlen($d) == $i) {
  1333. $this->validate("!((!$d.value.length && !$m.value.length & !$y.value.length) || ($d.value > 0 && $d.value < 32))", FORM_INCORRECT_DATE, $d);
  1334. $this->validate("$d.value == 31 && ($m.value == 4 || $m.value == 6 || $m.value == 9 || $m.value == 11)", FORM_INCORRECT_DATEMONTH, $d);
  1335. $this->validate("$d.value > 29 && $m.value == 2", FORM_INCORRECT_DATEMONTH, $d);
  1336. $this->validate("$d.value == 29 && $m.value == 2 && ($y.value % 4) > 0", FORM_INCORRECT_DATE, $d);
  1337. }
  1338. }
  1339. }
  1340. // Not empty
  1341. if ($validate == "NORMAL") {
  1342. $this->validate("!$d.value.length && !$m.value.length && !$y.value.length", FORM_MUST_SPECIFY_DATE, '¤¤¤');
  1343. }
  1344. // Save type if we desire to validate further
  1345. $this->last_datetime_type = array ($y, $m, $d);
  1346. }
  1347. /**
  1348. * Output five form fields that act as a date + time contruction with javascript validation.
  1349. *
  1350. * type: ISO YYYY-MM-DD HH:NN
  1351. * UK/US/EN MM/DD/YYYY HH:NN (24h)
  1352. * DK/DA DD-MM-YYYY HH:NN
  1353. *
  1354. * validation: NONE no validation.
  1355. * NORMAL require valid date/time
  1356. * EMPTY require valid date/time or empty.
  1357. *
  1358. * Define the following constants before for non-English error messages:
  1359. * FORM_INCORRECT_DATE
  1360. * FORM_INCORRECT_MONTH
  1361. * FORM_INCORRECT_YEAR
  1362. * FORM_INCORRECT_DATEMONTH
  1363. * FORM_MUST_SPECIFY_DATE
  1364. * FORM_INCORRECT_HOUR
  1365. * FORM_INCORRECT_MINUTE
  1366. *
  1367. * @param string name Name of file upload field.
  1368. * @param integer type Type of field.
  1369. * @param integer validation Type of validation.
  1370. * @param string attr Additional HTML attributes, e.g. "id=main"
  1371. */
  1372. public function datetime5($name, $type = "ISO", $validate = "NORMAL", $attr = false)
  1373. {
  1374. // Define constants for validation
  1375. @define("FORM_INCORRECT_HOUR", "Specified hour is incorrect.");
  1376. @define("FORM_INCORRECT_MINUTE", "Specified minute is incorrect.");
  1377. // Output date fields
  1378. $this->date3($name, $type, $validate, $attr);
  1379. // Get value
  1380. $value = $this->get($name);
  1381. // Extract time parts and save
  1382. $this->set("${name}__hh", substr($value, 11, 2));
  1383. $this->set("${name}__nn", substr($value, 14, 2));
  1384. // Update the hidden field that contains datetime afterwards. Require javascript.
  1385. $fname = $this->name;
  1386. $this->extra_code_post .= "if (document.$fname.${name}__yy.value) document.$fname.$name.value = ('0000' + document.$fname.${name}__yy.value).substr(document.$fname.${name}__yy.value.length, 4) + '-' + ('00' + document.$fname.${name}__mm.value).substr(document.$fname.${name}__mm.value.length, 2) + '-' + ('00' + document.$fname.${name}__dd.value).substr(document.$fname.${name}__dd.value.length, 2) + ' ' + ('00' + document.$fname.${name}__hh.value).substr(document.$fname.${name}__hh.value.length, 2) + ':' + ('00' + document.$fname.${name}__nn.value).substr(document.$fname.${name}__nn.value.length, 2);";
  1387. // Save old field class
  1388. $class_fields = $this->class_fields;
  1389. // Replace class_fields
  1390. $this->class_fields = $this->class_datefields;
  1391. // Output time fields
  1392. echo " &nbsp; ";
  1393. $this->text("${name}__hh", "size=2");
  1394. echo " : ";
  1395. $this->text("${name}__nn", "size=2");
  1396. // Restore old field class
  1397. $this->class_fields = $class_fields;
  1398. // Validate, correct date or empty
  1399. if ($validate != "NONE") {
  1400. list ($h, $n) = array ('¤¤', '¤');
  1401. $this->validate("!((!$h.value.length && !$n.value.length) || ($h.value >= 0 && $h.value <= 59))", FORM_INCORRECT_HOUR, $h);
  1402. $this->validate("!((!$h.value.length && !$n.value.length) || ($n.value >= 0 && $n.value <= 59))", FORM_INCORRECT_MINUTE, $n);
  1403. }
  1404. // Not empty
  1405. if ($validate == "NORMAL") {
  1406. // Date cannot be empty - validated by date3()
  1407. $this->validate("!$h.value.length && !$n.value.length", FORM_MUST_SPECIFY_DATE, "¤¤¤¤¤");
  1408. }
  1409. // Get last data type and adjust
  1410. list($y, $m, $d) = $this->last_datetime_type;
  1411. $y .= '¤¤';
  1412. $m .= '¤¤';
  1413. $d .= '¤¤';
  1414. // Save datetimetype if we desire to validate further
  1415. $this->last_datetime_type = array($y, $m, $d, $h, $n);
  1416. }
  1417. /**
  1418. * Set focus on last element.
  1419. */
  1420. public function focus() // Set focus on last element
  1421. {
  1422. $this->focus_element = sizeof($this->elements) - 1;
  1423. }
  1424. /**
  1425. * Execute javascript before submitting form.
  1426. *
  1427. * @param string code Javascript
  1428. */
  1429. public function js_before_submit($code)
  1430. {
  1431. $this->extra_code_post .= "\n$code\n";
  1432. }
  1433. /**
  1434. * Validate (with javascript) last field as by regular expression.
  1435. *
  1436. * @param string name Name for this check - function only written once
  1437. * @param string reg_exp Regular expression
  1438. * @param bool success True: reg_exp is success criterie,
  1439. * @param string errmsg Error message to show if e-mail is incorrect.
  1440. * @param string allowblank Allow user not to enter e-mail.
  1441. * @param string criteria Additional fail criteria
  1442. */
  1443. public function validate_regexp($name, $reg_exp, $success, $errmsg, $allowblank=null, $criteria=null)
  1444. {
  1445. $name = $name . "_ok";
  1446. if (!strstr($this->extra_code_pre, "function $name(field)")) {
  1447. $this->extra_code_pre .= "function $name(field)\n{\n";
  1448. $this->extra_code_pre .= " var reg_$name = $reg_exp;\n";
  1449. $this->extra_code_pre .= " return reg_$name.test(field.value)\n";
  1450. $this->extra_code_pre .= "}\n\n";
  1451. }
  1452. if ($criteria) {
  1453. $criteria = "&& $criteria";
  1454. }
  1455. if ($success) {
  1456. $name = "!$name";
  1457. }
  1458. if (!$allowblank) {
  1459. $this->validate("$name(¤) $criteria", $errmsg, '¤');
  1460. }
  1461. else {
  1462. $this->validate("¤.value.length && $name(¤) $criteria", $errmsg, '¤');
  1463. }
  1464. }
  1465. /**
  1466. * Validate (with javascript) last field as e-mail address.
  1467. *
  1468. * @param string errmsg Error message to show if e-mail is incorrect.
  1469. * @param string allowblank Allow user not to enter e-mail.
  1470. * @param string criteria Additional fail criteria
  1471. */
  1472. public function validate_email($errmsg, $allowblank=null, $criteria=null)
  1473. {
  1474. $this->validate_regexp("email", "/^[-\{\}\|\*\+\$\^\?!#%&'\/=_`~a-zA-Z0-9]+(\.[-\{\}\|\*\+\$\^\?!#%&'\/=_`~a-zA-Z0-9]+)*@(([a-zA-Z0-9]+\.)|([a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.))+[a-zA-Z]{2,6}$/", true, $errmsg, $allowblank, $criteria);
  1475. }
  1476. /**
  1477. * Validate (with javascript) last field as host name.
  1478. *
  1479. * @param string errmsg Error message to show if e-mail is incorrect.
  1480. * @param string allowblank Allow user not to enter e-mail.
  1481. * @param string criteria Additional fail criteria
  1482. */
  1483. public function validate_host($errmsg, $allowblank=null, $criteria=null)
  1484. {
  1485. $this->validate_regexp("host", "/^(([a-zA-Z0-9]+\.)|([a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.))+[a-zA-Z]{2,6}$/", true, $errmsg, $allowblank, $criteria);
  1486. }
  1487. /**
  1488. * Validate (with javascript) last field as host name or *.host.
  1489. *
  1490. * @param string errmsg Error message to show if e-mail is incorrect.
  1491. * @param string allowblank Allow user not to enter e-mail.
  1492. * @param string criteria Additional fail criteria
  1493. */
  1494. public function validate_host_wild($errmsg, $allowblank=null, $criteria=null)
  1495. {
  1496. $this->validate_regexp("host", "/^(\*\.)?(([a-zA-Z0-9]+\.)|([a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.))+[a-zA-Z]{2,6}$/", true, $errmsg, $allowblank, $criteria);
  1497. }
  1498. /**
  1499. * Validate (with javascript) last field as IP address.
  1500. *
  1501. * @param string errmsg Error message to show if ip address is incorrect.
  1502. * @param string allowblank Allow user not to enter ip address.
  1503. * @param string criteria Additional fail criteria
  1504. */
  1505. public function validate_ip($errmsg, $allowblank=false, $criteria=null)
  1506. {
  1507. $this->validate_regexp("ip", "/^(0*([1-9][0-9]?|1[0-9]{2}|2[0-4][0-9]|25[0-4]))\.(0*([1-9][0-9]?|1[0-9]{2}|2[0-4][0-9]|25[0-4]))\.(0*([1-9][0-9]?|1[0-9]{2}|2[0-4][0-9]|25[0-4]))\.(0*([1-9][0-9]?|1[0-9]{2}|2[0-4][0-9]|25[0-4]))$/", true, $errmsg, $allowblank, $criteria);
  1508. }
  1509. /**
  1510. * Validate (with javascript) last field as URL.
  1511. *
  1512. * @param string errmsg Error message to show if url is incorrect.
  1513. * @param string allowblank Allow user not to enter ip address.
  1514. * @param string criteria Additional fail criteria
  1515. */
  1516. public function validate_url($errmsg, $allowblank=false, $criteria=null)
  1517. {
  1518. $this->validate_regexp("ip", "/^(http|https|ftp):\/\//", true, $errmsg, $allowblank, $criteria);
  1519. }
  1520. /**
  1521. * Validate (with javascript) last field as an integer.
  1522. *
  1523. * @param string min Minimum value or null.
  1524. * @param string max Maximum value or null.
  1525. * @param string errmsg Show this message if last criteria fails.
  1526. */
  1527. public function validate_integer($min, $max, $errmsg, $allowblank=false)
  1528. {
  1529. $allowblank_string = $allowblank ? "¤.value.length && " : "";
  1530. $this->Validate('!(/^[0-9]*$/.test(¤.value))', $errmsg);
  1531. if (!is_null($min)) {
  1532. $this->Validate($allowblank_string . "¤.value < $min", $errmsg, "¤");
  1533. }
  1534. if (!is_null($max)) {
  1535. $this->Validate($allowblank_string . "¤.value > $max", $errmsg, "¤");
  1536. }
  1537. }
  1538. /**
  1539. * Validate (with javascript) last field as a string.
  1540. *
  1541. * @param string min Minimum value or null.
  1542. * @param string max Maximum value or null.
  1543. * @param string errmsg Show this message if last criteria fails.
  1544. */
  1545. public function validate_string($min, $max, $errmsg, $allowblank=false)
  1546. {
  1547. $allowblank_string = $allowblank ? "¤.value.length && " : "";
  1548. if (!is_null($min)) {
  1549. $this->Validate($allowblank_string . "¤.value.length < $min", $errmsg, "¤");
  1550. }
  1551. if (!is_null($max)) {
  1552. $this->Validate($allowblank_string . "¤.value.length > $max", $errmsg, "¤");
  1553. }
  1554. }
  1555. /**
  1556. * Validate (with javascript) last three fields as a date set.
  1557. *
  1558. * @param string min Minimum value (ISO format) or null.
  1559. * @param string max Maximum value (ISO format) or null.
  1560. * @param string errmsg Show this message if last criteria fails.
  1561. */
  1562. public function validate_date($min, $max, $errmsg, $allowblank=false)
  1563. {
  1564. // Get order
  1565. list($y, $m, $d) = $this->last_date_type;
  1566. // Generate allowblank string
  1567. $allowblank_string = $allowblank ? "(¤.value.length || ¤¤.value.length || ¤¤¤.value.length) && " : "";
  1568. // Validate
  1569. if (!is_null($min)) {
  1570. $this->Validate("('0000' + $y.value).substr($y.value.length, 4) + '-' + ('00' + $m.value).substr($m.value.length, 2) + '-' + ('00' + $d.value).substr($d.value.length, 2) < '$min'", $errmsg);
  1571. }
  1572. if (!is_null($max)) {
  1573. $this->Validate("('0000' + $y.value).substr($y.value.length, 4) + '-' + ('00' + $m.value).substr($m.value.length, 2) + '-' + ('00' + $d.value).substr($d.value.length, 2) > '$max'", $errmsg);
  1574. }
  1575. }
  1576. /**
  1577. * Validate (with javascript) last field as combobox.
  1578. *
  1579. * Fails if first entry is $_REQUEST['']ed.
  1580. *
  1581. * @param string errmsg Show this message if last criteria fails.
  1582. */
  1583. public function validate_select($errmsg)
  1584. {
  1585. $this->Validate('¤.selectedIndex == 0', $errmsg);
  1586. }
  1587. /**
  1588. * Validate (with javascript) last fields as group of checkboxes.
  1589. *
  1590. * Fails if wrong number of boxes has been checked.
  1591. *
  1592. * @param string num Number of fields in group.
  1593. * @param string min Minimum number of checked fields or null.
  1594. * @param string max Maximum number of checked fields or null.
  1595. * @param string errmsg Show this message if last criteria fails.
  1596. */
  1597. public function validate_checkbox_group($num, $min, $max, $errmsg)
  1598. {
  1599. // init
  1600. $e = $v = $p = "";
  1601. // Count number of checked boxes
  1602. while ($num--) {
  1603. $e .= '¤';
  1604. $v .= "$p$e.checked";
  1605. $p = " + ";
  1606. }
  1607. // Validate
  1608. if (!is_null($min)) {
  1609. $this->Validate("$v < $min", $errmsg, $e);
  1610. }
  1611. if (!is_null($max)) {
  1612. $this->Validate("$v > $max", $errmsg, $e);
  1613. }
  1614. }
  1615. /**
  1616. * Validate (with javascript) last fields as group of checkboxes.
  1617. *
  1618. * Fails if no item has been selected.
  1619. *
  1620. * @param string errmsg Show this message if this criteria fails.
  1621. */
  1622. public function validate_radio_group($num = null, $errmsg)
  1623. {
  1624. if (!strstr($this->extra_code_pre, "function validate_radio_group(field)")) {
  1625. $this->extra_code_pre .= "function validate_radio_group(field)\n{\n";
  1626. $this->extra_code_pre .= " for (counter = 0; counter < field.length; counter++)\n";
  1627. $this->extra_code_pre .= " if (field[counter].checked) return true\n";
  1628. $this->extra_code_pre .= " return false\n";
  1629. $this->extra_code_pre .= "}\n\n";
  1630. }
  1631. return $this->validate('!validate_radio_group(¤)', $errmsg);
  1632. }
  1633. /**
  1634. * Validate form with javascript.
  1635. *
  1636. * @param string fail_criteria Partial javascript code. Eg. ¤.value>5 && ¤.value.lengt>3
  1637. * ¤ = this element ¤¤ = previous element ¤¤¤ = ....
  1638. * @param string errmsg Show this message if last criteria fails.
  1639. * @param string focus_element Element on which to focus after error message was displayed.
  1640. */
  1641. public function validate($fail_criteria, $errmsg, $focus_element = '¤')
  1642. {
  1643. // Build criteria.
  1644. $fail_criteria = $this->build_js($fail_criteria);
  1645. // Get name and type of focus element. (assume it is only ¤¤¤s)
  1646. list($element, $type) = $this->elements[sizeof($this->elements) - strlen($focus_element)];
  1647. $element = 'document.' . $this->name . ".$element";
  1648. // element name has index, not supported by js, use element number instead
  1649. if (strstr($element, "[")) {
  1650. $element = 'document.' . $this->name . '.elements['.(sizeof($this->elements) - strlen($focus_element)).']';
  1651. }
  1652. // Output check_code
  1653. $this->check_code .= " if ($fail_criteria)\n";
  1654. $this->check_code .= " { alert(\"$errmsg\");\n";
  1655. if (in_array($type, array ("text", "password", "textarea", "file"))) {
  1656. $this->check_code .= " $element.select();\n";
  1657. }
  1658. if ($type != "checkbox" && $type != "radio") {
  1659. $this->check_code .= " $element.focus();\n";
  1660. }
  1661. $this->check_code .= " return false;\n";
  1662. $this->check_code .= " }\n\n";
  1663. }
  1664. /**
  1665. * Get field value.
  1666. *
  1667. * @param string key Array index or class variable.
  1668. */
  1669. protected function get($key)
  1670. {
  1671. // Recursive - get value from name[i][j][k]
  1672. if (ereg("^(.*)\[(.+)\]$", $key, $regs)) {
  1673. $value = $this->get($regs[1]);
  1674. return @$value[$regs[2]];
  1675. }
  1676. // Multi selects - has name[] - remove the [] part
  1677. $key = str_replace("[]", "", $key);
  1678. // Return value from array
  1679. if (is_array($this->values)) {
  1680. return @$this->values[$key];
  1681. }
  1682. // Return value from object
  1683. return @$this->values->$key;
  1684. }
  1685. /**
  1686. * Set field value.
  1687. *
  1688. * @param string key Array index or class variable.
  1689. */
  1690. protected function set($key, $value)
  1691. {
  1692. if (is_array($this->values)) {
  1693. @$this->values[$key] = $value;
  1694. }
  1695. else {
  1696. @$this->values->$key = $value;
  1697. }
  1698. }
  1699. /**
  1700. * Convert fail criteria (or other code) to javascript.
  1701. *
  1702. * @return string javascript code
  1703. */
  1704. protected function build_js($fail_criteria)
  1705. {
  1706. // Get number of form elements
  1707. $num = sizeof($this->elements);
  1708. $result = '';
  1709. foreach (explode("\r", ereg_replace("(¤+)", "\r\\1\r", $fail_criteria)) as $part) {
  1710. if ($part && $part[0] == '¤') {
  1711. $len = strlen($part);
  1712. list($element) = $this->elements[$num - $len];
  1713. // element name has index, not supported by js, use element number instead
  1714. if (strstr($element, "[")) {
  1715. $element = 'elements['.($num - $len).']';
  1716. }
  1717. $result .= 'document.' . $this->name . ".$element";
  1718. }
  1719. else {
  1720. $result .= $part;
  1721. }
  1722. }
  1723. return $result;
  1724. }
  1725. }
  1726. //////////////////////////////////////////////////////////////////////////////
  1727. // Tool Tips /////////////////////////////////////////////////////////////////
  1728. //////////////////////////////////////////////////////////////////////////////
  1729. /**
  1730. * HTML/JS ToolTip Generator.
  1731. *
  1732. * NOTE: Must specify valid <!DOCTYPE to work under MSIE.
  1733. *
  1734. * Define css class like this:
  1735. *
  1736. * .tooltip {
  1737. * font: 10pt/125% Verdana, sans-serif;
  1738. * background: #ffffe1;
  1739. * color: black;
  1740. * border: black 1px solid;
  1741. * margin: 2px;
  1742. * padding: 10px;
  1743. * position: absolute;
  1744. * top: 10px;
  1745. * left: 10px;
  1746. * z-index: 10000;
  1747. * visibility: hidden;
  1748. * }
  1749. */
  1750. class tool_tips
  1751. {
  1752. protected $tooltips;
  1753. /**
  1754. * Constructor
  1755. *
  1756. * Outputs javascripts
  1757. * NOTE: Must specify valid <!DOCTYPE to work under MSIE.
  1758. */
  1759. public function __construct()
  1760. {
  1761. // Init
  1762. $this->tooltips = array ();
  1763. // Output javascript
  1764. ?>
  1765. <script type="text/javascript">
  1766. <!--
  1767. function showTooltip(id, event, timeDelay, offsetX, offsetY) {
  1768. if (!document.getElementById) {
  1769. return;
  1770. }
  1771. var target = window.event ? window.event.srcElement : (event.target.tagName ? event.target : event.target.parentNode);
  1772. if (target && target.removeAttribute) {
  1773. target.title = "";
  1774. target.removeAttribute("alt");
  1775. }
  1776. var tooltip = getTooltip(id);
  1777. timeDelay = (timeDelay != null) ? timeDelay : 300;
  1778. var x,y;
  1779. if (typeof event.pageX == "number") {
  1780. x = event.pageX;
  1781. y = event.pageY;
  1782. }
  1783. else if (typeof event.clientX == "number") {
  1784. x = event.clientX + getScrollLeft();
  1785. y = event.clientY + getScrollTop();
  1786. }
  1787. x += (offsetX != null) ? offsetX : 10;
  1788. y += (offsetY != null) ? offsetY : 10;
  1789. var adjX = x + tooltip.el.offsetWidth - getViewportWidth() + 40 - getScrollLeft();
  1790. var adjY = y + tooltip.el.offsetHeight - getViewportHeight() + 20 - getScrollTop();
  1791. if (adjX > 0) {
  1792. x -= adjX;
  1793. }
  1794. if (adjY > 0) {
  1795. y -= adjY;
  1796. }
  1797. tooltip.el.style.left = x +"px";
  1798. tooltip.el.style.top = y +"px";
  1799. Tooltips[id].show(timeDelay);
  1800. }
  1801. Tooltip = function(el) {
  1802. this.id = el.id;
  1803. this.el = el;
  1804. this.blocked = false;
  1805. };
  1806. Tooltips = new Object();
  1807. function getTooltip(id) {
  1808. if (!Tooltips[id])
  1809. Tooltips[id] = new Tooltip(document.getElementById(id));
  1810. return Tooltips[id];
  1811. }
  1812. function hideTooltip(id, timeDelay) {
  1813. if (!document.getElementById)
  1814. return;
  1815. getTooltip(id).hide();
  1816. }
  1817. Tooltip.prototype.show = function(millis) {
  1818. if (this.blocked)
  1819. return;
  1820. this.blocked = true;
  1821. if (window.tooltipTimer)
  1822. clearTimeout(window.tooltipTimer);
  1823. window.tooltipTimer = setTimeout("Tooltips."+this.id+".el.style.visibility='visible';", millis);
  1824. setTimeout("Tooltips."+this.id+".blocked = false;", 1 + millis);
  1825. };
  1826. Tooltip.prototype.hide = function() {
  1827. if (window.tooltipTimer)
  1828. clearTimeout(window.tooltipTimer);
  1829. Tooltips[this.id].el.style.visibility='hidden';
  1830. Tooltips[this.id].blocked = false;
  1831. };
  1832. function getViewportHeight() {
  1833. if (window.innerHeight)
  1834. return window.innerHeight;
  1835. if (typeof window.document.documentElement.clientHeight == "number")
  1836. return window.document.documentElement.clientHeight;
  1837. return window.document.body.clientHeight;
  1838. }
  1839. function getViewportWidth() {
  1840. if (window.innerWidth)
  1841. return window.innerWidth -16;
  1842. if (typeof window.document.documentElement.clientWidth == "number")
  1843. return window.document.documentElement.clientWidth;
  1844. return window.document.body.clientWidth;
  1845. }
  1846. function getScrollLeft() {
  1847. if (typeof window.pageXOffset == "number")
  1848. return window.pageXOffset;
  1849. if (document.documentElement.scrollLeft)
  1850. return Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
  1851. else if (document.body.scrollLeft != null)
  1852. return document.body.scrollLeft;
  1853. return 0;
  1854. }
  1855. function getScrollTop() {
  1856. if (typeof window.pageYOffset == "number")
  1857. return window.pageYOffset;
  1858. if (document.documentElement.scrollTop)
  1859. return Math.max(document.documentElement.scrollTop, document.body.scrollTop);
  1860. else if (document.body.scrollTop != null)
  1861. return document.body.scrollTop;
  1862. return 0;
  1863. }
  1864. // -->
  1865. </script>
  1866. <?php
  1867. }
  1868. /**
  1869. * Create tooltip and return onmouseover code for <a>
  1870. *
  1871. * Converts wide pure text to some 300px wide table
  1872. */
  1873. public function create($html, $delay = '', $maxwidth = 300)
  1874. {
  1875. // Convert pure text to table
  1876. if (!strstr($html, "<") && (strlen($html) > $maxwidth/5)) {
  1877. $html = "<table cellpadding='0' cellspacing='0' border='0' width='$maxwidth'><tr><td align='left'>$html</td></tr></table>";
  1878. }
  1879. // Add tooltip
  1880. $this->tooltips[] = $html;
  1881. // Calc new id
  1882. $id = sizeof($this->tooltips) - 1;
  1883. // Delay
  1884. if ($delay) {
  1885. $delay = ", $delay";
  1886. }
  1887. // Return onmouseover code
  1888. return "onmouseover='showTooltip(\"tooltip$id\", event$delay);' onmouseout='hideTooltips();'";
  1889. }
  1890. /**
  1891. * Finaliste tooltips - Call after last tooltip was created
  1892. *
  1893. * Outputs javascripts
  1894. * Use </center> before this function!
  1895. */
  1896. public function done()
  1897. {
  1898. // Global onmousedown
  1899. if (!isset($this->tooltips)) {
  1900. return;
  1901. }
  1902. echo '
  1903. <script type="text/javascript">
  1904. <!--
  1905. document.onmousedown = hideTooltips;
  1906. ';
  1907. echo 'function hideTooltips(e) { ';
  1908. foreach ($this->tooltips as $id => $html) {
  1909. echo "hideTooltip('tooltip$id');";
  1910. }
  1911. echo "
  1912. }
  1913. // -->
  1914. </script>";
  1915. // Output tooltips
  1916. foreach ($this->tooltips as $id => $html) {
  1917. echo "\n<div id='tooltip$id' class='tooltip'>$html</div>\n";
  1918. }
  1919. }
  1920. }
  1921. ?>