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