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