diff --git a/examples/document.php b/examples/document.php index 0fd3834..6e24b35 100644 --- a/examples/document.php +++ b/examples/document.php @@ -1,57 +1,55 @@ beautify = true; - - // Add a link to the page - $link = html('a#google.external rel=external', 'Link', 'class="test something" target=blank rel=test'); - $link->href = 'http://google.com'; - $link->onclick = "return confirm('Navigate away?');"; - $link->appendTo($doc->body); - - // Create an unordered list for an array of items - // the array can be other html elements or text - $list = new SimpleList( - array( - html('b', 'first'), - 'second', - 'third', - array( - 'sub-third', - 'sub-forth' - ) - ) - ); - $list->appendTo($doc->body); - - // Create a sample table with some rows of dummy data - $table = new Table( - array( - array('id'=>1, 'first'=>'James', 'last'=>'Smith'), - array('id'=>2, 'first'=>'Mary', 'last'=>'Denver'), - array('id'=>3, 'first'=>'Charlie', 'last'=>'Rose') - ), - array('ID', 'First Name', 'Last Name') - ); - - // We'll set some of the table properties - $table->style = 'border:1px solid black'; - $table->border = 0; - $table->id = 'people'; - $table->appendTo($doc->body); - - // Output the result formatted nice with indents - echo $doc; + 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 -?> \ No newline at end of file + use Canteen\HTML5\Document; + use Canteen\HTML5\SimpleList; + use Canteen\HTML5\Table; + + // Create a new document + $doc = new Document('Test Document'); + $doc->beautify = true; + + // Add a link to the page + $link = html('a#google.external rel=external', 'Link', 'class="test something" target=blank rel=test'); + $link->href = 'http://google.com'; + $link->onclick = "return confirm('Navigate away?');"; + $link->appendTo($doc->body); + + // Create an unordered list for an array of items + // the array can be other html elements or text + $list = new SimpleList( + array( + html('b', 'first'), + 'second', + 'third', + array( + 'sub-third', + 'sub-forth' + ) + ) + ); + $list->appendTo($doc->body); + + // Create a sample table with some rows of dummy data + $table = new Table( + array( + array('id'=>1, 'first'=>'James', 'last'=>'Smith'), + array('id'=>2, 'first'=>'Mary', 'last'=>'Denver'), + array('id'=>3, 'first'=>'Charlie', 'last'=>'Rose') + ), + array('ID', 'First Name', 'Last Name') + ); + + // We'll set some of the table properties + $table->style = 'border:1px solid black'; + $table->border = 0; + $table->id = 'people'; + $table->appendTo($doc->body); + + // Output the result formatted nice with indents + echo $doc; diff --git a/src/Attribute.php b/src/Attribute.php index b25c29f..585df8c 100644 --- a/src/Attribute.php +++ b/src/Attribute.php @@ -1,170 +1,176 @@ setAttribute('class', 'button') - * ->setAttribute('href', 'about.html'); - * - * @class Attribute - * @constructor - * @param {String} [name=null] The name of the attribute - * @param {String} [value=null] The value of the attribute - */ - class Attribute - { - /** - * The name of the attribute - * @property {String} _name - * @private - */ - private $_name; - - /** - * The value of the attribute - * @property {String} _value - * @private - */ - private $_value; + /** + * An HTML attribute used on the Node, this is used internally. + * Do not initiate this class directly, use the `html()` function + * to create attributes on elements. + * + * echo html('a', 'Link', 'class=button href="about.html"'); + * + * echo html('a', 'Link') + * ->setAttribute('class', 'button') + * ->setAttribute('href', 'about.html'); + * + * @class Attribute + * @constructor + * @param {String} [name=null] The name of the attribute + * @param {String} [value=null] The value of the attribute + */ + class Attribute + { + /** + * The name of the attribute + * @property {String} _name + * @private + */ + private $_name; - public function __construct($name = null, $value = null) - { - $this->name = $name; - $this->value = $value; - } + /** + * The value of the attribute + * @property {String} _value + * @private + */ + private $_value; - /** - * Convert the attribute to an HTML tag attribute string - * @method __toString - * @return {String} String representation of attribute - */ - public function __toString() - { - return " " . $this->_name . "=\"" . $this->_value . "\""; - } + public function __construct($name = null, $value = null) + { + $this->name = $name; + $this->value = $value; + } - /** - * Get the name of this attribute - * @method getName - * @return {String} The attribute's name - */ - public function getName() - { - return $this->_name; - } + /** + * Convert the attribute to an HTML tag attribute string + * @method __toString + * @return {String} String representation of attribute + */ + public function __toString() + { + return " " . $this->_name . "=\"" . $this->_value . "\""; + } - /** - * Set the name of this attribute, cannot be empty - * @method setName - * @param {String} [name=null] The name of the attribute - */ - public function setName($name = null) - { - if (is_null($name) || empty($name)) - { - throw new HTML5Error(HTML5Error::EMPTY_ATTRIBUTE_NAME); - } - $this->_name = $name; - } - - /** - * Get the value of this attribute - * @method getValue - * @protected - * @return {String} The value of attribute - */ - protected function getValue() - { - return $this->_value; - } + /** + * Get the name of this attribute + * @method getName + * @return {String} The attribute's name + */ + public function getName() + { + return $this->_name; + } - /** - * Set the value of this attribute, this cannot be empty - * @method setValue - * @protected - * @param {String} value The value to set - */ - protected function setValue($value) - { - $this->_value = $value; - } - - /** - * Convert a string into an associative array - * @method shorthand - * @static - * @param {String} str The string, delineated by semicolons, and colons for attributes:values - * @return {Dictionary} The collection of attributes - */ - static public function shorthand($str) - { - $res = array(); - - // Match the name=value in the attributes string - preg_match_all('/([a-z]+[a-z\-]*)\=("[^\"]*"|\'[^\']*\'|[^\s\"\']*)/',$str, $arr); - - foreach($arr[1] as $i=>$name) - { - $value = $arr[2][$i]; - - // Remove containing quotes if present - if (preg_match('/^[\'\"][^\n]*[\'\"]$/', $value)) - { - $value = substr($value, 1, -1); - } - $res[$name] = $value; - } - return $res; - } - - /** - * General purpose getter for getting attribute->name and attribute->value - * @public __get - * @param {String} name The name of the property to get - */ - public function __get($name) - { - if (method_exists($this , $method =('get' . ucfirst($name)))) - return $this->$method(); - else - throw new HTML5Error(HTML5Error::INVALID_GETTER, $name); - } + /** + * Set the name of this attribute, cannot be empty + * @method setName + * @param {String} [name=null] The name of the attribute + */ + public function setName($name = null) + { + if (is_null($name) || empty($name)) + { + throw new HTML5Error(HTML5Error::EMPTY_ATTRIBUTE_NAME); + } + $this->_name = $name; + } - /** - * General purpose setter for setting attribute->name and attribute->value - * @public __set - * @param {String} name The name of the attribute - * @param {String} value The value of the attribute - */ - public function __set($name, $value) - { - if (method_exists($this , $method =('set' . ucfirst($name)))) - return $this->$method($value); - else - throw new HTML5Error(HTML5Error::INVALID_SETTER, $name); - } + /** + * Get the value of this attribute + * @method getValue + * @protected + * @return {String} The value of attribute + */ + protected function getValue() + { + return $this->_value; + } - /** - * See if a property exists - * @method __isset - * @param {String} name The name of the property - */ - public function __isset($name) - { - return method_exists($this , 'get' . ucfirst($name)) - || method_exists($this , 'set' . ucfirst($name)); - } - } + /** + * Set the value of this attribute, this cannot be empty + * @method setValue + * @protected + * @param {String} value The value to set + */ + protected function setValue($value) + { + $this->_value = $value; + } + + /** + * Convert a string into an associative array + * @method shorthand + * @static + * @param {String} str The string, delineated by semicolons, and colons for attributes:values + * @return {Dictionary} The collection of attributes + */ + static public function shorthand($str) + { + $res = array(); + + // Match the name=value in the attributes string + preg_match_all('/([a-z]+[a-z\-]*)\=("[^\"]*"|\'[^\']*\'|[^\s\"\']*)/',$str, $arr); + + foreach ($arr[1] as $i=>$name) + { + $value = $arr[2][$i]; + + // Remove containing quotes if present + if (preg_match('/^[\'\"][^\n]*[\'\"]$/', $value)) + { + $value = substr($value, 1, -1); + } + $res[$name] = $value; + } + return $res; + } + + /** + * General purpose getter for getting attribute->name and attribute->value + * @public __get + * @param {String} name The name of the property to get + */ + public function __get($name) + { + if (method_exists($this , $method =('get' . ucfirst($name)))) + { + return $this->$method(); + } + else + { + throw new HTML5Error(HTML5Error::INVALID_GETTER, $name); + } + } + + /** + * General purpose setter for setting attribute->name and attribute->value + * @public __set + * @param {String} name The name of the attribute + * @param {String} value The value of the attribute + */ + public function __set($name, $value) + { + if (method_exists($this , $method =('set' . ucfirst($name)))) + { + return $this->$method($value); + } + else + { + throw new HTML5Error(HTML5Error::INVALID_SETTER, $name); + } + } + + /** + * See if a property exists + * @method __isset + * @param {String} name The name of the property + */ + public function __isset($name) + { + return method_exists($this , 'get' . ucfirst($name)) + || method_exists($this , 'set' . ucfirst($name)); + } + } } - -?> \ No newline at end of file diff --git a/src/Comment.php b/src/Comment.php index 44ffe22..f50beae 100644 --- a/src/Comment.php +++ b/src/Comment.php @@ -1,38 +1,36 @@ _tag.' -->'; - } - } -} +{ + /** + * Special node type representing an HTML5 inline comment. + * Do not initiate this class directly, use the `html('comment')` function: + * + * echo html('comment', 'Hidden HTML comment here'); + * + * @class Comment + * @extends NodeContainer + * @constructor + * @param {String} text the plain text string + */ + class Comment extends NodeContainer + { + public function __construct($text) + { + parent::__construct($text); + } -?> \ No newline at end of file + /** + * Write to HTML + * @method __toString + * @return {String} The string representation of this HTML node + */ + public function __toString() + { + return ''; + } + } +} diff --git a/src/Document.php b/src/Document.php index fe126c0..3138203 100644 --- a/src/Document.php +++ b/src/Document.php @@ -1,117 +1,117 @@ head->addChild(html('script src=main.js')); - * $doc->body->addChild(html('div#frame')); - * echo $doc; - * - * @class Document - * @extends NodeContainer - * @constructor - * @param {String} [title=''] The title of the document - * @param {String} [charset='utf-8'] The character encoding set of this HTML document - * @param {Boolean} [beautify=false] If we should add whitespace to the output to make it look nice markup. - */ - class Document extends NodeContainer - { - /** - * The document type - * @property {NodeContainer} docType - */ - private $docType; +{ + /** + * Create an HTML document. Basic barebones structure. + * Located in the namespace __Canteen\HTML5__. + * + * $doc = new HTML5\Document('Untitled'); + * $doc->head->addChild(html('script src=main.js')); + * $doc->body->addChild(html('div#frame')); + * echo $doc; + * + * @class Document + * @extends NodeContainer + * @constructor + * @param {String} [title=''] The title of the document + * @param {String} [charset='utf-8'] The character encoding set of this HTML document + * @param {Boolean} [beautify=false] If we should add whitespace to the output to make it look nice markup. + */ + class Document extends NodeContainer + { + /** + * The document type + * @property {NodeContainer} docType + */ + private $docType; - /** - * The head node - * @property {NodeContainer} head - */ - public $head; - - /** - * The body node - * @property {NodeContainer} body - */ - public $body; - - /** - * The title node - * @property {NodeContainer} title - */ - public $title; - - /** - * Beautify the output - * @property {Boolean} beautify - */ - public $beautify = false; - - /** - * Constructor for Docs - */ - public function __construct($title='', $charset='utf-8', $beautify=false) - { - parent::__construct('html', null, null, - array_merge( - array('manifest'), - Specification::$ATTRIBUTES - ) - ); - - $this->docType = html('doctype'); - $this->head = html('head'); - $this->body = html('body'); - $this->title = html('title', $title); - - $this->head->addChild(html('meta', 'charset='.$charset)); - $this->head->addChild($this->title); - - $this->addChild($this->head); - $this->addChild($this->body); - } - - /** - * Write to HTML - * @method __toString - * @return {String} The string representation of this HTML node - */ - public function __toString() - { - $result = $this->docType . parent::__toString(); - if ($this->beautify) - $result = self::beautify($result); - return $result; - } - - /** - * Beautifies an HTML string into a human-readable and indented work of art. - * @method beautify - * @static - * @param {String} html The XML-compatible HTML as a string - * @return {String} The formatted string - */ - public static function beautify($html) - { - // Conver the HTML -> SimpleXML -> DOMDocument - $dom = dom_import_simplexml(new \SimpleXMLElement($html))->ownerDocument; - - // Format the DOMDocument - $dom->formatOutput = true; - - // Save the output as XML - $buffer = $dom->saveXML(); - - // Remove the first line which has the XML declaration - return substr($buffer, strpos($buffer, "\n")+1); - } - } + /** + * The head node + * @property {NodeContainer} head + */ + public $head; + + /** + * The body node + * @property {NodeContainer} body + */ + public $body; + + /** + * The title node + * @property {NodeContainer} title + */ + public $title; + + /** + * Beautify the output + * @property {Boolean} beautify + */ + public $beautify = false; + + /** + * Constructor for Docs + */ + public function __construct($title='', $charset='utf-8', $beautify=false) + { + parent::__construct('html', null, null, + array_merge( + array('manifest'), + Specification::$ATTRIBUTES + ) + ); + + $this->docType = html('doctype'); + $this->head = html('head'); + $this->body = html('body'); + $this->title = html('title', $title); + + $this->head->addChild(html('meta', 'charset=' . $charset)); + $this->head->addChild($this->title); + + $this->addChild($this->head); + $this->addChild($this->body); + } + + /** + * Write to HTML + * @method __toString + * @return {String} The string representation of this HTML node + */ + public function __toString() + { + $result = $this->docType . parent::__toString(); + if ($this->beautify) + { + $result = self::beautify($result); + } + return $result; + } + + /** + * Beautifies an HTML string into a human-readable and indented work of art. + * @method beautify + * @static + * @param {String} html The XML-compatible HTML as a string + * @return {String} The formatted string + */ + public static function beautify($html) + { + // Conver the HTML -> SimpleXML -> DOMDocument + $dom = dom_import_simplexml(new \SimpleXMLElement($html))->ownerDocument; + + // Format the DOMDocument + $dom->formatOutput = true; + + // Save the output as XML + $buffer = $dom->saveXML(); + + // Remove the first line which has the XML declaration + return substr($buffer, strpos($buffer, "\n")+1); + } + } } - -?> \ No newline at end of file diff --git a/src/Fragment.php b/src/Fragment.php index dd9f0a7..a702a5f 100644 --- a/src/Fragment.php +++ b/src/Fragment.php @@ -5,39 +5,37 @@ */ namespace Canteen\HTML5 { - /** - * Represents a set of HTML tags without a wrapper. - * Do not initiate this class directly, use the `html()` function: - * - * $div = html('fragment'); - * - * @class Fragment - * @extends NodeContainer - * @constructor - * @param {Node|Array} [children=null] The collection of children or single child - */ - class Fragment extends NodeContainer - { - public function __construct($children = null) - { - parent::__construct('fragment', $children, null); - } + /** + * Represents a set of HTML tags without a wrapper. + * Do not initiate this class directly, use the `html()` function: + * + * $div = html('fragment'); + * + * @class Fragment + * @extends NodeContainer + * @constructor + * @param {Node|Array} [children=null] The collection of children or single child + */ + class Fragment extends NodeContainer + { + public function __construct($children = null) + { + parent::__construct('fragment', $children, null); + } - /** - * Write to HTML - * @method __toString - * @return {String} The string representation of this HTML node - */ - public function __toString() - { - $buffer = ''; - foreach($this->getChildren() as $child) - { - $buffer .= $child->__toString(); - } - return $buffer; - } - } + /** + * Write to HTML + * @method __toString + * @return {String} The string representation of this HTML node + */ + public function __toString() + { + $buffer = ''; + foreach ($this->getChildren() as $child) + { + $buffer .= $child->__toString(); + } + return $buffer; + } + } } - -?> \ No newline at end of file diff --git a/src/HTML5.php b/src/HTML5.php index 090d10b..8fbe21c 100644 --- a/src/HTML5.php +++ b/src/HTML5.php @@ -1,170 +1,175 @@ -GitHub project. - * 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; + // Convert the rest to directories + $name = str_replace("\\", '/', $name); - // Comment tags are special - if ($tag == 'comment') - { - return new Comment($childrenOrAttributes); - } - // Document type declaration - else if ($tag == 'doctype') - { - return ''; - } - // Any normal text - else if ($tag == 'text') - { - return new Text($childrenOrAttributes); - } - // Untagged container - else if ($tag == 'fragment') - { - return new Fragment($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; - } -} \ No newline at end of file + // 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 + * GitHub project. + * 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 ''; + } + // Any normal text + else if ($tag == 'text') + { + return new Text($childrenOrAttributes); + } + // Untagged container + else if ($tag == 'fragment') + { + return new Fragment($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; + } +} diff --git a/src/HTML5Error.php b/src/HTML5Error.php index a9a9cdd..adea14f 100644 --- a/src/HTML5Error.php +++ b/src/HTML5Error.php @@ -1,144 +1,142 @@ getMessage(); - * } - * - * @class HTML5Error - * @extends Exception - * @constructor - * @param {int} code The code of the error - * @param {String} [data=''] Additional data to associate with this error - */ - class HTML5Error extends \Exception - { - /** - * The database connection failed - * @property {int} EMPTY_ATTRIBUTE_NAME - * @static - * @final - */ - const EMPTY_ATTRIBUTE_NAME = 500; - - /** - * The alias for a database is invalid - * @property {int} EMPTY_ATTRIBUTE_VALUE - * @static - * @final - */ - const EMPTY_ATTRIBUTE_VALUE = 501; - - /** - * The database name we're trying to switch to is invalid - * @property {int} INVALID_SETTER - * @static - * @final - */ - const INVALID_SETTER = 502; - - /** - * The mysql where trying to execute was a problem - * @property {int} INVALID_GETTER - * @static - * @final - */ - const INVALID_GETTER = 503; - - /** - * The html tag name is invalid - * @property {int} INVALID_TAG - * @static - * @final - */ - const INVALID_TAG = 504; - - /** - * When trying to create a node, the name is empty - * @property {int} EMPTY_NODE_TAG - * @static - * @final - */ - const EMPTY_NODE_TAG = 505; - - /** - * The parent cannot be empty - * @property {int} EMPTY_PARENT - * @static - * @final - */ - const EMPTY_PARENT = 506; - - /** - * THe addChildAt is out of bounds - * @property {int} OUT_OF_BOUNDS - * @static - * @final - */ - const OUT_OF_BOUNDS = 507; - - /** - * The child node is empty - * @property {int} EMPTY_CHILD - * @static - * @final - */ - const EMPTY_CHILD = 508; - - /** - * The node is not of instance type Node - * @property {int} INVALID_NODE - * @static - * @final - */ - const INVALID_NODE = 509; - - /** - * Look-up for error messages - * @property {Dictionary} messages - * @private - * @static - */ - private static $messages = array( - self::EMPTY_ATTRIBUTE_NAME => 'Attribute names cannot be empty', - self::EMPTY_ATTRIBUTE_VALUE => 'Attribute values cannot be empty', - self::INVALID_SETTER => 'Cannot set the property because name is invalid', - self::INVALID_GETTER => 'Cannot get the property because name is invalid', - self::INVALID_TAG => 'Not a valid HTML5 tag name', - self::EMPTY_NODE_TAG => 'Node tag is empty', - self::EMPTY_PARENT => 'The parent cannot be empty', - self::OUT_OF_BOUNDS => 'The index is out of bounds', - self::EMPTY_CHILD => 'Cannot addChild an empty child node', - self::INVALID_NODE => 'Child node must be a valid tag' - ); - - /** - * The label for an error that is unknown or unfound in messages - * @property {String} UNKNOWN - * @static - * @final - */ - const UNKNOWN = 'Unknown error'; - - public function __construct($code, $data='') - { - $message = (isset(self::$messages[$code]) ? self::$messages[$code]: self::UNKNOWN) - . ($data ? ' : ' . $data : $data); - parent::__construct($message, $code); - } - } -} +{ + /** + * Exceptions with using the HTML5 API. + * + * try + * { + * html('invalid', 'something'); + * } + * catch(Canteen\HTML5\HTML5Error $e) + * { + * $e->getMessage(); + * } + * + * @class HTML5Error + * @extends Exception + * @constructor + * @param {int} code The code of the error + * @param {String} [data=''] Additional data to associate with this error + */ + class HTML5Error extends \Exception + { + /** + * The database connection failed + * @property {int} EMPTY_ATTRIBUTE_NAME + * @static + * @final + */ + const EMPTY_ATTRIBUTE_NAME = 500; -?> \ No newline at end of file + /** + * The alias for a database is invalid + * @property {int} EMPTY_ATTRIBUTE_VALUE + * @static + * @final + */ + const EMPTY_ATTRIBUTE_VALUE = 501; + + /** + * The database name we're trying to switch to is invalid + * @property {int} INVALID_SETTER + * @static + * @final + */ + const INVALID_SETTER = 502; + + /** + * The mysql where trying to execute was a problem + * @property {int} INVALID_GETTER + * @static + * @final + */ + const INVALID_GETTER = 503; + + /** + * The html tag name is invalid + * @property {int} INVALID_TAG + * @static + * @final + */ + const INVALID_TAG = 504; + + /** + * When trying to create a node, the name is empty + * @property {int} EMPTY_NODE_TAG + * @static + * @final + */ + const EMPTY_NODE_TAG = 505; + + /** + * The parent cannot be empty + * @property {int} EMPTY_PARENT + * @static + * @final + */ + const EMPTY_PARENT = 506; + + /** + * THe addChildAt is out of bounds + * @property {int} OUT_OF_BOUNDS + * @static + * @final + */ + const OUT_OF_BOUNDS = 507; + + /** + * The child node is empty + * @property {int} EMPTY_CHILD + * @static + * @final + */ + const EMPTY_CHILD = 508; + + /** + * The node is not of instance type Node + * @property {int} INVALID_NODE + * @static + * @final + */ + const INVALID_NODE = 509; + + /** + * Look-up for error messages + * @property {Dictionary} messages + * @private + * @static + */ + private static $messages = array( + self::EMPTY_ATTRIBUTE_NAME => 'Attribute names cannot be empty', + self::EMPTY_ATTRIBUTE_VALUE => 'Attribute values cannot be empty', + self::INVALID_SETTER => 'Cannot set the property because name is invalid', + self::INVALID_GETTER => 'Cannot get the property because name is invalid', + self::INVALID_TAG => 'Not a valid HTML5 tag name', + self::EMPTY_NODE_TAG => 'Node tag is empty', + self::EMPTY_PARENT => 'The parent cannot be empty', + self::OUT_OF_BOUNDS => 'The index is out of bounds', + self::EMPTY_CHILD => 'Cannot addChild an empty child node', + self::INVALID_NODE => 'Child node must be a valid tag' + ); + + /** + * The label for an error that is unknown or unfound in messages + * @property {String} UNKNOWN + * @static + * @final + */ + const UNKNOWN = 'Unknown error'; + + public function __construct($code, $data='') + { + $message = (isset(self::$messages[$code]) ? self::$messages[$code]: self::UNKNOWN) + . ($data ? ' : ' . $data : $data); + parent::__construct($message, $code); + } + } +} diff --git a/src/Node.php b/src/Node.php index 02d8cdf..129bafa 100644 --- a/src/Node.php +++ b/src/Node.php @@ -1,341 +1,343 @@ isEmpty($tag)) - { - throw new HTML5Error(HTML5Error::EMPTY_NODE_TAG); - } - $this->_parent = null; - $this->_tag = $tag; - $this->_attributes = array(); + /** + * A generic html tag with any children or closing tag. (e.g., img, br, hr). + * Do not initiate this class directly, use the `html()` function: + * + * echo html('br'); + * + * @class Node + * @extends Proto + * @constructor + * @param {String} [tag=null] The name of the tag + * @param {Array|String} [attributes=null] The collection of tag attributes + */ + class Node extends Proto + { + /** + * The string name of the tag + * @property {String} _tag + * @protected + */ + protected $_tag; - if (isset(Specification::$TAGS[$tag])) - { - $this->_validAttrs = array_merge( - Specification::$TAGS[$tag], - Specification::$ATTRIBUTES - ); - } - else - { - $this->_validAttrs = array(); - } - - if ($attributes !== null) - { - if (is_string($attributes)) - { - $attributes = Attribute::shorthand($attributes); - } - - if (is_array($attributes)) - { - $this->setAttributes($attributes); - } - } - } - - /** - * Returns the parent node of this node, if - * a parent exists. If no parent exists, - * this function returns null. - * @method getParent - * @private - * @return {NodeContainer} The parent node object - */ - private function getParent() - { - return $this->_parent; - } - - /** - * Sets the parent of this Node. Note that this - * function is protected and can only be called by - * classes that extend Node. The parent cannot - * be null; this function will throw an Exception - * if the parent node is empty. - * @method setParent - * @protected - * @param {NodeContainer} [parent=null] The parent container node - */ - protected function setParent(NodeContainer $parent = null) - { - if ($this->isEmpty($parent)) - { - throw new HTML5Error(HTML5Error::EMPTY_PARENT); - } - $this->_parent = $parent; - } - - /** - * Given a name and value pair, sets an attribute on this Node. - * The name and value cannot be empty; if so, this function - * will throw an Exception. Note if the attribute already exists - * and the caller wants to set an attribute of the same name, - * this function will not create a new Attribute, but rather - * update the value of the existing named attribute. - * - * @method setAttribute - * @param {String} [name=null] The name of the attribute to add - * @param {String} [value=null] The value of the attribute - * @param {Node} The instance of this node - */ - public function setAttribute($name = null, $value = null) - { - if ($this->isEmpty($name)) - { - throw new HTML5Error(HTML5Error::EMPTY_ATTRIBUTE_NAME); - } - foreach($this->_attributes as $i=>$attribute) - { - if ($attribute->name === $name) - { - if (!$this->isEmpty($value)) - $attribute->value = $value; - else - unset($this->_attributes[$i]); - return $this; - } - } - $this->_attributes[] = new Attribute($name, $value); - return $this; - } - - /** - * Fetch and attribute by name from this Node. The attribute - * name cannot be null; if so, this function will throw an - * Exception. - * @method getAttribute - * @param {String} [name=null] The name of the attribute to fetch - * @return {String} The attribute's value, if any or null - */ - protected function getAttribute($name = null) - { - $returnAttr = null; + /** + * The collection of Attributes objects + * @property {Array} _attributes + * @protected + */ + protected $_attributes; - if ($this->isEmpty($name)) - { - throw new HTML5Error(HTML5Error::EMPTY_ATTRIBUTE_NAME); - } - foreach($this->_attributes as $attribute) - { - if ($attribute->name === $name) - { - $returnAttr = $attribute->value; - break; - } - } - return $returnAttr; - } - - /** - * Set the list of all attributes. - * @method setAttributes - * @param {Dictionary} values An attributes array(name=>value, name=>value) - * @return {Node} The instance of this Node - */ - public function setAttributes($values) - { - if (is_array($values)) - { - foreach($values as $name=>$value) - { - $this->setAttribute($name, $value); - } - return $this; - } - } - - /** - * Set the a data-* HTML5 Attribute - * @param {String} name The name of the data, for instance "id" is an attribute "data-id" - * @param {String} value The value of the attribute - * @return {Node} The instance of this Node - */ - public function setData($name, $value) - { - return $this->setAttribute('data-'.$name, $value); - } - - /** - * Add this child to a node container at the end - * @method appendTo - * @param {NodeContainer} container The node container to add to - * @return {Node} The instance of this Node - */ - public function appendTo(NodeContainer $container) - { - $container->addChild($this); - return $this; - } - - /** - * Add this child to the beginning of a node container - * @method prependTo - * @param {NodeContainer} container The node container to prepend to to - * @return {Node} The instance of this Node - */ - public function prependTo(NodeContainer $container) - { - $container->addChildAt($this, 0); - return $this; - } - - /** - * Get the data-* HTML5 attribute value, if set - * @method getData - * @param {String} name The name of the data attribute - * @return {String} The value of the data - */ - public function getData($name) - { - return $this->getAttribute('data-'.$name); - } - - /** - * Write to HTML - * @method __toString - * @return {String} The string representation of this HTML node - */ - public function __toString() - { - return $this->writeOpen(); - } - - /** - * Start the writing the tag - * @method writeOpen - * @protected - * @param {Boolean} [selfClose=true] If the tag is a self closing tag (e.g., br, img, hr) - * @return {String} The buffer of HTML - */ - protected function writeOpen($selfClose=true) - { - $buffer = '<'; - $buffer .= $this->_tag; - foreach($this->_attributes as $attribute) - { - $buffer .= (string)$attribute; - } - $buffer .= ($selfClose ? ' />' : '>'); - return $buffer; - } - - /** - * General purpose getter to get attribute values - * @method __get - * @param {String} name The name of the property to set - */ - public function __get($name) - { - if (in_array($name, $this->_validAttrs) || strpos($name, 'data-') === 0) - { - return $this->getAttribute($name); - } - return parent::__get($name); - } + /** + * The parent node, if any + * @property {NodeContainer} _parent + * @protected + */ + protected $_parent; - /** - * General purpose setter to set attribute values - * @method __set - * @param {String} name The name of the attribute - * @param {String} value The value of the attribute - */ - public function __set($name, $value) - { - if (in_array($name, $this->_validAttrs) || strpos($name, 'data-') === 0) - { - return $this->setAttribute($name, $value); - } - } + /** + * The collection of valid attributes names for given tag + * @property {Array} _validAttrs + * @protected + */ + protected $_validAttrs; - /** - * See if a property exists - * @method __isset - * @param {String} name The name of the attribute - */ - public function __isset($name) - { - return in_array($name, $this->_validAttrs) || parent::__isset($name); - } - - /** - * Checks if a variable is really "empty". Code borrowed from PHP.net at - * http://us3.php.net/manual/en/function.empty.php#90767 because we were - * previously using empty() to see if a variable is empty or not. But - * empty() dosen't work for attributes that have a value of "0", so we need - * something more robust here. - *