/home/desid573/verdenaturopathy.com.au/wp-content/plugins/pagelayer/lib/pquery
Edit: /home/desid573/verdenaturopathy.com.au/wp-content/plugins/pagelayer/lib/pquery/gan_node_html.php (75753B)
* @copyright 2010 Niels A.D., 2014 Todd Burry
* @license http://opensource.org/licenses/LGPL-2.1 LGPL-2.1
* @package pQuery
*/
namespace pagelayerQuery;
/**
* Holds (x)html/xml tag information like tag name, attributes,
* parent, children, self close, etc.
*
*/
class DomNode implements IQuery {
/**
* Element Node, used for regular elements
*/
const NODE_ELEMENT = 0;
/**
* Text Node
*/
const NODE_TEXT = 1;
/**
* Comment Node
*/
const NODE_COMMENT = 2;
/**
* Conditional Node (
*/
const NODE_CDATA = 4;
/**
* Doctype Node
*/
const NODE_DOCTYPE = 5;
/**
* XML Node, used for tags that start with ?, like 'value')
* @internal Public for faster access!
* @see getAttribute()
* @see setAttribute()
* @access private
*/
var $attributes = array();
/**
* Namespace info for attributes
* @var array
* @internal array('tag' => array(array('ns', 'tag', 'ns:tag', index)))
* @internal Public for easy outside modifications!
* @see findAttribute()
* @access private
*/
var $attributes_ns = null;
/**
* Array of child nodes
* @var array
* @internal Public for faster access!
* @see childCount()
* @see getChild()
* @see addChild()
* @see deleteChild()
* @access private
*/
var $children = array();
/**
* Full tag name (including namespace)
* @var string
* @see getTagName()
* @see getNamespace()
*/
var $tag = '';
/**
* Namespace info for tag
* @var array
* @internal array('namespace', 'tag')
* @internal Public for easy outside modifications!
* @access private
*/
var $tag_ns = null;
/**
* Is node a self closing node? No closing tag if true.
* @var bool
*/
var $self_close = false;
/**
* If self close, then this will be used to close the tag
* @var string
* @see $self_close
*/
var $self_close_str = ' /';
/**
* Use short tags for attributes? If true, then attributes
* with values equal to the attribute name will not output
* the value, e.g. selected="selected" will be selected.
* @var bool
*/
var $attribute_shorttag = false;
/**
* Function map used for the selector filter
* @var array
* @internal array('root' => 'filter_root') will cause the
* selector to call $this->filter_root at :root
* @access private
*/
var $filter_map = array(
'root' => 'filter_root',
'nth-child' => 'filter_nchild',
'eq' => 'filter_nchild', //jquery (naming) compatibility
'gt' => 'filter_gt',
'lt' => 'filter_lt',
'nth-last-child' => 'filter_nlastchild',
'nth-of-type' => 'filter_ntype',
'nth-last-of-type' => 'filter_nlastype',
'odd' => 'filter_odd',
'even' => 'filter_even',
'every' => 'filter_every',
'first-child' => 'filter_first',
'last-child' => 'filter_last',
'first-of-type' => 'filter_firsttype',
'last-of-type' => 'filter_lasttype',
'only-child' => 'filter_onlychild',
'only-of-type' => 'filter_onlytype',
'empty' => 'filter_empty',
'not-empty' => 'filter_notempty',
'has-text' => 'filter_hastext',
'no-text' => 'filter_notext',
'lang' => 'filter_lang',
'contains' => 'filter_contains',
'has' => 'filter_has',
'not' => 'filter_not',
'element' => 'filter_element',
'text' => 'filter_text',
'comment' => 'filter_comment',
'checked' => 'filter_checked',
'selected' => 'filter_selected',
);
/**
* Class constructor
* @param string|array $tag Name of the tag, or array with taginfo (array(
* 'tag_name' => 'tag',
* 'self_close' => false,
* 'attributes' => array('attribute' => 'value')))
* @param DomNode $parent Parent of node, null if none
*/
function __construct($tag, $parent) {
$this->parent = $parent;
if (is_string($tag)) {
$this->tag = $tag;
} else {
$this->tag = $tag['tag_name'];
$this->self_close = $tag['self_close'];
$this->attributes = $tag['attributes'];
}
}
#php4 PHP4 class constructor compatibility
#function DomNode($tag, $parent) {return $this->__construct($tag, $parent);}
#php4e
/**
* Class destructor
* @access private
*/
function __destruct() {
$this->delete();
}
/**
* Class toString, outputs {@link $tag}
* @return string
* @access private
*/
function __toString() {
return (($this->tag === '~root~') ? $this->toString(true, true, 1) : $this->tag);
}
/**
* Class magic get method, outputs {@link getAttribute()}
* @return string
* @access private
*/
function __get($attribute) {
return $this->getAttribute($attribute);
}
/**
* Class magic set method, performs {@link setAttribute()}
* @access private
*/
function __set($attribute, $value) {
$this->setAttribute($attribute, $value);
}
/**
* Class magic isset method, returns {@link hasAttribute()}
* @return bool
* @access private
*/
function __isset($attribute) {
return $this->hasAttribute($attribute);
}
/**
* Class magic unset method, performs {@link deleteAttribute()}
* @access private
*/
function __unset($attribute) {
return $this->deleteAttribute($attribute);
}
/**
* Class magic invoke method, performs {@link query()}.
* @param string $query The css query to run on the nodes.
* @return \pQuery
*/
function __invoke($query = '*') {
return $this->query($query);
}
/**
* Returns place in document
* @return string
*/
function dumpLocation() {
return (($this->parent) ? (($p = $this->parent->dumpLocation()) ? $p.' > ' : '').$this->tag.'('.$this->typeIndex().')' : '');
}
/**
* Returns all the attributes and their values
* @return string
* @access private
*/
protected function toString_attributes() {
$s = '';
foreach($this->attributes as $a => $v) {
$s .= ' '.$a;
if ((!$this->attribute_shorttag) || ($v !== $a)) {
$quote = '"';//(strpos($v, '"') === false) ? '"' : "'";
$v = str_replace('"', '"', $v);
$s .= '='.$quote.$v.$quote;
}
}
return $s;
}
/**
* Returns the content of the node (child tags and text)
* @param bool $attributes Print attributes of child tags
* @param bool|int $recursive How many sublevels of childtags to print. True for all.
* @param bool $content_only Only print text, false will print tags too.
* @return string
* @access private
*/
protected function toString_content($attributes = true, $recursive = true, $content_only = false) {
$s = '';
foreach($this->children as $c) {
$s .= $c->toString($attributes, $recursive, $content_only);
}
return $s;
}
/**
* Returns the node as string
* @param bool $attributes Print attributes (of child tags)
* @param bool|int $recursive How many sub-levels of child tags to print. True for all.
* @param bool|int $content_only Only print text, false will print tags too.
* @return string
*/
function toString($attributes = true, $recursive = true, $content_only = false) {
if ($content_only) {
if (is_int($content_only)) {
--$content_only;
}
return $this->toString_content($attributes, $recursive, $content_only);
}
$s = '<'.$this->tag;
if ($attributes) {
$s .= $this->toString_attributes();
}
if ($this->self_close) {
$s .= $this->self_close_str.'>';
} else {
$s .= '>';
if($recursive) {
$s .= $this->toString_content($attributes);
}
$s .= ''.$this->tag.'>';
}
return $s;
}
/**
* Similar to JavaScript outerText, will return full (html formatted) node
* @return string
*/
function getOuterText() {
return $this->toString();
}
/**
* Similar to JavaScript outerText, will replace node (and child nodes) with new text
* @param string $text
* @param HtmlParserBase $parser Null to auto create instance
* @return bool|array True on succeed, array with errors on failure
*/
function setOuterText($text, $parser = null) {
if (trim($text)) {
$index = $this->index();
if ($parser === null) {
$parser = new $this->parserClass();
}
$parser->setDoc($text);
$parser->parse_all();
$parser->root->moveChildren($this->parent, $index);
}
$this->delete();
return (($parser && $parser->errors) ? $parser->errors : true);
}
/**
* Return html code of node
* @internal jquery (naming) compatibility
* @param string|null $value The value to set or null to get the value.
* @see toString()
* @return string
*/
function html($value = null) {
if ($value !== null) {
$this->setInnerText($value);
}
return $this->getInnerText();
}
/**
* Similar to JavaScript innerText, will return (html formatted) content
* @return string
*/
function getInnerText() {
return $this->toString(true, true, 1);
}
/**
* Similar to JavaScript innerText, will replace child nodes with new text
* @param string $text
* @param HtmlParserBase $parser Null to auto create instance
* @return bool|array True on succeed, array with errors on failure
*/
function setInnerText($text, $parser = null) {
$this->clear();
if (trim($text)) {
if ($parser === null) {
$parser = new $this->parserClass();
}
$parser->root =& $this;
$parser->setDoc($text);
$parser->parse_all();
}
return (($parser && $parser->errors) ? $parser->errors : true);
}
/**
* Similar to JavaScript plainText, will return text in node (and subnodes)
* @return string
*/
function getPlainText() {
return preg_replace('`\s+`', ' ', $this->toString(true, true, true));
}
/**
* Return plaintext taking document encoding into account
* @return string
*/
function getPlainTextUTF8() {
$txt = $this->toString(true, true, true);
$enc = $this->getEncoding();
if ($enc !== false) {
$txt = mb_convert_encoding($txt, 'UTF-8', $enc);
}
return preg_replace('`\s+`', ' ', $txt);
}
/**
* Similar to JavaScript plainText, will replace child nodes with new text (literal)
* @param string $text
*/
function setPlainText($text) {
$this->clear();
if (trim($text)) {
$this->addText($text);
}
}
/**
* Delete node from parent and clear node
*/
function delete() {
if (($p = $this->parent) !== null) {
$this->parent = null;
$p->deleteChild($this);
} else {
$this->clear();
}
}
/**
* Detach node from parent
* @param bool $move_children_up Only detach current node and replace it with child nodes
* @internal jquery (naming) compatibility
* @see delete()
*/
function detach($move_children_up = false) {
if (($p = $this->parent) !== null) {
$index = $this->index();
$this->parent = null;
if ($move_children_up) {
$this->moveChildren($p, $index);
}
$p->deleteChild($this, true);
}
}
/**
* Deletes all child nodes from node
*/
function clear() {
foreach($this->children as $c) {
$c->parent = null;
$c->delete();
}
$this->children = array();
}
/**
* Get top parent
* @return DomNode Root, null if node has no parent
*/
function getRoot() {
$r = $this->parent;
$n = ($r === null) ? null : $r->parent;
while ($n !== null) {
$r = $n;
$n = $r->parent;
}
return $r;
}
/**
* Change parent
* @param null|DomNode $to New parent, null if none
* @param false|int $index Add child to parent if not present at index, false to not add, negative to count from end, null to append
*/
#php4
#function changeParent($to, &$index) {
#php4e
#php5
function changeParent($to, &$index = null) {
#php5e
if ($this->parent !== null) {
$this->parent->deleteChild($this, true);
}
$this->parent = $to;
if ($index !== false) {
$new_index = $this->index();
if (!(is_int($new_index) && ($new_index >= 0))) {
$this->parent->addChild($this, $index);
}
}
}
/**
* Find out if node has (a certain) parent
* @param DomNode|string $tag Match against parent, string to match tag, object to fully match node, null to return if node has parent
* @param bool $recursive
* @return bool
*/
function hasParent($tag = null, $recursive = false) {
if ($this->parent !== null) {
if ($tag === null) {
return true;
} elseif (is_string($tag)) {
return (($this->parent->tag === $tag) || ($recursive && $this->parent->hasParent($tag)));
} elseif (is_object($tag)) {
return (($this->parent === $tag) || ($recursive && $this->parent->hasParent($tag)));
}
}
return false;
}
/**
* Find out if node is parent of a certain tag
* @param DomNode|string $tag Match against parent, string to match tag, object to fully match node
* @param bool $recursive
* @return bool
* @see hasParent()
*/
function isParent($tag, $recursive = false) {
return ($this->hasParent($tag, $recursive) === ($tag !== null));
}
/**
* Find out if node is text
* @return bool
*/
function isText() {
return false;
}
/**
* Find out if node is comment
* @return bool
*/
function isComment() {
return false;
}
/**
* Find out if node is text or comment node
* @return bool
*/
function isTextOrComment() {
return false;
}
/**
* Move node to other node
* @param DomNode $to New parent, null if none
* @param int $new_index Add child to parent at index if not present, null to not add, negative to count from end
* @internal Performs {@link changeParent()}
*/
#php4
#function move($to, &$new_index) {
#php4e
#php5
function move($to, &$new_index = -1) {
#php5e
$this->changeParent($to, $new_index);
}
/**
* Move child nodes to other node
* @param DomNode $to New parent, null if none
* @param int $new_index Add child to new node at index if not present, null to not add, negative to count from end
* @param int $start Index from child node where to start wrapping, 0 for first element
* @param int $end Index from child node where to end wrapping, -1 for last element
*/
#php4
#function moveChildren($to, &$new_index, $start = 0, $end = -1) {
#php4e
#php5
function moveChildren($to, &$new_index = -1, $start = 0, $end = -1) {
#php5e
if ($end < 0) {
$end += count($this->children);
}
for ($i = $start; $i <= $end; $i++) {
$this->children[$start]->changeParent($to, $new_index);
}
}
/**
* Index of node in parent
* @param bool $count_all True to count all tags, false to ignore text and comments
* @return int -1 if not found
*/
function index($count_all = true) {
if (!$this->parent) {
return -1;
} elseif ($count_all) {
return $this->parent->findChild($this);
} else{
$index = -1;
//foreach($this->parent->children as &$c) {
// if (!$c->isTextOrComment()) {
// ++$index;
// }
// if ($c === $this) {
// return $index;
// }
//}
foreach(array_keys($this->parent->children) as $k) {
if (!$this->parent->children[$k]->isTextOrComment()) {
++$index;
}
if ($this->parent->children[$k] === $this) {
return $index;
}
}
return -1;
}
}
/**
* Change index of node in parent
* @param int $index New index
*/
function setIndex($index) {
if ($this->parent) {
if ($index > $this->index()) {
--$index;
}
$this->delete();
$this->parent->addChild($this, $index);
}
}
/**
* Index of all similar nodes in parent
* @return int -1 if not found
*/
function typeIndex() {
if (!$this->parent) {
return -1;
} else {
$index = -1;
//foreach($this->parent->children as &$c) {
// if (strcasecmp($this->tag, $c->tag) === 0) {
// ++$index;
// }
// if ($c === $this) {
// return $index;
// }
//}
foreach(array_keys($this->parent->children) as $k) {
if (strcasecmp($this->tag, $this->parent->children[$k]->tag) === 0) {
++$index;
}
if ($this->parent->children[$k] === $this) {
return $index;
}
}
return -1;
}
}
/**
* Calculate indent of node (number of parent tags - 1)
* @return int
*/
function indent() {
return (($this->parent) ? $this->parent->indent() + 1 : -1);
}
/**
* Get sibling node
* @param int $offset Offset from current node
* @return DomNode Null if not found
*/
function getSibling($offset = 1) {
$index = $this->index() + $offset;
if (($index >= 0) && ($index < $this->parent->childCount())) {
return $this->parent->getChild($index);
} else {
return null;
}
}
/**
* Get node next to current
* @param bool $skip_text_comments
* @return DomNode Null if not found
* @see getSibling()
* @see getPreviousSibling()
*/
function getNextSibling($skip_text_comments = true) {
$offset = 1;
while (($n = $this->getSibling($offset)) !== null) {
if ($skip_text_comments && ($n->tag[0] === '~')) {
++$offset;
} else {
break;
}
}
return $n;
}
/**
* Get node previous to current
* @param bool $skip_text_comments
* @return DomNode Null if not found
* @see getSibling()
* @see getNextSibling()
*/
function getPreviousSibling($skip_text_comments = true) {
$offset = -1;
while (($n = $this->getSibling($offset)) !== null) {
if ($skip_text_comments && ($n->tag[0] === '~')) {
--$offset;
} else {
break;
}
}
return $n;
}
/**
* Get namespace of node
* @return string
* @see setNamespace()
*/
function getNamespace() {
if ($this->tag_ns === null) {
$a = explode(':', $this->tag, 2);
if (empty($a[1])) {
$this->tag_ns = array('', $a[0]);
} else {
$this->tag_ns = array($a[0], $a[1]);
}
}
return $this->tag_ns[0];
}
/**
* Set namespace of node
* @param string $ns
* @see getNamespace()
*/
function setNamespace($ns) {
if ($this->getNamespace() !== $ns) {
$this->tag_ns[0] = $ns;
$this->tag = $ns.':'.$this->tag_ns[1];
}
}
/**
* Get tagname of node (without namespace)
* @return string
* @see setTag()
*/
function getTag() {
if ($this->tag_ns === null) {
$this->getNamespace();
}
return $this->tag_ns[1];
}
/**
* Set tag (with or without namespace)
* @param string $tag
* @param bool $with_ns Does $tag include namespace?
* @see getTag()
*/
function setTag($tag, $with_ns = false) {
$with_ns = $with_ns || (strpos($tag, ':') !== false);
if ($with_ns) {
$this->tag = $tag;
$this->tag_ns = null;
} elseif ($this->getTag() !== $tag) {
$this->tag_ns[1] = $tag;
$this->tag = (($this->tag_ns[0]) ? $this->tag_ns[0].':' : '').$tag;
}
}
/**
* Try to determine the encoding of the current tag
* @return string|bool False if encoding could not be found
*/
function getEncoding() {
$root = $this->getRoot();
if ($root !== null) {
if ($enc = $root->select('meta[charset]', 0, true, true)) {
return $enc->getAttribute("charset");
} elseif ($enc = $root->select('"?xml"[encoding]', 0, true, true)) {
return $enc->getAttribute("encoding");
} elseif ($enc = $root->select('meta[content*="charset="]', 0, true, true)) {
$enc = $enc->getAttribute("content");
return substr($enc, strpos($enc, "charset=")+8);
}
}
return false;
}
/**
* Number of children in node
* @param bool $ignore_text_comments Ignore text/comments with calculation
* @return int
*/
function childCount($ignore_text_comments = false) {
if (!$ignore_text_comments) {
return count($this->children);
} else{
$count = 0;
//foreach($this->children as &$c) {
// if (!$c->isTextOrComment()) {
// ++$count;
// }
//}
foreach(array_keys($this->children) as $k) {
if (!$this->children[$k]->isTextOrComment()) {
++$count;
}
}
return $count;
}
}
/**
* Find node in children
* @param DomNode $child
* @return int False if not found
*/
function findChild($child) {
return array_search($child, $this->children, true);
}
/**
* Checks if node has another node as child
* @param DomNode $child
* @return bool
*/
function hasChild($child) {
return ((bool) findChild($child));
}
/**
* Get childnode
* @param int|DomNode $child Index, negative to count from end
* @param bool $ignore_text_comments Ignore text/comments with index calculation
* @return DomNode
*/
function &getChild($child, $ignore_text_comments = false) {
if (!is_int($child)) {
$child = $this->findChild($child);
} elseif ($child < 0) {
$child += $this->childCount($ignore_text_comments);
}
if ($ignore_text_comments) {
$count = 0;
$last = null;
//foreach($this->children as &$c) {
// if (!$c->isTextOrComment()) {
// if ($count++ === $child) {
// return $c;
// }
// $last = $c;
// }
//}
foreach(array_keys($this->children) as $k) {
if (!$this->children[$k]->isTextOrComment()) {
if ($count++ === $child) {
return $this->children[$k];
}
$last = $this->children[$k];
}
}
return (($child > $count) ? $last : null);
} else {
return $this->children[$child];
}
}
/**
* Add child node
* @param string|DomNode $tag Tag name or object
* @param int $offset Position to insert node, negative to count from end, null to append
* @return DomNode Added node
*/
#php4
#function &addChild($tag, &$offset) {
#php4e
#php5
function &addChild($tag, &$offset = null) {
#php5e
if (is_array($tag)) {
$tag = new $this->childClass($tag, $this);
} elseif (is_string($tag)) {
$nodes = $this->createNodes($tag);
$tag = array_shift($nodes);
if ($tag && $tag->parent !== $this) {
$index = false;
$tag->changeParent($this, $index);
}
} elseif (is_object($tag) && $tag->parent !== $this) {
$index = false; //Needs to be passed by ref
$tag->changeParent($this, $index);
}
if (is_int($offset) && ($offset < count($this->children)) && ($offset !== -1)) {
if ($offset < 0) {
$offset += count($this->children);
}
array_splice($this->children, $offset++, 0, array(&$tag));
} else {
$this->children[] =& $tag;
}
return $tag;
}
/**
* First child node
* @param bool $ignore_text_comments Ignore text/comments with index calculation
* @return DomNode
*/
function &firstChild($ignore_text_comments = false) {
return $this->getChild(0, $ignore_text_comments);
}
/**
* Last child node
* @param bool $ignore_text_comments Ignore text/comments with index calculation
* @return DomNode
*/
function &lastChild($ignore_text_comments = false) {
return $this->getChild(-1, $ignore_text_comments);
}
/**
* Insert childnode
* @param string|DomNode $tag Tagname or object
* @param int $offset Position to insert node, negative to count from end, null to append
* @return DomNode Added node
* @see addChild();
*/
function &insertChild($tag, $index) {
return $this->addChild($tag, $index);
}
/**
* Add text node
* @param string $text
* @param int $offset Position to insert node, negative to count from end, null to append
* @return DomNode Added node
* @see addChild();
*/
#php4
#function &addText($text, &$offset) {
#php4e
#php5
function &addText($text, &$offset = null) {
#php5e
return $this->addChild(new $this->childClass_Text($this, $text), $offset);
}
/**
* Add comment node
* @param string $text
* @param int $offset Position to insert node, negative to count from end, null to append
* @return DomNode Added node
* @see addChild();
*/
#php4
#function &addComment($text, &$offset) {
#php4e
#php5
function &addComment($text, &$offset = null) {
#php5e
return $this->addChild(new $this->childClass_Comment($this, $text), $offset);
}
/**
* Add conditional node
* @param string $condition
* @param bool True for ';}
}
/**
* Node subclass for conditional tags
*/
class ConditionalTagNode extends DomNode {
#php4 Compatibility with PHP4, this gets changed to a regular var in release tool
#static $NODE_TYPE = self::NODE_CONDITIONAL;
#php4e
#php5
const NODE_TYPE = self::NODE_CONDITIONAL;
#php5e
var $tag = '~conditional~';
/**
* @var string
*/
var $condition = '';
/**
* Class constructor
* @param DomNode $parent
* @param string $condition e.g. "if IE"
* @param bool $hidden