From 6487a8beebb126105c3fd1efa748a936bd8a67af Mon Sep 17 00:00:00 2001
From: Christian Weber
Date: Fri, 31 Aug 2007 17:04:04 +0000
Subject: Great cleanup, get rid of this->_* vars in favor of p[], add method
html() to output entire page, got rid of asymmetric endhtml()
---
it_html.class | 494 +++++++++++++++++++++++++++-------------------------------
1 file changed, 232 insertions(+), 262 deletions(-)
(limited to 'it_html.class')
diff --git a/it_html.class b/it_html.class
index f05003d..af31ee5 100644
--- a/it_html.class
+++ b/it_html.class
@@ -2,121 +2,201 @@
/*
** $Id$
**
-** ITools - the Internet Tools Library
+** Copyright (C) 1995-2007 by the ITools Authors.
+** This file is part of ITools - the Internet Tools Library
**
-** Copyright (C) 1995-2003 by the ITools Authors.
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of either the GNU General Public License
-** or the GNU Lesser General Public License, as published by the Free
-** Software Foundation. See http://www.gnu.org/licenses/ for details.
+** ITools is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 3 of the License, or
+** (at your option) any later version.
+**
+** ITools is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program. If not, see .
**
** UltraHTML 3000 tool layer. Create functions for html tags.
**
** new it_html;
-** echo h1('hello.php') . div('contents', 'Hello world!');
+** echo html(head('title' => 'hello'), body(h1('hello'), p('Hello world!')));
**/
class it_html
{
- # Default configuration of html class
- var $_defaultconfig = array
- (
- 'name' => 'it_html', # Name of global variable to use
- 'oldhtml' => false,
- 'prettyprint' => false,
- 'tags' => 'a,br,form,h1,h2,h3,h4,input,li,meta,table,td,th,tr,ul',
- 'moretags' => '',
- 'nonewlinetags' => 'a,img,span',
- 'preprocess_attr' => array(),
- 'charset' => "iso-8859-1",
- 'ie_png_fix' => false, # To enable, supply URL of a transparent gif (like /images/0.gif)
- 'show_content_type' => true,
- 'show_favicon' => true,
- 'show_boot_dom' => true,
- 'staticallycallable' => "q,u,select", # Those methods are statically callable (have same arguments as global stubs) but are a bit slower
- 'notexported' => "sanitize", # Those methods are not exported
- );
- var $tags_seen = array('body' => true); # body always counts as seen
- var $_hasnonewline = array();
/**
* Create a HTML object and global functions for all methods (exlcluding
* methods starting with '_') in this class plus the default tags (see below).
*
- * @param $config Configuration settings:
- * name => Name of global variable $this is assigned to (string)
- * prettyprint => Should output be indented? (bool)
- * oldhtml => Should output be in old-style html? (bool)
- * tags => Comma-separated list of default tag-functions to generate (string)
- * moretags => Comma-separated list of tag-functions to generate additionally to 'tags' (string)
- * nonewlinetags => Comma-separated list of tags that do not like newlines before/after them
- * use_it_state => If true, generate code needed by state.js (aka 'history iframe')
+ * @param $p Configuration settings. Can be set/overridden in constructor, html() or head().
+ * See source code for a list of supported values
*/
-function it_html($config = array())
+function it_html($p = array())
{
- # Create current setting vars
- foreach ($config + $this->_defaultconfig as $key => $value)
- {
- $var = "_$key";
- $this->$var = $value;
- }
+ # Default configuration of html class
+ $this->p = $p + array(
+ 'charset' => 'iso-8859-1',
+ 'doctype' => null, # Custom doctype (will usually be calculated from htmltype)
+ 'htmltype' => 'html', # '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)
+ 'nonewlinetags' => 'a,b,em,img,input,span', # tags that do not like newlines after them
+ 'notexported' => '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
+ 'use_it_state' => false, # If true, generate code needed by state.js (aka 'history iframe')
+ 'tags' => 'a,b,br,button,div,em,form,h1,h2,h3,h4,h5,h6,hr,input,label,li,meta,p,span,table,td,textarea,th,tr,ul',
+ );
- if (isset($this->_oldhtml) && !$this->_htmltype)
- $this->_htmltype = $this->_oldhtml ? "html" : "xhtml";
- $this->_oldhtml = $this->_htmltype == "html";
- $this->_hasnonewline = array_flip(explode(',', "dummy," . $this->_nonewlinetags)); # dummy keeps values >0
- $notexported = array_flip(explode(',', "dummy," . $this->_notexported)); # dummy keeps values >0
+ # We know these doctypes. If you need something else, supply 'doctype' in p
+ $this->doctypes = array(
+ 'html' => '',
+ 'xhtml' => '',
+ 'xhtml-mobile' => ''
+ );
+
+ $this->p['oldhtml'] = $this->p['htmltype'] == "html";
+
+ $this->hasnonewline = array_flip(explode(',', "dummy," . $this->p['nonewlinetags'])); # dummy keeps values > 0
+ $notexported = array_flip(explode(',', "dummy," . $this->p['notexported'])); # dummy keeps values > 0
# Create global functions for _tags
- foreach (array_merge(explode(',', $this->_tags), explode(',', $this->_moretags)) as $func)
+ 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 \$GLOBALS['$this->_name']->_tag('$func', \$args);}";
+ $code[$func] = "function $func() { \$args = func_get_args(); return \$GLOBALS['{$this->p['name']}']->_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->_name']->$func(\$args); }";
+ $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->_staticallycallable) as $func)
+ 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->_name'], '$func'), \$args); }";
+ $code[$func] = "function $func() { \$args = func_get_args(); return call_user_func_array(array(&\$GLOBALS['{$this->p['name']}'], '$func'), \$args); }";
}
- eval(join("", (array)$code));
+ eval(join('', (array)$code));
# Since name is given as param, it is our duty to store it, not our caller's.
- $GLOBALS[$this->_name] =& $this;
+ $GLOBALS[$this->p['name']] =& $this;
}
/**
- * Return a containing optional data.
- * @param $name tag name ('h1', 'div' etc.)
- * @param ... any number optional data or array of key => value arguments
- * @return string containing XML/HTML tag
+ * 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 for $p (see constructor for list)
*/
-function tag($args)
+function html($args)
{
- $name = array_shift($args);
+ list($data, $p) = $this->_parse_args($args);
+ $p += $this->p;
- return $this->_tag($name, $args);
+ return ($p['doctype'] ? $p['doctype'] : $this->doctypes[$p['htmltype']]) . "\n" .
+ '\n" . $data . ($p['omit_endhtml'] ? '' : "\n");
}
+
/**
- * Internal: Create html tag from name and args array
+ * Return HTML header on first call or empty string on subsequent calls
+ *
+ * @param any number of text args or array of key => value:
+ * 'content-type' optional content type (default: "text/html; charset=iso-8859-1")
+ * 'description' optional data for tag
+ * 'keywords' optional data for tag
+ * 'lang' optional language (defaults to 'de')
+ * 'stylesheets' optional array mediatype => url of styleshests
+ * 'title' optional HTML title tag (default: empty title)
*/
-function _tag($name, $args)
+function head($args = array())
{
- $data = null;
- $attr = array();
+ if (!$this->head_sent++)
+ {
+ list($data, $p) = $this->_parse_args($args);
- foreach($args as $arg)
+ $p += $this->p;
+ $this->p = $p += array(
+ 'content-type' => "text/html; charset={$p['charset']}",
+ 'title' => tag('title', Q($p['title']))
+ );
+
+ $header = $p['show_content_type'] ? meta(array('http-equiv' => "Content-Type", 'content' => $p['content-type'])) : "";
+
+ foreach(array('description', 'keywords') as $name)
+ if (!empty($p[$name]))
+ $header .= meta(array('name' => $name, 'content' => $p[$name]));
+
+ # Add favicon if file exists
+ if ($p['show_favicon'] && @file_exists($_SERVER['DOCUMENT_ROOT'] . '/favicon.ico'))
+ $header .= tag('link', array('rel' => "shortcut icon", 'href' => "/favicon.ico"));
+
+ foreach((array)$p['stylesheets'] as $type => $url)
+ $header .= tag('link', array('rel' => "stylesheet", 'type' => "text/css", 'href' => $url) + (is_int($type) ? array() : array('media' => $type)));
+
+ if (!empty($p['cssinline']))
+ $header .= tag('style', array('type' => "text/css", "\n" . preg_replace(array('/\s*\/\*[^\*]+\*\//Um', '/\s*\{\s*/', '/;\s+/'), array('', '{', ';'), $p['cssinline'])));
+
+ 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)
+ $header .= $this->js(array($js));
+
+ return tag('head', $header, $data);
+ }
+}
+
+
+/**
+ * Return HTML head (if not already sent) and body with it_state and it_boot magic code
+ */
+function body($args)
+{
+ return $this->head() .
+ ($this->p['use_it_state'] ? tag('iframe', array('id' => "it_state", 'src' => "/itjs/state.html", 'width' => 1, 'height' => 1, 'frameborder' => 0)) : '') .
+ $this->_tag('body', $args) .
+ ($this->p['show_boot_dom'] ? div(array('id' => "it_boot_dom", 'style' => "visibility:hidden")) : '');
+}
+
+
+/**
+ * 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();
+ foreach ($args as $arg)
{
if (is_array($arg))
{
@@ -124,21 +204,30 @@ function _tag($name, $args)
{
if (is_int($key))
$data .= $value;
- else if ($this->_preprocess_attr[$key])
- $attr[$key] = call_user_func(($this->_preprocess_attr[$key]), $value, $name);
else
- $attr[$key] = $value;
+ $p[$key] = $value;
}
}
else
$data .= $arg;
}
- $newline = $this->_hasnonewline[$name] ? "" : "\n";
+ return array($data, $p);
+}
+
+
+/**
+ * INTERNAL: Create html tag from name and args array
+ */
+function _tag($name, $args)
+{
+ list($data, $attr) = $this->_parse_args($args);
+
+ $newline = $this->hasnonewline[$name] ? "" : "\n";
# Ultra XML PrettyPrinter 3000 [\] by SCA
- if ($this->_prettyprint && $newline && (substr($data, -1, 1) == "\n") && (strpos($data, '