3 * Code for writing the HTML subset of XML.
4 * @author: Jeff Dairiki
6 * This code is now php5 compatible. --2004-04-19 23:51:43 rurban
8 if (!class_exists("XmlElement"))
9 require_once(dirname(__FILE__)."/XmlElement.php");
10 if (class_exists("HtmlElement"))
16 //apd_set_session_trace(35);
18 class HtmlElement extends XmlElement
20 function __construct ($tagname /* , $attr_or_content , ...*/) {
21 $this->_init(func_get_args());
22 $this->_properties = HTML::getTagProperties($tagname);
25 function _init ($args) {
27 $args = func_get_args();
29 assert(count($args) >= 1);
30 assert(is_string($args[0]));
31 $this->_tag = array_shift($args);
33 if ($args && is_array($args[0]))
34 $this->_attr = array_shift($args);
36 $this->_attr = array();
37 if ($args && $args[0] === false)
40 $this->setContent($args);
41 $this->_properties = HTML::getTagProperties($this->_tag);
46 * This is used by the static factory methods is class HTML.
48 function _init2 ($args) {
50 if (is_array($args[0]))
51 $this->_attr = array_shift($args);
52 elseif ($args[0] === false)
56 if (count($args) == 1 && is_array($args[0]))
58 $this->_content = $args;
62 /** Add a "tooltip" to an element.
64 * @param $tooltip_text string The tooltip text.
66 function addTooltip ($tooltip_text, $accesskey = null) {
67 $this->setAttr('title', $tooltip_text);
68 if ($accesskey) $this->setAccesskey($accesskey);
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;");
79 function setAccesskey ($key) {
81 if (strlen($key) != 1) return;
82 $this->setAttr("accesskey", $key);
84 if (!empty($this->_attr['title'])) {
85 if (preg_match("/\[(alt-)?(.)\]$/", $this->_attr['title'], $m))
87 $this->_attr['title'] = preg_replace("/\[(alt-)?(.)\]$/", "[".$WikiTheme->tooltipAccessKeyPrefix()."-\\2]", $this->_attr['title']);
89 $this->_attr['title'] .= " [".$WikiTheme->tooltipAccessKeyPrefix()."-$key]";
92 $this->_attr['title'] = "[".$WikiTheme->tooltipAccessKeyPrefix()."-$key]";
96 function emptyTag () {
97 if (($this->_properties & HTMLTAG_EMPTY) == 0)
98 return $this->startTag() . "</$this->_tag>";
100 return substr($this->startTag(), 0, -1) . " />";
103 function hasInlineContent () {
104 return ($this->_properties & HTMLTAG_ACCEPTS_INLINE) != 0;
107 function isInlineElement () {
108 return ($this->_properties & HTMLTAG_INLINE) != 0;
112 function HTML (/* $content, ... */) {
113 return new XmlContent(func_get_args());
116 class HTML extends HtmlElement {
117 function raw ($html_text) {
118 return new RawXml($html_text);
121 function getTagProperties($tag) {
122 $props = &$GLOBALS['HTML_TagProperties'];
123 return isset($props[$tag]) ? $props[$tag] : 0;
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) {
133 if (isset($props[$tag]))
134 $props[$tag] |= $prop_flag;
136 $props[$tag] = $prop_flag;
141 // Shell script to generate the following static methods:
144 // function mkfuncs () {
147 // echo " function $tag (/*...*/) {"
148 // echo " \$el = new HtmlElement('$tag');"
149 // echo " return \$el->_init2(func_get_args());"
154 // /****************************************/'
155 // mkfuncs link meta style script noscript
157 // mkfuncs a img br span
159 // mkfuncs h1 h2 h3 h4 h5 h6
161 // mkfuncs hr div p pre blockquote
163 // mkfuncs em strong small
165 // mkfuncs tt u sup sub
167 // mkfuncs ul ol dl li dt dd
169 // mkfuncs table caption thead tbody tfoot tr td th colgroup col
171 // mkfuncs form input option select textarea
173 // mkfuncs area map frame frameset iframe nobody
175 function link (/*...*/) {
176 $el = new HtmlElement('link');
177 return $el->_init2(func_get_args());
179 function meta (/*...*/) {
180 $el = new HtmlElement('meta');
181 return $el->_init2(func_get_args());
183 function style (/*...*/) {
184 $el = new HtmlElement('style');
185 return $el->_init2(func_get_args());
187 function script (/*...*/) {
188 $el = new HtmlElement('script');
189 return $el->_init2(func_get_args());
191 function noscript (/*...*/) {
192 $el = new HtmlElement('noscript');
193 return $el->_init2(func_get_args());
196 /****************************************/
197 function a (/*...*/) {
198 $el = new HtmlElement('a');
199 return $el->_init2(func_get_args());
201 function img (/*...*/) {
202 $el = new HtmlElement('img');
203 return $el->_init2(func_get_args());
205 function br (/*...*/) {
206 $el = new HtmlElement('br');
207 return $el->_init2(func_get_args());
209 function span (/*...*/) {
210 $el = new HtmlElement('span');
211 return $el->_init2(func_get_args());
214 /****************************************/
215 function h1 (/*...*/) {
216 $el = new HtmlElement('h1');
217 return $el->_init2(func_get_args());
219 function h2 (/*...*/) {
220 $el = new HtmlElement('h2');
221 return $el->_init2(func_get_args());
223 function h3 (/*...*/) {
224 $el = new HtmlElement('h3');
225 return $el->_init2(func_get_args());
227 function h4 (/*...*/) {
228 $el = new HtmlElement('h4');
229 return $el->_init2(func_get_args());
231 function h5 (/*...*/) {
232 $el = new HtmlElement('h5');
233 return $el->_init2(func_get_args());
235 function h6 (/*...*/) {
236 $el = new HtmlElement('h6');
237 return $el->_init2(func_get_args());
240 /****************************************/
241 function hr (/*...*/) {
242 $el = new HtmlElement('hr');
243 return $el->_init2(func_get_args());
245 function div (/*...*/) {
246 $el = new HtmlElement('div');
247 return $el->_init2(func_get_args());
249 function p (/*...*/) {
250 $el = new HtmlElement('p');
251 return $el->_init2(func_get_args());
253 function pre (/*...*/) {
254 $el = new HtmlElement('pre');
255 return $el->_init2(func_get_args());
257 function blockquote (/*...*/) {
258 $el = new HtmlElement('blockquote');
259 return $el->_init2(func_get_args());
262 /****************************************/
263 function em (/*...*/) {
264 $el = new HtmlElement('em');
265 return $el->_init2(func_get_args());
267 function strong (/*...*/) {
268 $el = new HtmlElement('strong');
269 return $el->_init2(func_get_args());
271 function small (/*...*/) {
272 $el = new HtmlElement('small');
273 return $el->_init2(func_get_args());
276 /****************************************/
277 function tt (/*...*/) {
278 $el = new HtmlElement('tt');
279 return $el->_init2(func_get_args());
281 function u (/*...*/) {
282 $el = new HtmlElement('u');
283 return $el->_init2(func_get_args());
285 function sup (/*...*/) {
286 $el = new HtmlElement('sup');
287 return $el->_init2(func_get_args());
289 function sub (/*...*/) {
290 $el = new HtmlElement('sub');
291 return $el->_init2(func_get_args());
294 /****************************************/
295 function ul (/*...*/) {
296 $el = new HtmlElement('ul');
297 return $el->_init2(func_get_args());
299 function ol (/*...*/) {
300 $el = new HtmlElement('ol');
301 return $el->_init2(func_get_args());
303 function dl (/*...*/) {
304 $el = new HtmlElement('dl');
305 return $el->_init2(func_get_args());
307 function li (/*...*/) {
308 $el = new HtmlElement('li');
309 return $el->_init2(func_get_args());
311 function dt (/*...*/) {
312 $el = new HtmlElement('dt');
313 return $el->_init2(func_get_args());
315 function dd (/*...*/) {
316 $el = new HtmlElement('dd');
317 return $el->_init2(func_get_args());
320 /****************************************/
321 function table (/*...*/) {
322 $el = new HtmlElement('table');
323 return $el->_init2(func_get_args());
325 function caption (/*...*/) {
326 $el = new HtmlElement('caption');
327 return $el->_init2(func_get_args());
329 function thead (/*...*/) {
330 $el = new HtmlElement('thead');
331 return $el->_init2(func_get_args());
333 function tbody (/*...*/) {
334 $el = new HtmlElement('tbody');
335 return $el->_init2(func_get_args());
337 function tfoot (/*...*/) {
338 $el = new HtmlElement('tfoot');
339 return $el->_init2(func_get_args());
341 function tr (/*...*/) {
342 $el = new HtmlElement('tr');
343 return $el->_init2(func_get_args());
345 function td (/*...*/) {
346 $el = new HtmlElement('td');
347 return $el->_init2(func_get_args());
349 function th (/*...*/) {
350 $el = new HtmlElement('th');
351 return $el->_init2(func_get_args());
353 function colgroup (/*...*/) {
354 $el = new HtmlElement('colgroup');
355 return $el->_init2(func_get_args());
357 function col (/*...*/) {
358 $el = new HtmlElement('col');
359 return $el->_init2(func_get_args());
362 /****************************************/
363 function form (/*...*/) {
364 $el = new HtmlElement('form');
365 return $el->_init2(func_get_args());
367 function input (/*...*/) {
368 $el = new HtmlElement('input');
369 return $el->_init2(func_get_args());
371 function button (/*...*/) {
372 $el = new HtmlElement('button');
373 return $el->_init2(func_get_args());
375 function option (/*...*/) {
376 $el = new HtmlElement('option');
377 return $el->_init2(func_get_args());
379 function select (/*...*/) {
380 $el = new HtmlElement('select');
381 return $el->_init2(func_get_args());
383 function textarea (/*...*/) {
384 $el = new HtmlElement('textarea');
385 return $el->_init2(func_get_args());
387 function label (/*...*/) {
388 $el = new HtmlElement('label');
389 return $el->_init2(func_get_args());
392 /****************************************/
393 function area (/*...*/) {
394 $el = new HtmlElement('area');
395 return $el->_init2(func_get_args());
397 function map (/*...*/) {
398 $el = new HtmlElement('map');
399 return $el->_init2(func_get_args());
401 function frame (/*...*/) {
402 $el = new HtmlElement('frame');
403 return $el->_init2(func_get_args());
405 function frameset (/*...*/) {
406 $el = new HtmlElement('frameset');
407 return $el->_init2(func_get_args());
409 function iframe (/*...*/) {
410 $el = new HtmlElement('iframe');
411 return $el->_init2(func_get_args());
413 function nobody (/*...*/) {
414 $el = new HtmlElement('nobody');
415 return $el->_init2(func_get_args());
417 function object (/*...*/) {
418 $el = new HtmlElement('object');
419 return $el->_init2(func_get_args());
421 function embed (/*...*/) {
422 $el = new HtmlElement('embed');
423 return $el->_init2(func_get_args());
425 function param (/*...*/) {
426 $el = new HtmlElement('param');
427 return $el->_init2(func_get_args());
429 function legend (/*...*/) {
430 $el = new HtmlElement('legend');
431 return $el->_init2(func_get_args());
435 define('HTMLTAG_EMPTY', 1);
436 define('HTMLTAG_INLINE', 2);
437 define('HTMLTAG_ACCEPTS_INLINE', 4);
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,
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
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'
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');
460 HTML::_setTagProperty(HTMLTAG_INLINE,
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
471 * Generate hidden form input fields.
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
480 * $args = array('x' => '2',
481 * 'y' => array('a' => 'aval', 'b' => 'bval'));
482 * $inputs = HiddenInputs($args);
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" />
490 * @return object An XmlContent object containing the inputs.
492 function HiddenInputs ($query_args, $pfx = false, $exclude = array()) {
495 foreach ($query_args as $key => $val) {
496 if (in_array($key, $exclude)) continue;
497 $name = $pfx ? $pfx . "[$key]" : $key;
499 $inputs->pushContent(HiddenInputs($val, $name));
501 $inputs->pushContent(HTML::input(array('type' => 'hidden',
509 /** Generate a <script> tag containing javascript.
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.
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;
522 return HTML(HTML::script($script_args),"\n");
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");
531 /** Conditionally display content based of whether javascript is supported.
533 * This conditionally (on the client side) displays one of two alternate
534 * contents depending on whether the client supports javascript.
537 * The content you pass as arguments to this function must be block-level.
538 * (This is because the <noscript> tag is block-level.)
540 * @param mixed $if_content Content to display if the browser supports
543 * @param mixed $else_content Content to display if the browser does
544 * not support javascript.
548 function IfJavaScript($if_content = false, $else_content = false) {
551 $xml = AsXML($if_content);
552 $js = sprintf('document.write("%s");',
553 addcslashes($xml, "\0..\37!@\\\177..\377"));
554 $html[] = JavaScript($js);
557 $html[] = HTML::noscript(false, $else_content);
563 $Log: not supported by cvs2svn $
564 Revision 1.49 2007/06/02 18:23:49 rurban
567 Revision 1.48 2007/05/24 18:51:35 rurban
568 add param (for YouTube)
570 Revision 1.47 2005/08/06 12:53:36 rurban
571 beautify SCRIPT lines
573 Revision 1.46 2005/01/25 06:50:33 rurban
576 Revision 1.45 2005/01/10 18:05:56 rurban
577 php5 case-sensitivity
579 Revision 1.44 2005/01/08 20:58:19 rurban
580 ending space after colgroup breaks _setTagProperty
582 Revision 1.43 2004/11/21 11:59:14 rurban
583 remove final \n to be ob_cache independent
585 Revision 1.42 2004/09/26 17:09:23 rurban
586 add SVG support for Ploticus (and hopefully all WikiPluginCached types)
589 Revision 1.41 2004/08/05 17:31:50 rurban
590 more xhtml conformance fixes
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
599 Revision 1.39 2004/05/17 13:36:49 rurban
600 Apply RFE #952323 "ExternalSearchPlugin improvement", but
601 with <button><img></button>
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 button alignment
610 Revision 1.37 2004/04/26 20:44:34 rurban
611 locking table specific for better databases
613 Revision 1.36 2004/04/19 21:51:41 rurban
614 php5 compatibility: it works!
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)
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.
636 Revision 1.33 2004/03/18 22:32:33 rurban
637 work to make it php5 compatible
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?
648 Revision 1.31 2003/02/27 22:47:26 dairiki
649 New functions in HtmlElement:
652 Helper for generating javascript.
654 IfJavaScript($if_content, $else_content)
655 Helper for generating
656 <script>document.write('...')</script><noscript>...</noscript>
659 Revision 1.30 2003/02/17 06:02:25 dairiki
660 Remove functions HiddenGets() and HiddenPosts().
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,
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
670 Revision 1.29 2003/02/15 01:54:19 dairiki
671 Added HTML::meta() for <meta> tag.
673 Revision 1.28 2003/01/04 02:32:30 carstenklapp
674 Added 'col' and 'colgroup' table elements used by PluginManager.
678 // (c-file-style: "gnu")
683 // c-hanging-comment-ender-p: nil
684 // indent-tabs-mode: nil