.
**
** UltraHTML 3000 tool layer. Create functions for html tags.
**
** new it_html;
** echo html(head('title' => 'hello'), body(h1('hello'), p('Hello world!')));
**/
class it_html
{
/**
* Create a HTML object and global functions for all methods (exlcluding
* methods starting with '_') in this class plus the default tags (see below).
*
* @param $p Configuration settings. Can be set/overridden in constructor, configure(), html() or head().
* See source code for a list of supported values
*/
function it_html($p = array())
{
# Default configuration of html class
$this->p = $p + array(
'charset' => 'iso-8859-1',
'doctype' => null, # Custom doctype (will usually be calculated from htmltype)
'head' => '', # Code to put into head() section
'htmltype' => 'xhtml', # 'html' (=old-style), 'xhtml' or 'xhtml-mobile'
'lang' => 'de', # Language code to use in tag
'ie_png_fix' => false, # To enable, supply URL of a transparent gif (like /images/0.gif)
'moretags' => '', # Comma-separated list of tag-functions to generate additionally to 'tags'
'name' => 'it_html', # Name of global variable $this is assigned to (string), XXX Copy and paste in configure() to keep PHP4 compatibility
'nonewlinetags' => 'a,b,em,img,input,span', # tags that do not like newlines after them
'notexported' => 'configure,sanitize',# Those methods are not exported
'prettyprint' => false, # Should output be prettily indented?
'show_boot_dom' => false, # If true, append invisible
at the end of body
'show_content_type' => true, # If true, add header
'show_favicon' => true, # If true, add tag to /favicon.ico if it exists
'staticallycallable' => 'q,u,select', # Those methods are statically callable (have same arguments as global stubs) but are a bit slower
'tags' => 'a,b,br,button,div,em,fieldset,form,h1,h2,h3,h4,h5,h6,hr,input,label,legend,li,meta,noscript,p,span,style,table,td,textarea,th,tr,ul',
'title' => '', # HTML title (default: no title added)
'use_it_state' => false, # If true, generate code needed by state.js (aka 'history iframe')
'autoquote' => false, # Automatically pass plain strings through Q()
'reportquote' => 0, # Report plain strings with this error level (e.g. E_USER_NOTICE)
);
# We know these doctypes. If you need something else, supply 'doctype' in p
$this->doctypes = array(
'html' => '',
'xhtml' => '',
'xhtml-mobile' => ''
);
$this->hasnonewline = array_flip(explode(',', $this->p['nonewlinetags']));
$notexported = array_flip(explode(',', "dummy," . $this->p['notexported'])); # dummy keeps values > 0
# Create global functions for _tags
foreach (array_merge(explode(',', $this->p['tags']), explode(',', $this->p['moretags'])) as $func)
{
if (!function_exists($func) && $func)
$code[$func] = "function $func() { \$args = func_get_args(); return new it_tag('$func', \$args); }";
}
# Create global functions for it_html methods
foreach (get_class_methods(get_class($this)) as $func)
{
if (!preg_match('/^_/', $func) && !is_a($this, $func) && $func && !function_exists($func) && !$notexported[$func])
$code[$func] = "function $func() { \$args = func_get_args(); return \$GLOBALS['{$this->p['name']}']->$func(\$args); }";
}
# Create global functions for methods that are statically callable (have same arguments as global stubs)
foreach (explode(',', $this->p['staticallycallable']) as $func)
{
if ($func && !function_exists($func))
$code[$func] = "function $func() { \$args = func_get_args(); return call_user_func_array(array(&\$GLOBALS['{$this->p['name']}'], '$func'), \$args); }";
}
eval(join('', (array)$code));
# Since name is given as param, it is our duty to store it, not our caller's.
$GLOBALS[$this->p['name']] =& $this;
}
/**
* Modify configuration of it_html, e.g. htmltype after it was instantiated.
* @param $p Configuration settings. Can be set/overridden in constructor, configure(), html() or head().
* See constructor for a list of supported values
*/
function configure($p)
{
$p += array('name' => "it_html"); # XXX Copy and paste from constructor to keep PHP4 compatibility
$GLOBALS[$p['name']]->p = $p + (array)$GLOBALS[$p['name']]->p;
$GLOBALS[$p['name']]->hasnonewline = array_flip(explode(',', $GLOBALS[$p['name']]->p['nonewlinetags']));
}
/**
* Return doctype and entire HTML page.
* Example application code to render page:
* echo html(head(...), body(...));
*
* @param any number of text args or array of key => value pairs
* Defaults for key => value parameters are inherited from the it_html constructor and should be set there.
* The parameters are $p['lang'], $p['htmltype'] and $p['doctype']
*/
function html($args)
{
$result = new it_tag('html');
list($data, $p) = $this->_parse_args($args);
$p += $this->p;
$result->prefix = EDC('upd') ? "" : (($p['doctype'] ? $p['doctype'] : $this->doctypes[$p['htmltype']]) . "\n");
if ($p['htmltype'] == "xhtml")
$result['xmlns'] = "http://www.w3.org/1999/xhtml";
$result[$p['htmltype'] == "xhtml-mobile" ? "xml:lang" : "lang"] = $p['lang'];
$result[] = $data;
return $result;
}
/**
* Return HTML header on first call or empty string on subsequent calls
*
* @param args... any number of assoc arrays and strings. strings will be content of
* @param $p['content-type'] content type (default: "text/html; charset=iso-8859-1")
* @param $p['cssinline'] stylesheet to be put in header
* @param $p['description'] data for tag
* @param $p['keywords'] data for tag
* @param $p['stylesheets'] array mediatype => url of styleshests
* @param $p['title'] content of , will be html encoded
*/
function head($args = array())
{
$result = array();
if (!$this->head_sent++)
{
$result = new it_tag('head');
list($data, $p) = $this->_parse_args($args);
$p += $this->p;
$this->p = ($p += array('content-type' => "text/html; charset={$p['charset']}"));
if ($p['show_content_type'])
$result[] = new it_tag('meta', array('http-equiv' => "Content-Type", 'content' => $p['content-type']));
foreach(array('description', 'keywords') as $name)
if (!empty($p[$name]))
$result[] = new it_tag('meta', array('name' => $name, 'content' => $p[$name]));
# Add favicon if file exists
if ($p['show_favicon'] && @file_exists($_SERVER['DOCUMENT_ROOT'] . '/favicon.ico'))
$result[] = new it_tag('link', array('rel' => "shortcut", 'href' => "/favicon.ico"));
foreach((array)$p['stylesheets'] as $type => $url)
$result[] = new it_tag('link', array('rel' => "stylesheet", 'type' => "text/css", 'href' => $url) + (is_int($type) ? array() : array('media' => $type)));
if (!empty($p['cssinline']))
$result[] = new it_tag('style', array('type' => "text/css", "\n" . preg_replace(array('/\s*\/\*[^\*]+\*\//Um', '/\s*\{\s*/', '/;\s+/'), array('', '{', ';'), $p['cssinline'])));
if ($p['head'])
$result[] = $p['head'];
$result[] = new it_tag('title', new it_q($p['title']));
if($this->p['htmltype'] == "xhtml-mobile" && strpos($_SERVER['HTTP_USER_AGENT'], 'W3C_Validator'))
header("Content-Type: application/xhtml+xml; charset={$this->p['charset']}"); # for validation
else if (!headers_sent()) # prevent warnings when ED() in use
header("Content-Type: " . $p['content-type']);
$js = $p['jsenv'] ? "var env = " . itjs::serialize($p['jsenv']) . ";\n" : '';
if ($p['js'])
{
$checksum = itjs::checksum(itjs::filenames($p['js']));
$js .= $this->_itjs("boot.js", "inline");
$js .= "function it_boot_start(){ " . trim($p['jsboot']) . " }\n";
$js .= "it_boot('/itjs/" . U($p['js'], array('s' => $checksum)) . "');\n";
}
$js .= $this->_itjs($p['jsinline'], 'inline');
if ($js)
$result[] = $this->js(array($js));
foreach ($data as $value)
$result[] = $value;
}
return $result;
}
/**
* Return HTML head (if not already sent) and body with it_state and it_boot magic code
*/
function body($args)
{
$result = $this->head();
if ($this->p['use_it_state'])
array_unshift($args, new it_tag('iframe', array('id' => "it_state", 'src' => "/itjs/state.html", 'width' => 1, 'height' => 1, 'frameborder' => 0)));
if ($this->p['show_boot_dom'])
$args[] = new it_tag('div', array('id' => "it_boot_dom", 'style' => "visibility:hidden"));
$result[] = new it_tag('body', $args);
return $result;
}
/**
* INTERNAL: Parse an arg array (mixed key=>value pairs and strings) and return it
* as array(0 => all numerical args concatenated, 1 => array(key=>value pairs)
*/
function _parse_args($args)
{
$p = array();
$data = array();
foreach ($args as $arg)
{
if (is_array($arg))
{
foreach ($arg as $key => $value)
{
if (is_int($key))
$data[] = $value;
else
$p[$key] = $value;
}
}
else
$data[] = $arg;
}
return array($data, $p);
}
/**
* function div($args...)
* Return a
...
element
* Any strings in the argument list will be content of the
* Any associative arrays among the arguments will create attributes for
.
* Attributes with values false or null will be omitted completely.
* Attributes with value true can be used for boolean attributes like 'checked'
* Attribute values will be html encoded, content values won't so you may need to use Q().
* @see _tag()
*/ #:}
/**
* Return a containing optional data.
* @param $name tag name ('style', etc.)
* @param ... any number optional data or array of key => value arguments
* @return string containing XML/HTML tag
*/
function tag($args)
{
$name = array_shift($args);
return new it_tag($name, $args);
}
/**
* Special img() function patches png transparency for IE 5.5-6 if ie_png_fix is set
* @param ... any number optional data or array of key => value arguments
* @return
*/
function img($args)
{
if ($this->p['ie_png_fix'] && preg_match('/MSIE [56]/', $_SERVER['HTTP_USER_AGENT']))
{
foreach($args as $id => $arg)
{
if (preg_match('/\.png(\?.*)?$/', $arg['src']))
{
$args[$id]['style'] = "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='{$arg['src']}',sizingMethod='scale');" . $arg['style'];
$args[$id]['src'] = $this->p['ie_png_fix'];
}
}
}
return new it_tag("img", $args);
}
/**
* Create a dropdown menu object. Warning: encodes html code within options!
* @param $tags key => value pairs of