Fixed example, optional global function, added Specification

This commit is contained in:
Matt Karl 2014-10-31 12:34:20 -04:00
parent 497dc7140a
commit 946984b6e4
10 changed files with 610 additions and 251 deletions

View File

@ -1,12 +1,12 @@
{
"name": "canteen/html5",
"description" : "Create dynamic, valid HTML5 markup with a simple an intuitive PHP API",
"version" : "1.0.1",
"version" : "1.1.0",
"type": "library",
"keywords": ["html5", "markup", "document", "html", "tags"],
"license": "MIT",
"homepage" : "http://github.com/Canteen/CanteenHTML5",
"time": "2013-10-12",
"time": "2014-10-31",
"authors": [
{
"name": "Matt Karl",
@ -16,8 +16,7 @@
}
],
"autoload": {
"psr-4": {"Canteen\\HTML5\\": "src/"},
"files": ["src/html.php"]
"psr-4": {"Canteen\\HTML5\\": "src/"}
},
"require": {
"php": ">=5.3.0"

View File

@ -1,6 +1,10 @@
<?php
include '../lib/html.php';
include '../src/HTML5.php';
use Canteen\HTML5\HTML5;
HTML5::autoload(); // Autoload the classes, helpful if using outside composer
HTML5::useGlobal(); // if you want to use the global html() method instead of namespaced one
use Canteen\HTML5\Document;
use Canteen\HTML5\SimpleList;

View File

@ -58,7 +58,12 @@ namespace Canteen\HTML5
*/
public function __construct($title='', $charset='utf-8', $beautify=false)
{
parent::__construct('html', null, null, 'manifest');
parent::__construct('html', null, null,
array_merge(
array('manifest'),
Specification::$ATTRIBUTES
)
);
$this->docType = html('doctype');
$this->head = html('head');

165
src/HTML5.php Normal file
View File

@ -0,0 +1,165 @@
<?php
/**
* @module Canteen\HTML5
*/
namespace Canteen\HTML5
{
/**
* Main class of the library
* @class HTML5
*/
class HTML5
{
/**
* Turn on autoloading for the library
* @method autoload
* @static
*/
static public function autoload()
{
spl_autoload_register(function($name)
{
// Ignore class names not in the HTML5 namespace
if (!preg_match('/^Canteen\\\HTML5\\\/', $name)) return;
// Remove the HTML5 namespace
$name = preg_replace('/^Canteen\\\HTML5\\\/', '', $name);
// Convert the rest to directories
$name = str_replace("\\", '/', $name);
// Include the class relative to here
include __DIR__.'/'.$name.'.php';
});
}
/**
* Use the global `html()` method
* @method {Boolean} useGlobal
*/
static public function useGlobal()
{
include __DIR__.'/html.php';
}
}
/**
* This is the global function is the main entry for interacting with the HTML5 for PHP library.
* using `html()` global function you can create HTML5 quickly and easily. For more
* examples and instruction on how to use this library, please refer to the the
* <a href="https://github.com/Canteen/CanteenHTML5">GitHub project</a>.
* To install the library simply include `html.php`, this takes care of any autoloading that's needed
* for the rest of the library.
*
* echo html('img src=home.jpg');
* echo html('img', 'src=home.jpg');
* echo html('a', array('href'=>'about.html'));
*
*
*
* @method html
* @param {String} tag The name of the tag as a string for example 'tr', 'table', can be followed
* by CSS selector, e.g. 'a#backButton' or 'a.button'
* @param {Dictionary|Node|String|Array} [childrenOrAttributes=null] If the tag is a NodeContainer, this can be an array
* of attributes, another html node or some text. If the tag is a single node, this can
* be an array or chain of attributes
* @param {Dictionary|String} [attributes=null] The attributes list for container tags (e.g., 'class:selected')
* @return {Node} Return the html node
*/
function html($tag, $childrenOrAttributes=null, $attributes=null)
{
// Get the tag ID from the tag string
// for instance 'a.button rel=external', a.button is the tagId, the rest are the attributes
$endPos = strpos(trim($tag), ' ');
// The tag attributes
$tagAttributes = array();
// If the tag also has some attributes
if ($endPos !== false)
{
$tagOriginal = $tag;
$tag = substr($tag, 0, $endPos);
$tagAttributes = Attribute::shorthand(substr($tagOriginal, $endPos + 1));
}
// Match the tag name without the CSS selectors
preg_match('/^([a-z1-6]{1,10})(.*)/', $tag, $tagParts);
// Valid class ane id names must begin with a -, _, or a-z letter
preg_match_all('/(\.|\#)\-?[\_a-zA-Z]+[\_a-zA-Z0-9\-]*/', $tagParts[2], $selectors);
$tag = strtolower($tagParts[1]); // the name of the tag
$selfClosing = false;
// Comment tags are special
if ($tag == 'comment')
{
return new Comment($childrenOrAttributes);
}
// Document type declaration
else if ($tag == 'doctype')
{
return '<!DOCTYPE html>';
}
// Any normal text
else if ($tag == 'text')
{
return new Text($childrenOrAttributes);
}
// Check for task specification
else if (isset(Specification::$TAGS[$tag]))
{
// Check to see if this is a self closing tag
$selfClosing = in_array($tag, Specification::$SELF_CLOSING);
}
else
{
throw new HTML5Error(HTML5Error::INVALID_TAG, $tag);
}
// Create the attributes collection, either string or array
$attributes = $selfClosing ? $childrenOrAttributes : $attributes;
// If there are attributes and they are in a string format
// convert to an attributes array
if ($attributes !== null && is_string($attributes))
{
$attributes = Attribute::shorthand($attributes);
}
// Combine the attributes and the tags
if (is_array($attributes))
{
$attributes = array_merge($tagAttributes, $attributes);
}
// Or just add any tag attributes
else if (count($tagAttributes))
{
$attributes = $tagAttributes;
}
// Create the node or container
$node = $selfClosing ?
new Node($tag, $attributes) :
new NodeContainer($tag, $childrenOrAttributes, $attributes);
// Take the selectors convert them into id or class
foreach($selectors[0] as $selector)
{
switch($selector[0])
{
case '#' :
$node->id = substr($selector, 1);
break;
case '.' :
if ($node->class) $node->class .= ' ';
$node->class .= substr($selector, 1);
break;
}
}
return $node;
}
}

View File

@ -15,7 +15,6 @@ namespace Canteen\HTML5
* @constructor
* @param {String} [tag=null] The name of the tag
* @param {Array|String} [attributes=null] The collection of tag attributes
* @param {String} [validAttrs=null] The list of non-global valid attributes for the tag, comma separated
*/
class Node
{
@ -47,15 +46,7 @@ namespace Canteen\HTML5
*/
protected $_validAttrs;
/**
* The default valid attributes
* @property {String} GLOBAL_ATTRS
* @final
* @static
*/
const GLOBAL_ATTRS = 'accesskey,class,contenteditable,contextmenu,dir,draggable,dropzone,hidden,id,lang,spellcheck,style,tabindex,title,translate';
public function __construct($tag = null, $attributes = null, $validAttrs = null)
public function __construct($tag = null, $attributes = null)
{
if ($this->isEmpty($tag))
{
@ -65,12 +56,16 @@ namespace Canteen\HTML5
$this->_tag = $tag;
$this->_attributes = array();
$validAttrs = is_string($validAttrs) ? explode(',', $validAttrs) : $validAttrs;
$this->_validAttrs = explode(',', self::GLOBAL_ATTRS);
if ($validAttrs !== null)
if (isset(Specification::$TAGS[$tag]))
{
$this->_validAttrs = array_merge($this->_validAttrs, $validAttrs);
$this->_validAttrs = array_merge(
Specification::$TAGS[$tag],
Specification::$ATTRIBUTES
);
}
else
{
$this->_validAttrs = array();
}
if ($attributes !== null)
@ -299,7 +294,6 @@ namespace Canteen\HTML5
{
return $this->setAttribute($name, $value);
}
return parent::__set($name);
}
/**

View File

@ -17,7 +17,6 @@ namespace Canteen\HTML5
* @param {String} [tag=null] The name of the tag element
* @param {Node|Array} [children=null] The collection of children or single child
* @param {String|Dictionary} [attributes=null] The tag attributes
* @param {String} [validAttrs=null] Valid attributes specific to the HTML5 element, comma separated
*/
class NodeContainer extends Node
{
@ -28,13 +27,13 @@ namespace Canteen\HTML5
*/
private $_children;
public function __construct($tag = null, $children = null, $attributes = null, $validAttrs=null)
public function __construct($tag = null, $children = null, $attributes = null)
{
if ($this->isEmpty($tag))
{
throw new HTML5Error(HTML5Error::EMPTY_NODE_TAG);
}
parent::__construct($tag, $attributes, $validAttrs);
parent::__construct($tag, $attributes);
$this->_children = array();

View File

@ -31,8 +31,7 @@ namespace Canteen\HTML5
{
public function __construct($elements=null, $attributes=null, $type='ul')
{
parent::__construct($type, null, $attributes,
$type == 'ol' ? 'reversed,start,type' : null);
parent::__construct($type, null, $attributes);
if ($elements != null)
{

406
src/Specification.php Normal file
View File

@ -0,0 +1,406 @@
<?php
/**
* @module Canteen\HTML5
*/
namespace Canteen\HTML5
{
/**
* The HTML5 Specification
*
* @class Specification
* @constructor
*/
class Specification
{
/**
* The list of all tags and their specific attributes
* @property {array} TAGS
* @final
* @readOnly
* @static
*/
public static $TAGS = array(
'a' => array(
'href',
'hreflang',
'media',
'rel',
'target',
'type'
),
'abbr' => array(),
'address' => array(),
'area' => array(
'alt',
'coords',
'href',
'hreflang',
'media',
'rel',
'shape',
'target',
'type'
),
'article' => array(),
'aside' => array(),
'audio' => array(
'autoplay',
'controls',
'loop',
'muted',
'preload',
'src'
),
'b' => array(),
'base' => array(
'href',
'target'
),
'bdo' => array(),
'blockquote' => array('cite'),
'body' => array(),
'br' => array(),
'button' => array(
'autofocus',
'disabled',
'form',
'formaction',
'formenctype',
'formmethod',
'formnovalidate',
'formtarget',
'name',
'type',
'value'
),
'canvas' => array(
'height',
'width'
),
'caption' => array(),
'cite' => array(),
'code' => array(),
'col' => null,
'colgroup' => array('span'),
'command' => array(
'checked',
'disabled',
'icon',
'label',
'radiogroup',
'type'
),
'datalist' => array(),
'dd' => array(),
'del' => array(
'cite',
'datetime'
),
'dfn' => array(),
'div' => array(),
'dl' => array(),
'dt' => array(),
'em' => array(),
'embed' => array(
'height',
'src',
'type',
'width'
),
'fieldset' => array(
'disabled',
'form_id',
'text'
),
'figcaption' => array(),
'figure' => array(),
'footer' => array(),
'form' => array(
'accept',
'accept-charset',
'action',
'autocomplete',
'enctype',
'method',
'name',
'novalidate',
'target'
),
'h1' => array(),
'h2' => array(),
'h3' => array(),
'h4' => array(),
'h5' => array(),
'h6' => array(),
'head' => array(),
'header' => array(),
'hgroup' => array(),
'hr' => array(),
'html' => array('manifest'),
'img' => array(
'alt',
'crossorigin',
'height',
'src',
'usemap',
'width'
),
'i' => array(),
'input' => array(
'accept',
'alt',
'autocomplete',
'autofocus',
'checked',
'disabled',
'form',
'formaction',
'formenctype',
'formmethod',
'formnovalidate',
'formtarget',
'height',
'list',
'max',
'maxlength',
'min',
'multiple',
'name',
'pattern',
'placeholder',
'readonly',
'required',
'size',
'src',
'step',
'type',
'value',
'width'
),
'keygen' => array(
'autofocus',
'challenge',
'disabled',
'form',
'keytype',
'name'
),
'label' => array(
'for',
'form'
),
'legend' => array(),
'li' => array(),
'link' => array(
'href',
'hreflang',
'media',
'rel',
'sizes',
'type'
),
'map' => array('name'),
'mark' => array(),
'menu' => array(),
'meta' => array(
'charset',
'content',
'http-equiv',
'name'
),
'meter' => array(
'form',
'heigh',
'low',
'max',
'min',
'optimum',
'value'
),
'nav' => array(),
'noscript' => array(),
'object' => array(
'data',
'form',
'height',
'name',
'type',
'usemap',
'width'
),
'ol' => array(
'reversed',
'start',
'type'
),
'optgroup' => array(
'disabled',
'label'
),
'option' => array(
'disabled',
'label',
'selected',
'value'
),
'output' => array(
'for',
'form',
'name'
),
'p' => array(),
'param' => array(
'name',
'value'
),
'pre' => array(),
'progress' => array(
'max',
'value'
),
'q' => array('cite'),
'rp' => array(),
'rt' => array(),
'ruby' => array(),
's' => array(),
'sample' => array(),
'script' => array(
'async',
'charset',
'defer',
'src',
'type'
),
'section' => array(),
'select' => array(
'autofocus',
'disabled',
'form',
'multiple',
'name',
'required',
'size'
),
'small' => array(),
'source' => array('media',
'src',
'type'
),
'span' => array(),
'strong' => array(),
'style' => array('media',
'scoped',
'type'
),
'sub' => array(),
'table' => array('border'),
'tbody' => array(),
'td' => array(
'colspan',
'headers',
'scope'
),
'textarea' => array(
'autofocus',
'cols',
'disabled',
'form',
'maxlength',
'name',
'placeholder',
'readonly',
'required',
'row',
'wrap'
),
'tfoot' => array(),
'th' => array(
'colspan',
'headers',
'rowspan',
'scope'
),
'thead' => array(),
'time' => array('datetime'),
'title' => array(),
'tr' => array(),
'track' => array(
'default',
'kind',
'label',
'src',
'srclang'
),
'u' => array(),
'ul' => array(),
'var' => array(),
'video' => array(
'autoplay',
'controls',
'height',
'loop',
'muted',
'poster',
'preload',
'src',
'width'
),
'wbr' => null
);
/**
* The list of self-closing tags
* @property {array} SELF_CLOSING
* @final
* @readOnly
* @static
*/
public static $SELF_CLOSING = array(
'area',
'base',
'br',
'col',
'command',
'embed',
'hr',
'img',
'input',
'keygen',
'link',
'meta',
'param',
'source',
'track',
'wbr'
);
/**
* Global valid attributes for all HTML5 tags
* See: http://www.w3.org/TR/html5/dom.html#global-attributes
* @property {Array} ATTRIBUTES
* @final
* @static
* @readOnly
*/
public static $ATTRIBUTES = array(
// Event handler context attributes
'onabort', 'onblur', 'oncancel', 'oncanplay', 'oncanplaythrough',
'onchange', 'onclick', 'oncuechange', 'ondblclick', 'ondurationchange',
'onemptied', 'onended', 'onerror', 'onfocus', 'oninput', 'oninvalid',
'onkeydown', 'onkeypress', 'onkeyup', 'onload', 'onloadeddata',
'onloadedmetadata', 'onloadstart', 'onmousedown', 'onmouseenter',
'onmouseleave', 'onmousemove', 'onmouseout', 'onmouseover', 'onmouseup',
'onmousewheel', 'onpause', 'onplay', 'onplaying', 'onprogress',
'onratechange', 'onreset', 'onresize', 'onscroll', 'onseeked',
'onseeking', 'onselect', 'onshow', 'onstalled', 'onsubmit', 'onsuspend',
'ontimeupdate', 'ontoggle', 'onvolumechange', 'onwaiting',
// Allow-able on all tags
'accesskey', 'class', 'contenteditable', 'contextmenu', 'dir', 'draggable',
'dropzone', 'hidden', 'id', 'lang', 'spellcheck', 'style', 'tabindex',
'title', 'translate'
);
}
}

View File

@ -32,7 +32,7 @@ namespace Canteen\HTML5
{
public function __construct($data, $headers=null, $checkbox=null)
{
parent::__construct('table', null, null, 'border');
parent::__construct('table', null, null);
if ($headers != null && is_array($headers))
{

View File

@ -1,48 +1,13 @@
<?php
/**
* @module global
*/
namespace
{
/**
* @module global
*/
/**
* Auto load the assets in this library
*/
spl_autoload_register(function($name)
{
// Ignore class names not in the HTML5 namespace
if (!preg_match('/^HTML5\\\/', $name)) return;
// Remove the HTML5 namespace
$name = preg_replace('/^HTML5\\\/', '', $name);
// Convert the rest to directories
$name = str_replace("\\", '/', $name);
// Include the class relative to here
include __DIR__.'/'.$name.'.php';
});
use Canteen\HTML5\NodeContainer;
use Canteen\HTML5\Node;
use Canteen\HTML5\Comment;
use Canteen\HTML5\HTML5Error;
use Canteen\HTML5\Text;
use Canteen\HTML5\Attribute;
/**
* This is the global function is the main entry for interacting with the HTML5 for PHP library.
* using `html()` global function you can create HTML5 quickly and easily. For more
* examples and instruction on how to use this library, please refer to the the
* <a href="https://github.com/Canteen/CanteenHTML5">GitHub project</a>.
* To install the library simply include `html.php`, this takes care of any autoloading that's needed
* for the rest of the library.
*
* echo html('img src=home.jpg');
* echo html('img', 'src=home.jpg');
* echo html('a', array('href'=>'about.html'));
*
*
*
* The global method which is an alias for Canteen\HTML5\html()
* to use this method globally call Canteen\HTML5\HTML5::useGlobal()
* @class html
* @constructor
* @param {String} tag The name of the tag as a string for example 'tr', 'table', can be followed
@ -55,183 +20,6 @@
*/
function html($tag, $childrenOrAttributes=null, $attributes=null)
{
// Get the tag ID from the tag string
// for instance 'a.button rel=external', a.button is the tagId, the rest are the attributes
$endPos = strpos(trim($tag), ' ');
// The tag attributes
$tagAttributes = array();
// If the tag also has some attributes
if ($endPos !== false)
{
$tagOriginal = $tag;
$tag = substr($tag, 0, $endPos);
$tagAttributes = Attribute::shorthand(substr($tagOriginal, $endPos + 1));
}
// Match the tag name without the CSS selectors
preg_match('/^([a-z1-6]{1,10})(.*)/', $tag, $tagParts);
// Valid class ane id names must begin with a -, _, or a-z letter
preg_match_all('/(\.|\#)\-?[\_a-zA-Z]+[\_a-zA-Z0-9\-]*/', $tagParts[2], $selectors);
$s = false; // if the html is a single tag like <br>
$tag = strtolower($tagParts[1]); // the name of the tag
$a = ''; // Valid extra attributes for tags
switch($tag)
{
case 'a': $a = 'href,hreflang,media,rel,target,type'; break;
case 'abbr': break;
case 'address': break;
case 'area': $s = true; $a = 'alt,coords,href,hreflang,media,rel,shape,target,type'; break;
case 'article': break;
case 'aside': break;
case 'audio': $a = 'autoplay,controls,loop,muted,preload,src'; break;
case 'b': break;
case 'base': $s = true; $a = 'href,target'; break;
case 'bdo': break;
case 'blockquote': $a = 'cite'; break;
case 'body': break;
case 'br': $s = true; break;
case 'button': $a = 'autofocus,disabled,form,formaction,formenctype,formmethod,formnovalidate,formtarget,name,type,value'; break;
case 'canvas': $a = 'height,width'; break;
case 'caption': break;
case 'cite': break;
case 'code': break;
case 'col': $s = true; break;
case 'colgroup': $a = 'span'; break;
case 'command': $s = true; $a = 'checked,disabled,icon,label,radiogroup,type'; break;
case 'comment': return new Comment($childrenOrAttributes);
case 'doctype': return '<!DOCTYPE html>';
case 'datalist': break;
case 'dd': break;
case 'del': $a = 'cite,datetime'; break;
case 'dfn': break;
case 'div': break;
case 'dl': break;
case 'dt': break;
case 'em': break;
case 'embed': $s = true; $a = 'height,src,type,width'; break;
case 'fieldset': $a = 'disabled,form_id,text'; break;
case 'figcaption': break;
case 'figure': break;
case 'footer': break;
case 'form': $a = 'accept,accept-charset,action,autocomplete,enctype,method,name,novalidate,target'; break;
case 'h1': break;
case 'h2': break;
case 'h3': break;
case 'h4': break;
case 'h5': break;
case 'h6': break;
case 'head': break;
case 'header': break;
case 'hgroup': break;
case 'hr': $s = true; break;
case 'html': $a = 'manifest'; break;
case 'img': $s = true; $a = 'alt,crossorigin,height,src,usemap,width'; break;
case 'i': break;
case 'input': $s = true; $a = 'accept,alt,autocomplete,autofocus,checked,disabled,form,formaction,formenctype,formmethod,formnovalidate,formtarget,height,list,max,maxlength,min,multiple,name,pattern,placeholder,readonly,required,size,src,step,type,value,width'; break;
case 'keygen': $s = true; $a = 'autofocus,challenge,disabled,form,keytype,name'; break;
case 'label': $a = 'for,form'; break;
case 'legend': break;
case 'li': break;
case 'link': $s = true; $a = 'href,hreflang,media,rel,sizes,type'; break;
case 'map': $a = 'name'; break;
case 'mark': break;
case 'menu': break;
case 'meta': $s = true; $a = 'charset,content,http-equiv,name'; break;
case 'meter': $a = 'form,heigh,low,max,min,optimum,value'; break;
case 'nav': break;
case 'noscript': break;
case 'object': $a = 'data,form,height,name,type,usemap,width'; break;
case 'ol': $a = 'reversed,start,type'; break;
case 'optgroup': $a = 'disabled,label'; break;
case 'option': $a = 'disabled,label,selected,value'; break;
case 'output': $a = 'for,form,name'; break;
case 'p': break;
case 'param': $s = true; $a = 'name,value'; break;
case 'pre': break;
case 'progress': $a = 'max,value'; break;
case 'q': $a = 'cite'; break;
case 'rp': break;
case 'rt': break;
case 'ruby': break;
case 's': break;
case 'sample': break;
case 'script': $a = 'async,charset,defer,src,type'; break;
case 'section': break;
case 'select': $a = 'autofocus,disabled,form,multiple,name,required,size'; break;
case 'small': break;
case 'source': $s = true; $a = 'media,src,type'; break;
case 'span': break;
case 'strong': break;
case 'style': $a = 'media,scoped,type'; break;
case 'sub': break;
case 'table': $a = 'border'; break;
case 'tbody': break;
case 'td': $a = 'colspan,headers,scope'; break;
case 'text': return new Text($childrenOrAttributes);
case 'textarea': $a = 'autofocus,cols,disabled,form,maxlength,name,placeholder,readonly,required,row,wrap'; break;
case 'tfoot': break;
case 'th': $a = 'colspan,headers,rowspan,scope'; break;
case 'thead': break;
case 'time': $a = 'datetime'; break;
case 'title': break;
case 'tr': break;
case 'track': $s = true; $a = 'default,kind,label,src,srclang'; break;
case 'u': break;
case 'ul': break;
case 'var': break;
case 'video': $a = 'autoplay,controls,height,loop,muted,poster,preload,src,width'; break;
case 'wbr': $s = true; break;
default:
throw new HTML5Error(HTML5Error::INVALID_TAG, $tag);
break;
}
// Create the attributes collection, either string or array
$attributes = $s ? $childrenOrAttributes : $attributes;
// If there are attributes and they are in a string format
// convert to an attributes array
if ($attributes !== null && is_string($attributes))
{
$attributes = Attribute::shorthand($attributes);
}
// Combine the attributes and the tags
if (is_array($attributes))
{
$attributes = array_merge($tagAttributes, $attributes);
}
// Or just add any tag attributes
else if (count($tagAttributes))
{
$attributes = $tagAttributes;
}
// Create the node or container
$node = ($s) ?
new Node($tag, $attributes, $a) :
new NodeContainer($tag, $childrenOrAttributes, $attributes, $a);
// Take the selectors convert them into id or class
foreach($selectors[0] as $selector)
{
switch($selector[0])
{
case '#' :
$node->id = substr($selector, 1);
break;
case '.' :
if ($node->class) $node->class .= ' ';
$node->class .= substr($selector, 1);
break;
}
}
return $node;
return Canteen\HTML5\html($tag, $childrenOrAttributes, $attributes);
}
?>
}