]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/HtmlElement.php
remove final \n to be ob_cache independent
[SourceForge/phpwiki.git] / lib / HtmlElement.php
1 <?php rcs_id('$Id: HtmlElement.php,v 1.43 2004-11-21 11:59:14 rurban Exp $');
2 /**
3  * Code for writing the HTML subset of XML.
4  * @author: Jeff Dairiki
5  *
6  * This code is now php5 compatible. --2004-04-19 23:51:43 rurban
7  */
8 if (!class_exists("XmlElement"))
9     require_once(dirname(__FILE__)."/XmlElement.php");
10 if (class_exists("HtmlElement"))
11     return;
12
13 /**
14  * An XML element.
15  */
16 //apd_set_session_trace(35);
17
18 class HtmlElement extends XmlElement
19 {
20     function __construct ($tagname /* , $attr_or_content , ...*/) {
21         $this->_init(func_get_args());
22         $this->_properties = HTML::getTagProperties($tagname);
23     }
24
25     function _init ($args) {
26         if (!is_array($args))
27             $args = func_get_args();
28
29         assert(count($args) >= 1);
30         assert(is_string($args[0]));
31         $this->_tag = array_shift($args);
32         
33         if ($args && is_array($args[0]))
34             $this->_attr = array_shift($args);
35         else {
36             $this->_attr = array();
37             if ($args && $args[0] === false)
38                 array_shift($args);
39         }
40         $this->setContent($args);
41         $this->_properties = HTML::getTagProperties($this->_tag);
42     }
43
44     /**
45      * @access protected
46      * This is used by the static factory methods is class HTML.
47      */
48     function _init2 ($args) {
49         if ($args) {
50             if (is_array($args[0]))
51                 $this->_attr = array_shift($args);
52             elseif ($args[0] === false)
53                 array_shift($args);
54         }
55         
56         if (count($args) == 1 && is_array($args[0]))
57             $args = $args[0];
58         $this->_content = $args;
59         return $this;
60     }
61
62     /** Add a "tooltip" to an element.
63      *
64      * @param $tooltip_text string The tooltip text.
65      */
66     function addTooltip ($tooltip_text) {
67         $this->setAttr('title', $tooltip_text);
68
69         // FIXME: this should be initialized from title by an onLoad() function.
70         //        (though, that may not be possible.)
71         $qtooltip = str_replace("'", "\\'", $tooltip_text);
72         $this->setAttr('onmouseover',
73                        sprintf('window.status="%s"; return true;',
74                                addslashes($tooltip_text)));
75         $this->setAttr('onmouseout', "window.status='';return true;");
76     }
77
78     function emptyTag () {
79         if (($this->_properties & HTMLTAG_EMPTY) == 0)
80             return $this->startTag() . "</$this->_tag>";
81
82         return substr($this->startTag(), 0, -1) . " />";
83     }
84
85     function hasInlineContent () {
86         return ($this->_properties & HTMLTAG_ACCEPTS_INLINE) != 0;
87     }
88
89     function isInlineElement () {
90         return ($this->_properties & HTMLTAG_INLINE) != 0;
91     }
92 };
93
94 function HTML (/* $content, ... */) {
95     return new XmlContent(func_get_args());
96 }
97
98 class HTML extends HtmlElement {
99     function raw ($html_text) {
100         return new RawXML($html_text);
101     }
102     
103     function getTagProperties($tag) {
104         $props = &$GLOBALS['HTML_TagProperties'];
105         return isset($props[$tag]) ? $props[$tag] : 0;
106     }
107
108     function _setTagProperty($prop_flag, $tags) {
109         $props = &$GLOBALS['HTML_TagProperties'];
110         if (is_string($tags))
111             $tags = preg_split('/\s+/', $tags);
112         foreach ($tags as $tag) {
113             if (isset($props[$tag]))
114                 $props[$tag] |= $prop_flag;
115             else
116                 $props[$tag] = $prop_flag;
117         }
118     }
119
120     //
121     // Shell script to generate the following static methods:
122     //
123     // #!/bin/sh
124     // function mkfuncs () {
125     //     for tag in "$@"
126     //     do
127     //         echo "    function $tag (/*...*/) {"
128     //         echo "        \$el = new HtmlElement('$tag');"
129     //         echo "        return \$el->_init2(func_get_args());"
130     //         echo "    }"
131     //     done
132     // }
133     // d='
134     //     /****************************************/'
135     // mkfuncs link meta style script noscript
136     // echo "$d"
137     // mkfuncs a img br span
138     // echo "$d"
139     // mkfuncs h1 h2 h3 h4 h5 h6
140     // echo "$d"
141     // mkfuncs hr div p pre blockquote
142     // echo "$d"
143     // mkfuncs em strong small
144     // echo "$d"
145     // mkfuncs tt u sup sub
146     // echo "$d"
147     // mkfuncs ul ol dl li dt dd
148     // echo "$d"
149     // mkfuncs table caption thead tbody tfoot tr td th colgroup col
150     // echo "$d"
151     // mkfuncs form input option select textarea
152     // echo "$d"
153     // mkfuncs area map frame frameset iframe nobody
154
155     function link (/*...*/) {
156         $el = new HtmlElement('link');
157         return $el->_init2(func_get_args());
158     }
159     function meta (/*...*/) {
160         $el = new HtmlElement('meta');
161         return $el->_init2(func_get_args());
162     }
163     function style (/*...*/) {
164         $el = new HtmlElement('style');
165         return $el->_init2(func_get_args());
166     }
167     function script (/*...*/) {
168         $el = new HtmlElement('script');
169         return $el->_init2(func_get_args());
170     }
171     function noscript (/*...*/) {
172         $el = new HtmlElement('noscript');
173         return $el->_init2(func_get_args());
174     }
175
176     /****************************************/
177     function a (/*...*/) {
178         $el = new HtmlElement('a');
179         return $el->_init2(func_get_args());
180     }
181     function img (/*...*/) {
182         $el = new HtmlElement('img');
183         return $el->_init2(func_get_args());
184     }
185     function br (/*...*/) {
186         $el = new HtmlElement('br');
187         return $el->_init2(func_get_args());
188     }
189     function span (/*...*/) {
190         $el = new HtmlElement('span');
191         return $el->_init2(func_get_args());
192     }
193
194     /****************************************/
195     function h1 (/*...*/) {
196         $el = new HtmlElement('h1');
197         return $el->_init2(func_get_args());
198     }
199     function h2 (/*...*/) {
200         $el = new HtmlElement('h2');
201         return $el->_init2(func_get_args());
202     }
203     function h3 (/*...*/) {
204         $el = new HtmlElement('h3');
205         return $el->_init2(func_get_args());
206     }
207     function h4 (/*...*/) {
208         $el = new HtmlElement('h4');
209         return $el->_init2(func_get_args());
210     }
211     function h5 (/*...*/) {
212         $el = new HtmlElement('h5');
213         return $el->_init2(func_get_args());
214     }
215     function h6 (/*...*/) {
216         $el = new HtmlElement('h6');
217         return $el->_init2(func_get_args());
218     }
219
220     /****************************************/
221     function hr (/*...*/) {
222         $el = new HtmlElement('hr');
223         return $el->_init2(func_get_args());
224     }
225     function div (/*...*/) {
226         $el = new HtmlElement('div');
227         return $el->_init2(func_get_args());
228     }
229     function p (/*...*/) {
230         $el = new HtmlElement('p');
231         return $el->_init2(func_get_args());
232     }
233     function pre (/*...*/) {
234         $el = new HtmlElement('pre');
235         return $el->_init2(func_get_args());
236     }
237     function blockquote (/*...*/) {
238         $el = new HtmlElement('blockquote');
239         return $el->_init2(func_get_args());
240     }
241
242     /****************************************/
243     function em (/*...*/) {
244         $el = new HtmlElement('em');
245         return $el->_init2(func_get_args());
246     }
247     function strong (/*...*/) {
248         $el = new HtmlElement('strong');
249         return $el->_init2(func_get_args());
250     }
251     function small (/*...*/) {
252         $el = new HtmlElement('small');
253         return $el->_init2(func_get_args());
254     }
255
256     /****************************************/
257     function tt (/*...*/) {
258         $el = new HtmlElement('tt');
259         return $el->_init2(func_get_args());
260     }
261     function u (/*...*/) {
262         $el = new HtmlElement('u');
263         return $el->_init2(func_get_args());
264     }
265     function sup (/*...*/) {
266         $el = new HtmlElement('sup');
267         return $el->_init2(func_get_args());
268     }
269     function sub (/*...*/) {
270         $el = new HtmlElement('sub');
271         return $el->_init2(func_get_args());
272     }
273
274     /****************************************/
275     function ul (/*...*/) {
276         $el = new HtmlElement('ul');
277         return $el->_init2(func_get_args());
278     }
279     function ol (/*...*/) {
280         $el = new HtmlElement('ol');
281         return $el->_init2(func_get_args());
282     }
283     function dl (/*...*/) {
284         $el = new HtmlElement('dl');
285         return $el->_init2(func_get_args());
286     }
287     function li (/*...*/) {
288         $el = new HtmlElement('li');
289         return $el->_init2(func_get_args());
290     }
291     function dt (/*...*/) {
292         $el = new HtmlElement('dt');
293         return $el->_init2(func_get_args());
294     }
295     function dd (/*...*/) {
296         $el = new HtmlElement('dd');
297         return $el->_init2(func_get_args());
298     }
299
300     /****************************************/
301     function table (/*...*/) {
302         $el = new HtmlElement('table');
303         return $el->_init2(func_get_args());
304     }
305     function caption (/*...*/) {
306         $el = new HtmlElement('caption');
307         return $el->_init2(func_get_args());
308     }
309     function thead (/*...*/) {
310         $el = new HtmlElement('thead');
311         return $el->_init2(func_get_args());
312     }
313     function tbody (/*...*/) {
314         $el = new HtmlElement('tbody');
315         return $el->_init2(func_get_args());
316     }
317     function tfoot (/*...*/) {
318         $el = new HtmlElement('tfoot');
319         return $el->_init2(func_get_args());
320     }
321     function tr (/*...*/) {
322         $el = new HtmlElement('tr');
323         return $el->_init2(func_get_args());
324     }
325     function td (/*...*/) {
326         $el = new HtmlElement('td');
327         return $el->_init2(func_get_args());
328     }
329     function th (/*...*/) {
330         $el = new HtmlElement('th');
331         return $el->_init2(func_get_args());
332     }
333     function colgroup (/*...*/) {
334         $el = new HtmlElement('colgroup');
335         return $el->_init2(func_get_args());
336     }
337     function col (/*...*/) {
338         $el = new HtmlElement('col');
339         return $el->_init2(func_get_args());
340     }
341
342     /****************************************/
343     function form (/*...*/) {
344         $el = new HtmlElement('form');
345         return $el->_init2(func_get_args());
346     }
347     function input (/*...*/) {
348         $el = new HtmlElement('input');
349         return $el->_init2(func_get_args());
350     }
351     function button (/*...*/) {
352         $el = new HtmlElement('button');
353         return $el->_init2(func_get_args());
354     }
355     function option (/*...*/) {
356         $el = new HtmlElement('option');
357         return $el->_init2(func_get_args());
358     }
359     function select (/*...*/) {
360         $el = new HtmlElement('select');
361         return $el->_init2(func_get_args());
362     }
363     function textarea (/*...*/) {
364         $el = new HtmlElement('textarea');
365         return $el->_init2(func_get_args());
366     }
367
368     /****************************************/
369     function area (/*...*/) {
370         $el = new HtmlElement('area');
371         return $el->_init2(func_get_args());
372     }
373     function map (/*...*/) {
374         $el = new HtmlElement('map');
375         return $el->_init2(func_get_args());
376     }
377     function frame (/*...*/) {
378         $el = new HtmlElement('frame');
379         return $el->_init2(func_get_args());
380     }
381     function frameset (/*...*/) {
382         $el = new HtmlElement('frameset');
383         return $el->_init2(func_get_args());
384     }
385     function iframe (/*...*/) {
386         $el = new HtmlElement('iframe');
387         return $el->_init2(func_get_args());
388     }
389     function nobody (/*...*/) {
390         $el = new HtmlElement('nobody');
391         return $el->_init2(func_get_args());
392     }
393     function object (/*...*/) {
394         $el = new HtmlElement('object');
395         return $el->_init2(func_get_args());
396     }
397     function embed (/*...*/) {
398         $el = new HtmlElement('embed');
399         return $el->_init2(func_get_args());
400     }
401 }
402
403 define('HTMLTAG_EMPTY', 1);
404 define('HTMLTAG_INLINE', 2);
405 define('HTMLTAG_ACCEPTS_INLINE', 4);
406
407
408 HTML::_setTagProperty(HTMLTAG_EMPTY,
409                       'area base basefont br col frame hr img input isindex link meta param');
410 HTML::_setTagProperty(HTMLTAG_ACCEPTS_INLINE,
411                       // %inline elements:
412                       'b big i small tt ' // %fontstyle
413                       . 's strike u ' // (deprecated)
414                       . 'abbr acronym cite code dfn em kbd samp strong var ' //%phrase
415                       . 'a img object embed br script map q sub sup span bdo '//%special
416                       . 'button input label option select textarea ' //%formctl
417
418                       // %block elements which contain inline content
419                       . 'address h1 h2 h3 h4 h5 h6 p pre '
420                       // %block elements which contain either block or inline content
421                       . 'div fieldset frameset'
422
423                       // other with inline content
424                       . 'caption dt label legend '
425                       // other with either inline or block
426                       . 'dd del ins li td th colgroup ');
427
428 HTML::_setTagProperty(HTMLTAG_INLINE,
429                       // %inline elements:
430                       'b big i small tt ' // %fontstyle
431                       . 's strike u ' // (deprecated)
432                       . 'abbr acronym cite code dfn em kbd samp strong var ' //%phrase
433                       . 'a img object br script map q sub sup span bdo '//%special
434                       . 'button input label option select textarea ' //%formctl
435                       . 'nobody iframe'
436                       );
437
438 /**
439  * Generate hidden form input fields.
440  *
441  * @param $query_args hash  A hash mapping names to values for the hidden inputs.
442  * Values in the hash can themselves be hashes.  The will result in hidden inputs
443  * which will reconstruct the nested structure in the resulting query args as
444  * processed by PHP.
445  *
446  * Example:
447  *
448  * $args = array('x' => '2',
449  *               'y' => array('a' => 'aval', 'b' => 'bval'));
450  * $inputs = HiddenInputs($args);
451  *
452  * Will result in:
453  *
454  *  <input type="hidden" name="x" value = "2" />
455  *  <input type="hidden" name="y[a]" value = "aval" />
456  *  <input type="hidden" name="y[b]" value = "bval" />
457  *
458  * @return object An XmlContent object containing the inputs.
459  */
460 function HiddenInputs ($query_args, $pfx = false, $exclude = array()) {
461     $inputs = HTML();
462
463     foreach ($query_args as $key => $val) {
464         if (in_array($key,$exclude)) continue;
465         $name = $pfx ? $pfx . "[$key]" : $key;
466         if (is_array($val))
467             $inputs->pushContent(HiddenInputs($val, $name));
468         else
469             $inputs->pushContent(HTML::input(array('type' => 'hidden',
470                                                    'name' => $name,
471                                                    'value' => $val)));
472     }
473     return $inputs;
474 }
475
476
477 /** Generate a <script> tag containing javascript.
478  *
479  * @param string $js  The javascript.
480  * @param string $script_args  (optional) hash of script tags options
481  *                             e.g. to provide another version or the defer attr
482  * @return HtmlElement A <script> element.
483  */
484 function JavaScript ($js, $script_args = false) {
485     $default_script_args = array(//'version' => 'JavaScript', // not xhtml conformant
486                                  'type' => 'text/javascript');
487     $script_args = $script_args ? array_merge($default_script_args,$script_args)
488                                 : $default_script_args;
489     if (empty($js))
490         return HTML::script($script_args);
491     else
492         // see http://devedge.netscape.com/viewsource/2003/xhtml-style-script/
493         return HTML::script($script_args,
494                             new RawXml((ENABLE_XHTML_XML ? "\n//<![CDATA[" : "\n<!--//")
495                                        . "\n".rtrim($js)."\n"
496                                        . (ENABLE_XHTML_XML ? "//]]>\n" : "// -->")));
497 }
498
499 /** Conditionally display content based of whether javascript is supported.
500  *
501  * This conditionally (on the client side) displays one of two alternate
502  * contents depending on whether the client supports javascript.
503  *
504  * NOTE:
505  * The content you pass as arguments to this function must be block-level.
506  * (This is because the <noscript> tag is block-level.)
507  *
508  * @param mixed $if_content Content to display if the browser supports
509  * javascript.
510  *
511  * @param mixed $else_content Content to display if the browser does
512  * not support javascript.
513  *
514  * @return XmlContent
515  */
516 function IfJavaScript($if_content = false, $else_content = false) {
517     $html = array();
518     if ($if_content) {
519         $xml = AsXML($if_content);
520         $js = sprintf('document.write("%s");',
521                       addcslashes($xml, "\0..\37!@\\\177..\377"));
522         $html[] = JavaScript($js);
523     }
524     if ($else_content) {
525         $html[] = HTML::noscript(false, $else_content);
526     }
527     return HTML($html);
528 }
529     
530 /**
531  $Log: not supported by cvs2svn $
532  Revision 1.42  2004/09/26 17:09:23  rurban
533  add SVG support for Ploticus (and hopefully all WikiPluginCached types)
534  SWF not yet.
535
536  Revision 1.41  2004/08/05 17:31:50  rurban
537  more xhtml conformance fixes
538
539  Revision 1.40  2004/06/25 14:29:17  rurban
540  WikiGroup refactoring:
541    global group attached to user, code for not_current user.
542    improved helpers for special groups (avoid double invocations)
543  new experimental config option ENABLE_XHTML_XML (fails with IE, and document.write())
544  fixed a XHTML validation error on userprefs.tmpl
545
546  Revision 1.39  2004/05/17 13:36:49  rurban
547  Apply RFE #952323 "ExternalSearchPlugin improvement", but
548    with <button><img></button>
549
550  Revision 1.38  2004/05/12 10:49:54  rurban
551  require_once fix for those libs which are loaded before FileFinder and
552    its automatic include_path fix, and where require_once doesn't grok
553    dirname(__FILE__) != './lib'
554  upgrade fix with PearDB
555  navbar.tmpl: remove spaces for IE &nbsp; button alignment
556
557  Revision 1.37  2004/04/26 20:44:34  rurban
558  locking table specific for better databases
559
560  Revision 1.36  2004/04/19 21:51:41  rurban
561  php5 compatibility: it works!
562
563  Revision 1.35  2004/04/19 18:27:45  rurban
564  Prevent from some PHP5 warnings (ref args, no :: object init)
565    php5 runs now through, just one wrong XmlElement object init missing
566  Removed unneccesary UpgradeUser lines
567  Changed WikiLink to omit version if current (RecentChanges)
568
569  Revision 1.34  2004/03/24 19:39:02  rurban
570  php5 workaround code (plus some interim debugging code in XmlElement)
571    php5 doesn't work yet with the current XmlElement class constructors,
572    WikiUserNew does work better than php4.
573  rewrote WikiUserNew user upgrading to ease php5 update
574  fixed pref handling in WikiUserNew
575  added Email Notification
576  added simple Email verification
577  removed emailVerify userpref subclass: just a email property
578  changed pref binary storage layout: numarray => hash of non default values
579  print optimize message only if really done.
580  forced new cookie policy: delete pref cookies, use only WIKI_ID as plain string.
581    prefs should be stored in db or homepage, besides the current session.
582
583  Revision 1.33  2004/03/18 22:32:33  rurban
584  work to make it php5 compatible
585
586  Revision 1.32  2004/02/15 21:34:37  rurban
587  PageList enhanced and improved.
588  fixed new WikiAdmin... plugins
589  editpage, Theme with exp. htmlarea framework
590    (htmlarea yet committed, this is really questionable)
591  WikiUser... code with better session handling for prefs
592  enhanced UserPreferences (again)
593  RecentChanges for show_deleted: how should pages be deleted then?
594
595  Revision 1.31  2003/02/27 22:47:26  dairiki
596  New functions in HtmlElement:
597
598  JavaScript($js)
599     Helper for generating javascript.
600
601  IfJavaScript($if_content, $else_content)
602     Helper for generating
603        <script>document.write('...')</script><noscript>...</noscript>
604     constructs.
605
606  Revision 1.30  2003/02/17 06:02:25  dairiki
607  Remove functions HiddenGets() and HiddenPosts().
608
609  These functions were evil.  They didn't check the request method,
610  so they often resulted in GET args being converted to POST args,
611  etc...
612
613  One of these is still used in lib/plugin/WikiAdminSelect.php,
614  but, so far as I can tell, that code is both broken _and_ it
615  doesn't do anything.
616
617  Revision 1.29  2003/02/15 01:54:19  dairiki
618  Added HTML::meta() for <meta> tag.
619
620  Revision 1.28  2003/01/04 02:32:30  carstenklapp
621  Added 'col' and 'colgroup' table elements used by PluginManager.
622
623  */
624
625 // (c-file-style: "gnu")
626 // Local Variables:
627 // mode: php
628 // tab-width: 8
629 // c-basic-offset: 4
630 // c-hanging-comment-ender-p: nil
631 // indent-tabs-mode: nil
632 // End:
633 ?>