<?php
/* vim: set expandtab tabstop=4 shiftwidth=4: */
// +----------------------------------------------------------------------+
// | PHP Version 4 |
// +----------------------------------------------------------------------+
// | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group |
// +----------------------------------------------------------------------+
// | This source file is subject to version 2.0 of the PHP license, |
// | that is bundled with this package in the file LICENSE, and is |
// | available at through the world-wide-web at |
// | http://www.php.net/license/2_02.txt. |
// | If you did not receive a copy of the PHP license and are unable to |
// | obtain it through the world-wide-web, please send a note to |
// | license@php.net so we can mail you a copy immediately. |
// +----------------------------------------------------------------------+
// | Author: Alan Knowles <alan@akbkhome.com> |
// | Based on HTML_Common by: Adam Daniel <adaniel1@eesus.jnj.com> |
// +----------------------------------------------------------------------+
//
// $Id: Element.php 299896 2010-05-28 06:03:39Z alan_k $
/**
* Lightweight HTML Element builder and render
*
* This differs from HTML_Common in the following ways:
*
* $element->attributes is Public
* $element->override if set to anything other than false, renders the value rather than
* the defined element
*
* $element->children is a recursvable child array which is rendered by toHTML
* $element->toHtml() is implemented
* $element->toHtmlNoClose() renders only the first tag and children (designed for <form
* No support for tab offsets, comments ...
*
* Full support for Select, and common Form elements using
* setValue()
* setOptions()
*
* overlay support with SetFrom - base + inherited..
*
* attributes array values:
* key="value" // standard key="value" in output
* key = true // outputs just key.
*
* children can be
* another HTML_Element
* or string (raw text)
*
*
* @author Adam Daniel <adaniel1@eesus.jnj.com>
* @version 1.6
* @since PHP 4.0.3pl1
* @abstract
*/
class HTML_Template_Flexy_Element {
/**
* Tag that this Element represents.
* @var array
* @access public
*/
var $tag = '';
/**
* Associative array of table attributes
* Note Special values:
* true == only display the key
* false == remove
*
* @var array
* @access public
*/
var $attributes = array();
/**
* Sequence array of children
* children that are strings are assumed to be text
* @var array
* @access public
*/
var $children = array();
/**
* override the tag.
* if this is set to anything other than false, it will be output
* rather than the tags+children
* @var array
* @access public
*/
var $override = false;
/**
* prefix the tag.
* this is output by toHtml as a prefix to the tag (can be used for require tags)
* @var array
* @access private
*/
var $prefix = '';
/**
* suffix the tag.
* this is output by toHtml as a suffix to the tag (can be used for error messages)
* @var array
* @access private
*/
var $suffix = '';
/**
* a value for delayed merging into live objects
* if you set this on an element, it is merged by setValue, at merge time.
* @var array
* @access public
*/
var $value = null;
/**
* If an input element has a label element associated to it
* *and* the 'useElementLabels' option is true, then you can
* optionally set the text of this label. This permits
* to set custom strings for doing translations.
* @var string | null
* @access public
*/
var $label = null;
/**
* Class constructor
* @param mixed $attributes Associative array of table tag attributes
* or HTML attributes name="value" pairs
* @access public
*/
function HTML_Template_Flexy_Element($tag='', $attributes=null)
{
$this->tag = strtolower($tag);
if (false !== strpos($tag, ':')) {
$bits = explode(':',$this->tag);
$this->tag = $bits[0] . ':'.strtolower($bits[1]);
}
$this->setAttributes($attributes);
} // end constructor
/**
* Returns an HTML formatted attribute string
* @param array $attributes
* @return string
* @access private
*/
function attributesToHTML()
{
$strAttr = '';
$xhtmlclose = '';
$activeEngine = HTML_Template_Flexy::$activeEngine;
$charset = empty($activeEngine->options['charset']) ?
'ISO-8859-1' :
$activeEngine->options['charset'];
foreach ($this->attributes as $key => $value) {
// you shouldn't do this, but It shouldnt barf when you do..
if (is_array($value) || is_object($value)) {
continue;
}
if ($key == 'flexy:xhtml') {
continue;
}
if ($value === false) {
continue;
}
if ($value === true) {
// this is not xhtml compatible..
if ($key == '/') {
$xhtmlclose = ' /';
continue;
}
if (isset($this->attributes['flexy:xhtml'])) {
$strAttr .= " {$key}=\"{$key}\"";
} else {
$strAttr .= ' ' . $key;
}
continue;
}
// dont replace & with &
if ($this->tag == 'textbox') { // XUL linefeed fix.
$value = str_replace("\n", ' ', htmlspecialchars($value,ENT_COMPAT,$charset));
} else {
$value = str_replace('&nbsp;',' ',htmlspecialchars($value,ENT_COMPAT,$charset));
}
// translation..
if (($this->tag == 'input') &&
$this->attributes['type'] == 'submit' &&
$key == 'value') {
$value = htmlspecialchars($activeEngine->translateString($value));
}
if (in_array($this->tag ,array('input','textarea')) && $key == 'placeholder') {
$value = htmlspecialchars($activeEngine->translateString($value));
}
$strAttr .= ' ' . $key . '="' . $value . '"';
}
$strAttr .= $xhtmlclose;
return $strAttr;
} // end func _getAttrString
/**
* Static Method to get key/value array from attributes.
* Returns a valid atrributes array from either a string or array
* @param mixed $attributes Either a typical HTML attribute string or an associative array
* @access private
*/
function parseAttributes($attributes)
{
if (is_array($attributes)) {
$ret = array();
foreach ($attributes as $key => $value) {
if (is_int($key)) {
$ret[strtolower($value)] = true;
} else {
$ret[strtolower($key)] = $value;
}
}
return $ret;
} elseif (is_string($attributes)) {
$preg = "/(([A-Za-z_:]|[^\\x00-\\x7F])([A-Za-z0-9_:.-]|[^\\x00-\\x7F])*)" .
"([ \\n\\t\\r]+)?(=([ \\n\\t\\r]+)?(\"[^\"]*\"|'[^']*'|[^ \\n\\t\\r]*))?/";
if (preg_match_all($preg, $attributes, $regs)) {
for ($counter=0; $counter<count($regs[1]); $counter++) {
$name = $regs[1][$counter];
$check = $regs[0][$counter];
$value = $regs[7][$counter];
if (trim($name) == trim($check)) {
$arrAttr[strtolower(trim($name))] = strtolower(trim($name));
} else {
if (substr($value, 0, 1) == "\"" || substr($value, 0, 1) == "'") {
$value = substr($value, 1, -1);
}
$arrAttr[strtolower(trim($name))] = trim($value);
}
}
return $arrAttr;
}
}
} // end func _parseAttributes
/**
* Utility function to set values from common tag types.
* @param HTML_Element $from override settings from another element.
* @access public
*/
function setValue($value) {
// store the value in all situations
$this->value = $value;
$tag = strtolower($this->tag);
if (strpos($tag,':') !== false) {
$bits = explode(':',$tag);
$tag = $bits[1];
}
switch ($tag) {
case 'input':
switch (isset($this->attributes['type']) ? strtolower($this->attributes['type']) : '') {
case 'checkbox':
if (isset($this->attributes['checked'])) {
unset($this->attributes['checked']);
}
// if value is nto set, it doesnt make any difference what you set ?
if (!isset($this->attributes['value'])) {
return;
}
//print_r($this); echo "SET TO "; serialize($value);
if (isset($this->attributes['name']) && (substr($this->attributes['name'],-2) == '[]')) {
if (is_array($value) &&
in_array((string) $this->attributes['value'],$value)
) {
$this->attributes['checked'] = true;
}
// removed - see bug 15279 - not sure if there is any knock on effects from this.
///return;
}
if ($this->attributes['value'] == $value) {
$this->attributes['checked'] = true;
}
return;
case 'radio':
if (isset($this->attributes['checked'])) {
unset($this->attributes['checked']);
}
// if we dont have values associated yet, store it..
if (!isset($this->attributes['value'])) {
$this->value = $value;
return;
}
if ($this->attributes['value'] == $value) {
$this->attributes['checked'] = true;
}
return;
default:
// no other input accepts array as a value.
if (is_array($value)) {
return;
}
$this->attributes['value'] = $value;
return;
}
case 'select':
if (!is_array($value)) {
$value = array($value);
}
// its setting the default value..
foreach($this->children as $i=>$child) {
if (is_string($child)) {
continue;
}
if ($child->tag == 'optgroup') {
foreach($this->children[$i]->children as $ii=>$child) {
// does the value exist and match..
if (isset($child->attributes['value'])
&& in_array((string) $child->attributes['value'], $value))
{
$this->children[$i]->children[$ii]->attributes['selected'] =
isset($this->attributes['flexy:xhtml']) ? 'selected' : true;
continue;
}
if (isset($child->attributes['value']) &&
isset($this->children[$i]->children[$ii]->attributes['selected']))
{
unset($this->children[$i]->children[$ii]->attributes['selected']);
continue;
}
// value doesnt exst..
if (isset($this->children[$i]->children[$ii]->attributes['selected'])) {
unset($this->children[$i]->children[$ii]->attributes['selected']);
continue;
}
}
continue;
}
// standard option value...
//echo "testing {$child->attributes['value']} against ". print_r($value,true)."\n";
// does the value exist and match..
if (isset($child->attributes['value'])
&& in_array((string) $child->attributes['value'], $value))
{
$this->children[$i]->attributes['selected'] =
isset($this->attributes['flexy:xhtml']) ? 'selected' : true;;
continue;
}
// no value attribute try and use the contents.
if (!isset($child->attributes['value'])
&& is_string($child->children[0])
&& in_array((string) $child->children[0], $value))
{
$this->children[$i]->attributes['selected'] =
isset($this->attributes['flexy:xhtml']) ? 'selected' : true;
continue;
}
if (isset($child->attributes['value']) &&
isset($this->children[$i]->attributes['selected']))
{
//echo "clearing selected\n";
unset($this->children[$i]->attributes['selected']);
continue;
}
// value doesnt exst..
if (isset($this->children[$i]->attributes['selected'])) {
//echo "clearing selected\n";
unset($this->children[$i]->attributes['selected']);
continue;
}
}
return;
case 'textarea':
case 'label':
$activeEngine = HTML_Template_Flexy::$activeEngine;
$charset = empty($activeEngine->options['charset']) ?
'ISO-8859-1' :
$activeEngine->options['charset'];
$this->children = array(htmlspecialchars($value,ENT_COMPAT,$charset));
return;
case '': // dummy objects.
$this->value = $value;
return;
// XUL elements
case 'menulist':
case 'textbox':
case 'checkbox':
require_once 'HTML/Template/Flexy/Element/Xul.php';
HTML_Template_Flexy_Element_Xul::setValue($this,$value);
return ;
default:
if (is_array($value)) {
return;
}
$this->value = $value;
}
}
/**
* Utility function equivilant to HTML_Select - loadArray **
* but using
* key=>value maps
* <option value="key">Value</option>
* Key=key (eg. both the same) maps to
* <option>key</option>
* and label = array(key=>value) maps to
* <optgroup label="label"> <option value="key">value</option></optgroup>
*
* $element->setOptions(array('a'=>'xxx','b'=>'yyy'));
* or
* $element->setOptions(array('a','b','c','d'),true);
*
*
*.
* @param HTML_Element $from override settings from another element.
* @param HTML_Element $noValue ignore the key part of the array
* @access public
*/
function setOptions($array,$noValue=false)
{
if (!is_array($array)) {
$this->children = array();
return;
}
$activeEngine = HTML_Template_Flexy::$activeEngine;
$charset = empty($activeEngine->options['charset']) ?
'ISO-8859-1' :
$activeEngine->options['charset'];
$tag = strtolower($this->tag);
$namespace = '';
if (false !== strpos($this->tag, ':')) {
$bits = explode(':',$this->tag);
$namespace = $bits[0] . ':';
$tag = strtolower($bits[1]);
}
// if we have specified a xultag!!?
if (strlen($tag) && ($tag != 'select')) {
require_once 'HTML/Template/Flexy/Element/Xul.php';
return HTML_Template_Flexy_Element_Xul::setOptions($this,$array,$noValue);
}
foreach($array as $k=>$v) {
if (is_array($v)) { // optgroup
$child = new HTML_Template_Flexy_Element($namespace . 'optgroup',array('label'=>$k));
foreach($v as $kk=>$vv) {
$atts=array();
if (($kk !== $vv) && !$noValue) {
$atts = array('value'=>$kk);
} else {
$atts = array('value'=>$vv);
}
$add = new HTML_Template_Flexy_Element($namespace . 'option',$atts);
$add->children = array(htmlspecialchars($vv,ENT_COMPAT,$charset));
$child->children[] = $add;
}
$this->children[] = $child;
continue;
}
$atts=array();
if (($k !== $v) && !$noValue) {
$atts = array('value'=>$k);
} else {
$atts = array('value'=>$v);
}
$add = new HTML_Template_Flexy_Element($namespace . 'option',$atts);
$add->children = array(htmlspecialchars($v,ENT_COMPAT,$charset));
$this->children[] = $add;
}
}
/**
* Returns THIS select element's options as an associative array
* Validates that $this element is "select"
* @return array $options
* @access public
*/
function getOptions()
{
$tag = strtolower($this->tag);
$namespace = '';
if (false !== strpos($this->tag, ':')) {
$bits = explode(':',$this->tag);
$namespace = $bits[0] . ':';
$tag = strtolower($bits[1]);
}
// this is not a select element
if (strlen($tag) && ($tag != 'select')) {
return false;
}
// creates an associative array that can be used by setOptions()
// null does work for no value ( a "Please Choose" option, for example)
foreach ($this->children as $child) {
if (is_object($child)) {
$child->attributes['value'] = isset($child->attributes['value']) ? $child->attributes['value'] : '';
$children[$child->attributes['value']] = $child->children[0];
}
}
return $children;
}
/**
* Removes all of this element's options
* Validates that $this element is "select"
* @return bool result
* @access public
*/
function clearOptions($children = array())
{
$tag = strtolower($this->tag);
$namespace = '';
if (false !== strpos($this->tag, ':')) {
$bits = explode(':',$this->tag);
$namespace = $bits[0] . ':';
$tag = strtolower($bits[1]);
}
// this is not a select element
if (strlen($tag) && ($tag != 'select')) {
return false;
}
// clear this select's options
$this->children = array(null);
$this->values = array(null);
// If called with an array of new options go ahead and set them
$this->setOptions($children);
return true;
}
/**
* Sets the HTML attributes
* @param mixed $attributes Either a typical HTML attribute string or an associative array
* @access public
*/
function setAttributes($attributes)
{
$attrs= $this->parseAttributes($attributes);
if (!is_array($attrs)) {
return false;
}
foreach ($attrs as $key => $value) {
$this->attributes[$key] = $value;
}
} // end func updateAttributes
/**
* Removes an attributes
*
* @param string $attr Attribute name
* @since 1.4
* @access public
* @return void
* @throws
*/
function removeAttributes($attrs)
{
if (is_string($attrs)) {
$attrs = array($attrs);
}
foreach ($attrs as $attr) {
if (isset($this->attributes[strtolower($attr)])) {
$this->attributes[strtolower($attr)] = false;
}
}
} //end func removeAttribute
/**
* Output HTML and children
*
* @access public
* @param object $overlay = merge data from object.
* @return string
* @abstract
*/
function toHtml($overlay=false)
{
//echo "BEFORE<PRE>";print_R($this);
$ret = $this;
if ($overlay !== false) {
$ret = HTML_Template_Flexy::mergeElement($this,$overlay);
}
if ($ret->override !== false) {
return $ret->override;
}
$prefix = $ret->prefix;
if (is_object($prefix)) {
$prefix = $prefix->toHtml();
}
$suffix = $ret->suffix;
if (is_object($suffix)) {
$suffix = $suffix->toHtml();
}
//echo "AFTER<PRE>";print_R($ret);
$tag = $this->tag;
if (strpos($tag,':') !== false) {
$bits = explode(':',$tag);
$tag = $bits[1];
}
// tags that never should have closers
$close = "</{$ret->tag}>";
if (in_array(strtoupper($tag),array("INPUT","IMG", "LINK", "META", "HR", "BR"))) {
$close = '';
if (isset($ret->attributes['flexy:xhtml'])) {
$this->attributes['/'] = true;
}
}
if (isset($this->attributes['/'])) {
$close = '';
}
$close .= $suffix ;
return "{$prefix}<{$ret->tag}" . $ret->attributesToHTML() . '>' . $ret->childrenToHTML() . $close;
} // end func toHtml
/**
* Output Open Tag and any children and not Child tag (designed for use with <form + hidden elements>
*
* @access public
* @param object $overlay = merge data from object.
* @return string
* @abstract
*/
function toHtmlnoClose($overlay=false)
{
$ret = $this;
if ($ret->override !== false) {
return $ret->override;
}
if ($overlay !== false) {
$ret = HTML_Template_Flexy::mergeElement($this,$overlay);
}
return "<{$ret->tag}".$ret->attributesToHTML() . '>' . $ret->childrenToHTML();
} // end func toHtml
/**
* Output HTML and children
*
* @access public
* @return string
* @abstract
*/
function childrenToHtml()
{
$ret = '';
foreach($this->children as $child) {
if (!is_object($child)) {
$ret .= $child;
continue;
}
$ret .= $child->toHtml();
}
return $ret;
} // end func toHtml
/**
* merge this element with another
* originally was in main engine
*
* @param HTML_Template_Flexy_Element $new (with data to replace/merge)
* @return HTML_Template_Flexy_Element the combined/merged data.
* @static
* @access public
*/
function merge($new)
{
// Clone objects is possible to avoid creating references between elements
$original = clone($this);
// no new - return original
if (!$new) {
return $original;
}
$new = clone($new);
// If the properties of $original differ from those of $new and
// they are set on $new, set them to $new's. Otherwise leave them
// as they are.
if ($new->tag && ($new->tag != $original->tag)) {
$original->tag = $new->tag;
}
if ($new->override !== false) {
$original->override = $new->override;
}
if (count($new->children)) {
//echo "<PRE> COPY CHILDREN"; print_r($from->children);
$original->children = $new->children;
}
if (is_array($new->attributes)) {
foreach ($new->attributes as $key => $value) {
$original->attributes[$key] = $value;
}
}
// originals never have prefixes or suffixes..
$original->prefix = $new->prefix;
$original->suffix = $new->suffix;
if ($new->value !== null) {
$original->setValue($new->value);
}
if ($new->label !== null) {
$original->label = $new->label;
}
return $original;
}
} // end class HTML_Template_Flexy_Element
Copyright 2K16 - 2K18 Indonesian Hacker Rulez