File: D:/HostingSpaces/PvdBoogaard/indoorski.nl/backup/oude-site/cms/api/class.domhelper.php
<?php
/**
* This file contains the iwp_domhelper class
*
* @version $Id$
*
*
* @package IWP
* @subpackage IWP_API
*/
/**
* IWP DOM Helper
* This is a static class that contains functions for use with DOMDocument
*
* @package IWP
* @subpackage IWP_API
*/
class
iwp_domhelper {
/**
* This function takes a DomElement object and outputs the outer HTML of it. i.e. The HTML of all the children AND the current element's HTML
*
* @param DomElement $node The DomElement object to get outer HTML for.
* @param string $NodeContent The html content to append from a parent element
*/
public static function outerHTML($node, $NodeContent='', $first=true){
if($first === true){
$firstNodeName = $node->nodeName;
$firstNodeValue = $node->nodeValue;
$NodeContent .= '<'.$firstNodeName;
$attAre = $node->attributes;
foreach ($attAre as $value){
if(!in_array(iwp_strtolower($value->nodeName), array('block', 'blockstyle'))){
$NodeContent .= " {$value->nodeName}='{$value->nodeValue}'" ;
}
}
$NodeContent .=">";
}
$NodList = $node->childNodes;
if($NodList instanceof DOMNodeList) {
for( $j=0 ; $j < $NodList->length; $j++ ){
$subNode = $NodList->item($j);//Node j
$nodeName = $subNode->nodeName;
$nodeValue = $subNode->nodeValue;
if($subNode->nodeType == XML_TEXT_NODE){
$NodeContent .= htmlspecialchars($nodeValue);
}elseif($subNode->nodeType == XML_COMMENT_NODE) {
$NodeContent .= '<!--'.$subNode->data.'-->';
}elseif($subNode->nodeType == XML_CDATA_SECTION_NODE) {
$NodeContent .= "\n".'/*<![CDATA[*/'."\n".$subNode->data."\n".'/*]]>*/'."\n";
}else{
$NodeContent .= '<'.$nodeName;
$attAre = $subNode->attributes;
if(!is_null($attAre)){
foreach ($attAre as $value){
if(!in_array(iwp_strtolower($value->nodeName), array('block', 'blockstyle'))){
$NodeContent .= " {$value->nodeName}='{$value->nodeValue}'" ;
}
}
}
$NodeContent .=">";
$NodeContent = iwp_domhelper::outerHTML($subNode, $NodeContent, false);
$NodeContent .= '</'.$nodeName.'>';
}
}
}
if($first === true){
$NodeContent .= '</'.$firstNodeName.'>';
$NodeContent = iwp_styleguide::CleanUpHTML($NodeContent);
}
return $NodeContent;
}
/**
* This function takes a DomElement object and outputs the inner HTML of it. i.e. The HTML of all the children, but not the current tag.
*
* @param DomElement $node The DomElement object to get inner HTML from.
* @param string $NodeContent The html content to append from a parent element
*/
public static function innerHTML($mainNode, $NodeContent=''){
$NodList = $mainNode->childNodes;
for( $j=0 ; $j < $NodList->length; $j++ ) {
$subNode = $NodList->item($j);
$nodeName = $subNode->nodeName;
$nodeValue = $subNode->nodeValue;
if($subNode->nodeType == XML_TEXT_NODE){
$NodeContent .= htmlspecialchars($nodeValue);
}else{
$NodeContent .= '<'.$nodeName;
$attAre = $subNode->attributes;
foreach ($attAre as $value){
$NodeContent .= ' ' . $value->nodeName . "='" . $value->nodeValue . "'";
}
$NodeContent .=">";
$NodeContent = self::innerHTML($subNode, $NodeContent);
$NodeContent .= '</'.$nodeName.'>';
}
}
return $NodeContent;
}
/**
* This function retrieves all the attributes of a DomElement object. It then returns it as an array (usually they're DomAttr objects)
*
* @param DomElement $attributes The HTML to be cleaned up
*/
public static function getAttributes($domElement){
$attAre = $domElement->attributes;
$return = array();
foreach ($attAre as $value){
$return[$value->nodeName] = $value->nodeValue;
}
return $return;
}
/**
* This function takes a "base" class name and looks for all elements that contain the class or any derivations of it.
* It will then position the replaceValue either inside the element with the class or elsewhere depending on whether it has extra position information appended.
* Matched formats include: tpl-myvar, tpl-myvar-attr where 'attr' is the attribute name to enter the value into. If no 'attr' is given, the value will be inserted as the tag's value and not as an attribute's value.
* There are special 'attr' values available for use:
* - inside - This is the same as not having an 'attr'
* - append - This appends the replaceValue to the end of the content inside the element, leaving existing data intact.
* - prepend - This prepends the replaceValue to the beginning of the content inside the element, leaving existing data intact.
* - spaceappend - This is the same as "append" but includes a space before the value. This is useful for combinding language variables.
* - spaceprepend - This works the same was as "spaceappend" but ads it to the end and the space is after the value.
* - styleprepend - This works the same as "spaceprepend", but the value is added into the "style" attribute, leaving existing styles intact.
* - styleappend - This works the same as "styleprepend", but adds it to the end instead of the beginning.
* - classprepend - This works the same as "styleprepend", but adds the values to the "class" attribute.
* - classappend - This works the same as "styleappend", but adds the values to the "class" attribute.
*
* Example: tplvar-myvar is a base class. But tpl-myvar, tpl-myvar-value, tpl-myvar-inside would all be matched.
*
* @param $domElement
* @param $baseClassName
* @param $replaceValue
* @return unknown_type
*/
public static function modifyTagByClassName($domElement, $baseClassName, $replaceValue) {
$baseClassName = trim($baseClassName);
$xpathFind = '';
if (($domElement instanceof DOMDocument)) {
$xPath = new DOMXPath($domElement);
} else {
$xPath = new DOMXPath($domElement->ownerDocument);
$attr = iwp_domhelper::getAttributes($domElement);
if(isset($attr['block'])){
$xpathFind = '//*[@block="'.$attr['block'].'" and @blockstyle="'.$attr['blockstyle'].'"]';
}
}
$classMatches = $xPath->query($xpathFind.'//*[contains(concat(\' \', @class, \' \'), \' '.$baseClassName.' \') or contains(concat(\' \', @class, \' \'), \' '.$baseClassName.'-\')]');
if($classMatches->length == 0){
return;
}
foreach($classMatches as $thisElement) {
$thisAttr = iwp_domhelper::getAttributes($thisElement);
if(!isset($thisAttr['class'])) {
continue;
}
$classList = preg_split('#\s+#', $thisAttr['class'], -1, PREG_SPLIT_NO_EMPTY);
if(empty($classList)) {
continue;
}
foreach($classList as $thisClass){
if(in_array($thisClass, array($baseClassName, $baseClassName . '-inside'))){
iwp_domhelper::replaceInnerHTML($thisElement, $replaceValue);
}elseif(substr($thisClass, 0, strlen($baseClassName)) == $baseClassName){
// we have a base class name
$positions = preg_split('#\-#', substr($thisClass, strlen($baseClassName)), -1, PREG_SPLIT_NO_EMPTY);
if(empty($positions)){
continue;
}
foreach($positions as $thisPosition){
if($thisPosition == 'inside'){
iwp_domhelper::replaceInnerHTML($thisElement, $replaceValue);
}elseif($thisPosition == 'append'){
iwp_domhelper::insertHTMLAfter($replaceValue, $thisElement->lastChild);
}elseif($thisPosition == 'prepend'){
iwp_domhelper::insertHTMLBefore($replaceValue, $thisElement->firstChild);
}elseif($thisPosition == 'spaceappend'){
iwp_domhelper::insertHTMLAfter(' ' . $replaceValue, $thisElement->lastChild);
}elseif($thisPosition == 'spaceprepend'){
iwp_domhelper::insertHTMLBefore($replaceValue . ' ', $thisElement->firstChild);
}elseif(preg_match('#^(.+?)((pre|ap)pend)$#', $thisPosition, $matches)) {
$attribute = $matches[1];
$action = $matches[2];
$addSpace = ($attribute == 'class' ? ' ' : '');
if ($thisElement->hasAttribute($attribute)) {
$currentValue = $thisElement->getAttribute($attribute);
if ($action == 'prepend') {
$thisElement->setAttribute($attribute, $replaceValue . $addSpace . $currentValue);
} else {
$thisElement->setAttribute($attribute, $currentValue . $addSpace . $replaceValue);
}
} else {
$thisElement->setAttribute($attribute, $replaceValue);
}
}else{
$thisElement->setAttribute($thisPosition, $replaceValue);
}
}
}
}
}
}
/**
* This function returns a new DomText object. By default it returns it with a new line before and after the text content
*
* @param string $text The text to be converted to a DOMText object
* @param boolean $newLines True if the text should have a new line prepended and appended before being added into a DomText object
*/
public static function NewDOMText($text, $newLines = true){
if($newLines){
return new DOMText("\n".$text."\n");
}else{
return new DOMText($text);
}
}
public static function replaceInnerHTML($domElement, $html) {
for($i=($domElement->childNodes->length - 1); $i>-1;$i--){
$childElement = $domElement->childNodes->item($i);
$domElement->removeChild($childElement);
}
$node = new DOMDocument();
$node->loadHTML('<html><body><p>'.$html.'</p></body></html>');
$xpath = new DomXpath($node);
$nodeList = $xpath->query('//body/p');
if($nodeList->length == 0){
return;
}
$cleanNodes = array();
foreach($nodeList->item(0)->childNodes as $thisNode) {
$cleanNodes[] = $domElement->ownerDocument->importNode($thisNode->cloneNode(true), true);
}
foreach($cleanNodes as $cleanNode) {
$domElement->appendChild($cleanNode);
}
unset($node);
}
public static function insertHTMLAfter($html, $before) {
$document = $before->ownerDocument;
$node = new DOMDocument();
$node->loadHTML('<html><body><p>'.$html.'</p></body></html>');
$xpath = new DomXpath($node);
$nodeList = $xpath->query('//body/p');
if($nodeList->length == 0){
return;
}
$cleanNodes = array();
foreach($nodeList->item(0)->childNodes as $thisNode) {
$cleanNodes[] = $document->importNode($thisNode->cloneNode(true), true);
}
//$cleanNodes = array_reverse($cleanNodes);
foreach($cleanNodes as $cleanNode) {
$before = $before->parentNode->insertBefore($cleanNode, $before->nextSibling);
}
unset($node);
}
public static function insertHTMLBefore($html, $before) {
$document = $before->ownerDocument;
$node = new DOMDocument();
$node->loadHTML('<html><body><p>'.$html.'</p></body></html>');
$xpath = new DomXpath($node);
$nodeList = $xpath->query('//body/p');
if($nodeList->length == 0){
return;
}
$cleanNodes = array();
foreach($nodeList->item(0)->childNodes as $thisNode) {
$cleanNodes[] = $document->importNode($thisNode->cloneNode(true), true);
}
$cleanNodes = array_reverse($cleanNodes);
foreach($cleanNodes as $cleanNode) {
$before = $before->parentNode->insertBefore($cleanNode, $before);
}
unset($node);
}
public static function HTML2Element($html, $doc){
$node = new DOMDocument();
$node->loadHTML('<html><body><p>'.$html.'</p></body></html>');
$xpath = new DomXpath($node);
$nodeList = $xpath->query('//body/p/*');
$newNode = $nodeList->item(0);
foreach($nodeList as $thisNode) {
}
$cleanNode = $doc->importNode($newNode->cloneNode(true));
unset($node);
return $cleanNode;
}
public static function AppendHTMLAfterElement($appendToElement, $domElement, $html){
$node = new DOMDocument();
$node->loadHTML('<html><body>'.$html.'</body></html>');
$lastNode = $appendToElement->nextSibling;
for($i=0;$i<$node->childNodes->item(1)->childNodes->item(0)->childNodes->length;$i++){
$newNode = $domElement->ownerDocument->importNode($node->childNodes->item(1)->childNodes->item(0)->childNodes->item($i), true);
$appendToElement->parentNode->insertBefore($newNode, $lastNode);
/*
TODO: remove?
Took this out because doesn't look like its needed.
if(is_object($lastNode->nextSibling)){
$lastNode = $lastNode->nextSibling;
}
*/
}
}
public static function AppendHTMLToElement($appendToElement, $domElement, $html){
$node = new DOMDocument();
$node->loadHTML('<html><body>'.$html.'</body></html>');
$lastNode = $appendToElement->childNodes->item($appendToElement->childNodes->length-1);
for($i=0;$i<$node->childNodes->item(1)->childNodes->item(0)->childNodes->length;$i++){
$newNode = $domElement->ownerDocument->importNode($node->childNodes->item(1)->childNodes->item(0)->childNodes->item($i), true);
$appendToElement->insertBefore($newNode, $lastNode);
if(is_object($lastNode) && is_object($lastNode->nextSibling)){
$lastNode = $lastNode->nextSibling;
}
}
}
/**
* @return DOMElement
*/
public static function GetElementByClass($domElement, $className, $iterator=0){
$blocksXpath = new DOMXPath($domElement->ownerDocument);
$xpathFind = '';
$attr = iwp_domhelper::getAttributes($domElement);
$xpathFind = '';
if(isset($attr['block'])){
$xpathFind = '//*[@block="'.$attr['block'].'" and @blockstyle="'.$attr['blockstyle'].'"]';
}
$blocks = $blocksXpath->query($xpathFind.'//*[contains(concat(\' \', @class, \' \'), \' '.$className.' \') or normalize-space(@class)="'.$className.'"]');
return $blocks->item($iterator);
}
public static function GetElementListByClass($domElement, $className){
$blocksXpath = new DOMXPath($domElement->ownerDocument);
$xpathFind = '';
$attr = iwp_domhelper::getAttributes($domElement);
$xpathFind = '@block="'.$attr['block'].'" and @blockstyle="'.$attr['blockstyle'].'"';
$blocks = $blocksXpath->query('//*['.$xpathFind.']//*[contains(concat(\' \', @class, \' \'), \' '.$className.' \') or normalize-space(@class)="'.$className.'"]');
return $blocks;
}
public static function getXpathForClass($className){
return 'contains(concat(\' \', @class, \' \'), \' '.$className.' \') or normalize-space(@class)="'.$className.'"';
}
public static function ReplaceContentByClass($domElement, $className, $replaceWith){
$blocksXpath = new DOMXPath($domElement->ownerDocument);
$xpathFind = '';
$attr = iwp_domhelper::getAttributes($domElement);
if(isset($attr['block'])){
$xpathFind = '//*[@block="'.$attr['block'].'" and @blockstyle="'.$attr['blockstyle'].'"]';
}else{
$xpathFind = '';
}
$blocks = $blocksXpath->query($xpathFind.'//*[contains(concat(\' \', @class, \' \'), \' '.$className.' \') or normalize-space(@class)="'.$className.'"]');
foreach ($blocks as $blockData) {
$blockData->nodeValue = $replaceWith;
}
}
public static function ReplaceAttributeByClass($domElement, $className, $attrName, $replaceWith){
$blocksXpath = new DOMXPath($domElement->ownerDocument);
$xpathFind = '';
$attr = iwp_domhelper::getAttributes($domElement);
if(isset($attr['block'])){
$xpathFind = '//*[@block="'.$attr['block'].'" and @blockstyle="'.$attr['blockstyle'].'"]';
}else{
$xpathFind = '';
}
$xpath = $xpathFind . '//*[contains(concat(\' \', @class, \' \'), \' '.$className.' \') or normalize-space(@class)="'.$className.'"]';
$blocks = $blocksXpath->query($xpath);
foreach ($blocks as $blockData) {
$blockData->setAttribute($attrName, $replaceWith);
}
}
public static function AppendAttributeByClass($domElement, $className, $attrName, $replaceWith, $withSpace=true){
$blocksXpath = new DOMXPath($domElement->ownerDocument);
$space = $xpathFind = '';
$attr = iwp_domhelper::getAttributes($domElement);
if($withSpace){
$space = ' ';
}
if(isset($attr['block'])){
$xpathFind = '//*[@block="'.$attr['block'].'" and @blockstyle="'.$attr['blockstyle'].'"]';
}else{
$xpathFind = '';
}
$xpath = $xpathFind . '//*[contains(concat(\' \', @class, \' \'), \' '.$className.' \') or normalize-space(@class)="'.$className.'"]';
$blocks = $blocksXpath->query($xpath);
foreach ($blocks as $blockData) {
$blockData->setAttribute($attrName, (string)$blockData->getAttribute($attrName) . $space . $replaceWith);
}
}
public static function ReplaceAttribute($domElement, $attrName, $replaceWith){
$domElement->setAttribute($attrName, $replaceWith);
}
public static function WrapElement($element, $before, $after = ''){
if ($before) {
$element->parentNode->insertBefore(iwp_domhelper::NewDOMText($before), $element);
}
if ($after) {
$element->parentNode->insertBefore(iwp_domhelper::NewDOMText($after), $element->nextSibling);
}
}
public static function WrapInnerElement($element, $before, $after = ''){
if ($before) {
$element->insertBefore(iwp_domhelper::NewDOMText($before), $element->firstChild);
}
if ($after) {
$element->insertBefore(iwp_domhelper::NewDOMText($after), $element->lastChild->nextSibling);
}
}
public static function WrapElementsByClass ($domElement, $className, $before, $after = '') {
$nodes = iwp_domhelper::GetElementListByClass($domElement, $className);
$count = 0;
if (is_object($nodes)) {
foreach ($nodes as $node) {
iwp_domhelper::WrapElement($node, $before, $after);
++$count;
}
}
return $count;
}
public static function WrapInnerElementsByClass ($domElement, $className, $before, $after = '') {
$nodes = iwp_domhelper::GetElementListByClass($domElement, $className);
if (is_object($nodes)) {
foreach ($nodes as $node) {
iwp_domhelper::WrapInnerElement($node, $before, $after);
}
}
}
/**
* This function removes the block="" and blockStyle="" attributes from a simplexml object
*
* @param SimpleXML This msut be a SimpleXML object
*
* @return void Returns nothing, changes are made the object
*/
public static function removeBlockAttributes($objBlock){
unset($objBlock['block']);
unset($objBlock['blockStyle']);
}
}