]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/HtmlElement.php
add SVG support for Ploticus (and hopefully all WikiPluginCached types)
[SourceForge/phpwiki.git] / lib / HtmlElement.php
1 <?php rcs_id('$Id: HtmlElement.php,v 1.42 2004-09-26 17:09:23 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.41  2004/08/05 17:31:50  rurban
533  more xhtml conformance fixes
534
535  Revision 1.40  2004/06/25 14:29:17  rurban
536  WikiGroup refactoring:
537    global group attached to user, code for not_current user.
538    improved helpers for special groups (avoid double invocations)
539  new experimental config option ENABLE_XHTML_XML (fails with IE, and document.write())
540  fixed a XHTML validation error on userprefs.tmpl
541
542  Revision 1.39  2004/05/17 13:36:49  rurban
543  Apply RFE #952323 "ExternalSearchPlugin improvement", but
544    with <button><img></button>
545
546  Revision 1.38  2004/05/12 10:49:54  rurban
547  require_once fix for those libs which are loaded before FileFinder and
548    its automatic include_path fix, and where require_once doesn't grok
549    dirname(__FILE__) != './lib'
550  upgrade fix with PearDB
551  navbar.tmpl: remove spaces for IE &nbsp; button alignment
552
553  Revision 1.37  2004/04/26 20:44:34  rurban
554  locking table specific for better databases
555
556  Revision 1.36  2004/04/19 21:51:41  rurban
557  php5 compatibility: it works!
558
559  Revision 1.35  2004/04/19 18:27:45  rurban
560  Prevent from some PHP5 warnings (ref args, no :: object init)
561    php5 runs now through, just one wrong XmlElement object init missing
562  Removed unneccesary UpgradeUser lines
563  Changed WikiLink to omit version if current (RecentChanges)
564
565  Revision 1.34  2004/03/24 19:39:02  rurban
566  php5 workaround code (plus some interim debugging code in XmlElement)
567    php5 doesn't work yet with the current XmlElement class constructors,
568    WikiUserNew does work better than php4.
569  rewrote WikiUserNew user upgrading to ease php5 update
570  fixed pref handling in WikiUserNew
571  added Email Notification
572  added simple Email verification
573  removed emailVerify userpref subclass: just a email property
574  changed pref binary storage layout: numarray => hash of non default values
575  print optimize message only if really done.
576  forced new cookie policy: delete pref cookies, use only WIKI_ID as plain string.
577    prefs should be stored in db or homepage, besides the current session.
578
579  Revision 1.33  2004/03/18 22:32:33  rurban
580  work to make it php5 compatible
581
582  Revision 1.32  2004/02/15 21:34:37  rurban
583  PageList enhanced and improved.
584  fixed new WikiAdmin... plugins
585  editpage, Theme with exp. htmlarea framework
586    (htmlarea yet committed, this is really questionable)
587  WikiUser... code with better session handling for prefs
588  enhanced UserPreferences (again)
589  RecentChanges for show_deleted: how should pages be deleted then?
590
591  Revision 1.31  2003/02/27 22:47:26  dairiki
592  New functions in HtmlElement:
593
594  JavaScript($js)
595     Helper for generating javascript.
596
597  IfJavaScript($if_content, $else_content)
598     Helper for generating
599        <script>document.write('...')</script><noscript>...</noscript>
600     constructs.
601
602  Revision 1.30  2003/02/17 06:02:25  dairiki
603  Remove functions HiddenGets() and HiddenPosts().
604
605  These functions were evil.  They didn't check the request method,
606  so they often resulted in GET args being converted to POST args,
607  etc...
608
609  One of these is still used in lib/plugin/WikiAdminSelect.php,
610  but, so far as I can tell, that code is both broken _and_ it
611  doesn't do anything.
612
613  Revision 1.29  2003/02/15 01:54:19  dairiki
614  Added HTML::meta() for <meta> tag.
615
616  Revision 1.28  2003/01/04 02:32:30  carstenklapp
617  Added 'col' and 'colgroup' table elements used by PluginManager.
618
619  */
620
621 // (c-file-style: "gnu")
622 // Local Variables:
623 // mode: php
624 // tab-width: 8
625 // c-basic-offset: 4
626 // c-hanging-comment-ender-p: nil
627 // indent-tabs-mode: nil
628 // End:
629 ?>