PageRenderTime 64ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/php-getid3-2.0.0b5/sample_apps/morg/morg/abstraction.php

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