/**
  * Clones a node for appending to raw-html containing Elements like Interactive.
  *
  * @param DOMNode $node The node to clone
  * @return DOMNode The cloned node.
  */
 public static function cloneNode($node)
 {
     $clone = $node->cloneNode(true);
     if (Type::is($clone, 'DOMElement') && $clone->hasAttribute(self::INSTANT_ARTICLES_PARSED_FLAG)) {
         $clone->removeAttribute(self::INSTANT_ARTICLES_PARSED_FLAG);
     }
     return $clone;
 }
Example #2
0
 /**
  * @param \DOMNode $node
  * @return string
  */
 public static function getOuterHtml(\DOMNode $node)
 {
     $domDocument = new \DOMDocument('1.0');
     $b = $domDocument->importNode($node->cloneNode(true), true);
     $domDocument->appendChild($b);
     $html = $domDocument->saveHtml();
     $html = StringHelper::safeEncodeStr($html);
     return $html;
 }
Example #3
0
 /**
  * Adds a node to parent node and all its child nodes
  *
  * @param DOMNode $node   // parent node
  * @param DOMNode $appendChild   // append node
  */
 function appendChilds($node, $appendChild)
 {
     $cloneChild = $this->importNode($appendChild->cloneNode(false), true);
     $newNode = $node->appendChild($cloneChild);
     if ($appendChild->childNodes) {
         foreach ($appendChild->childNodes as $child) {
             $this->appendChilds($newNode, $child);
         }
     }
 }
Example #4
0
 /**
  * Duplicate an element in the main document. Mainly used to complete calls_list
  *
  * @param DOMNode 	$node 						A DOMNode element.
  * @param string 	$insert_duplicate_as 		Specifies how to place the duplicated element relative to its source.
  * @param bool 		$insert_before 				The numeric key location of an item in list before which to add this newly duplicated $node.
  * 
  * @return void
  */
 public function duplicateNode($node, $insert_duplicate_as = 'immediate_sibling', $insert_before = false)
 {
     $parent = $node->parentNode;
     if ($insert_duplicate_as == 'sub_child') {
         $parent = $node;
     } elseif ($insert_before === false && !empty($node->nextSibling)) {
         $insert_before = $node->nextSibling;
     }
     // Copy and insert the main node
     $node_copy = $node->cloneNode(true);
     if ($insert_before) {
         // Insert $node_copy
         $parent->insertBefore($node_copy, $insert_before);
     } else {
         // Insert $node_copy as last child
         $parent->appendChild($node_copy);
     }
     // See if we can first add a contextual line break or space. Not always the case anyways
     if ($this->formatOutput && is_object($parent->firstChild) && $parent->firstChild->nodeName == '#text' && is_null(trim($parent->firstChild->nodeValue))) {
         $white_space = $parent->firstChild->cloneNode(true);
         $parent->insertBefore($white_space, $node_copy);
     }
     return $node_copy;
 }
Example #5
0
 /**
  * @param \DOMNode $node
  * @return \DOMNode
  */
 public function cloneAndPrependChild(\DOMNode $node)
 {
     return DOMStatic::prependTo($node->cloneNode(true), $this);
 }
Example #6
0
 /**
  * Cousin of the javascript attribute of the same name.
  *
  * Several methods of implementation are available, though the best is 
  *  likely not written yet, and would include node cloning and document
  *  fragments.
  *
  * @param DOMElement $element
  *  The element whos innerds we want
  * @param bool $deep
  *  Sets whether or not we want to do a "deep copy" and recurse into child
  *  elements (which is the de-facto for the standard javascript innerHTML
  *  attribute). Set this to false in order to get a "shallow" innerHTML.
  *  If $deep is set to false, then $method is ignored, and method 1 is 
  *  used since it is the only one that supports this option.
  * @param int $method
  *  An integer selector for the method we wish to use (0, 1, or 2). There 
  *  are many ways of implementing this functionality, some better than 
  *  others.  
  *  Method 0 takes less memory and should be slightly faster than method 1.
  *  Method 1 is the most versatile.
  *  Method 2 only works with php v5.3.6 and above, and ignores the deep
  *  setting, but is the most efficient method.
  * @param boo $preserve
  *  If method 1 or 2 are used, then $preserve may be set to true in order to
  *  preserve all characters from the original document; otherwise, they
  *  will strip out all carriage-returns ("\n") in order to be a functional 
  *  equivalent to the default method 0.
  * @return String of the html within the submitted element
  * @author David Hazel
  **/
 public static function innerHtml(DOMNode $node, $deep = true, $method = 0, $preserve = false)
 {
     // do type checking
     if (!is_bool($deep)) {
         throw new Exception(sprintf('The second parameter (for the "deep" setting) must be boolean. %s given.', gettype($deep)));
     } elseif (!is_int($method)) {
         throw new Exception(sprintf('The third parameter (for the "method" setting) must be an integer. %s given.', gettype($method)));
     } elseif (!is_bool($preserve)) {
         throw new Exception(sprintf('The fourth parameter (for the "preserve" setting) must be boolean. %s given.', gettype($preserve)));
     }
     // if deep is false, use the one method that can do shallow
     if ($deep === false) {
         $method = 1;
     }
     // execute the method
     if ($method == 0) {
         // taken from the Raxan PDI framework
         $d = new DOMDocument('1.0');
         $b = $d->importNode($node->cloneNode(true), true);
         $d->appendChild($b);
         $h = $d->saveHTML();
         // remove outer tags (comment out this line if tags are desired)
         $h = substr($h, strpos($h, '>') + 1, -(strlen($node->nodeName) + 4));
         return $h;
     } else {
         if ($method == 1) {
             // my first method
             $innerHTML = '';
             $children = $node->childNodes;
             foreach ($children as $child) {
                 $tmp_dom = new DOMDocument();
                 $tmp_dom->appendChild($tmp_dom->importNode($child, $deep));
                 //$innerHTML .= trim($tmp_dom->saveHTML());
                 if ($preserve !== true) {
                     $innerHTML .= preg_replace('/\\n/', '', $tmp_dom->saveHTML());
                 } else {
                     $innerHTML .= $tmp_dom->saveHTML();
                 }
             }
             return $innerHTML;
         } else {
             if ($method == 2) {
                 // my own creation, prior to the Raxan method
                 // (only works with php v5.3.6 and above)
                 $innerHTML = '';
                 $children = $node->childNodes;
                 foreach ($children as $child) {
                     $tmpString = $child->ownerDocument->saveHTML($child);
                     if ($preserve !== true) {
                         $innerHTML .= preg_replace('/\\n/', '', $tmpString);
                     } else {
                         $innerHTML .= $tmpString;
                     }
                 }
                 return $innerHTML;
             } else {
                 throw new Exception(sprintf('The requested innerHtml method ("%s") does not exist.', $method));
             }
         }
     }
 }
 private function parseNodeAttributes(DOMNode &$node)
 {
     if ($node->hasAttributes()) {
         foreach ($node->attributes as $attr) {
             if (strpos($attr->value, '${') !== false) {
                 $expressions = array();
                 preg_match_all('/(\\$\\{)(.*)(\\})/imsxU', $attr->value, $expressions);
                 for ($i = 0; $i < count($expressions[0]); $i++) {
                     $toReplace = $expressions[0][$i];
                     $expression = $expressions[2][$i];
                     $expressionResult = ExpressionParser::evaluate($expression, $this->dataContext);
                     switch (strtolower($attr->name)) {
                         case 'repeat':
                             // Can only loop if the result of the expression was an array
                             if (!is_array($expressionResult)) {
                                 throw new ExpressionException("Can't repeat on a singular var");
                             }
                             // Make sure the repeat variable doesn't show up in the cloned nodes (otherwise it would infinit recurse on this->parseNode())
                             $node->removeAttribute('repeat');
                             // Is a named var requested?
                             $variableName = $node->getAttribute('var') ? trim($node->getAttribute('var')) : false;
                             // Store the current 'Cur', index and count state, we might be in a nested repeat loop
                             $previousCount = isset($this->dataContext['Context']['Count']) ? $this->dataContext['Context']['Count'] : null;
                             $previousIndex = isset($this->dataContext['Context']['Index']) ? $this->dataContext['Context']['Index'] : null;
                             $previousCur = $this->dataContext['Cur'];
                             // For information on the loop context, see http://opensocial-resources.googlecode.com/svn/spec/0.9/OpenSocial-Templating.xml#rfc.section.10.1
                             $this->dataContext['Context']['Count'] = count($expressionResult);
                             foreach ($expressionResult as $index => $entry) {
                                 if ($variableName) {
                                     // this is cheating a little since we're not putting it on the top level scope, the variable resolver will check 'Cur' first though so myVar.Something will still resolve correctly
                                     $this->dataContext['Cur'][$variableName] = $entry;
                                 }
                                 $this->dataContext['Cur'] = $entry;
                                 $this->dataContext['Context']['Index'] = $index;
                                 // Clone this node and it's children
                                 $newNode = $node->cloneNode(true);
                                 // Append the parsed & expanded node to the parent
                                 $newNode = $node->parentNode->insertBefore($newNode, $node);
                                 // And parse it (using the global + loop context)
                                 $this->parseNode($newNode, true);
                             }
                             // Restore our previous data context state
                             $this->dataContext['Cur'] = $previousCur;
                             if ($previousCount) {
                                 $this->dataContext['Context']['Count'] = $previousCount;
                             } else {
                                 unset($this->dataContext['Context']['Count']);
                             }
                             if ($previousIndex) {
                                 $this->dataContext['Context']['Index'] = $previousIndex;
                             } else {
                                 unset($this->dataContext['Context']['Index']);
                             }
                             return $node;
                             break;
                         case 'if':
                             if (!$expressionResult) {
                                 return $node;
                             } else {
                                 $node->removeAttribute('if');
                             }
                             break;
                             // These special cases that only apply for certain tag types
                         // These special cases that only apply for certain tag types
                         case 'selected':
                             if ($node->tagName == 'option') {
                                 if ($expressionResult) {
                                     $node->setAttribute('selected', 'selected');
                                 } else {
                                     $node->removeAttribute('selected');
                                 }
                             } else {
                                 throw new ExpressionException("Can only use selected on an option tag");
                             }
                             break;
                         case 'checked':
                             if ($node->tagName == 'input') {
                                 if ($expressionResult) {
                                     $node->setAttribute('checked', 'checked');
                                 } else {
                                     $node->removeAttribute('checked');
                                 }
                             } else {
                                 throw new ExpressionException("Can only use checked on an input tag");
                             }
                             break;
                         case 'disabled':
                             $disabledTags = array('input', 'button', 'select', 'textarea');
                             if (in_array($node->tagName, $disabledTags)) {
                                 if ($expressionResult) {
                                     $node->setAttribute('disabled', 'disabled');
                                 } else {
                                     $node->removeAttribute('disabled');
                                 }
                             } else {
                                 throw new ExpressionException("Can only use disabled on input, button, select and textarea tags");
                             }
                             break;
                         default:
                             // On non os-template spec attributes, do a simple str_replace with the evaluated value
                             $stringVal = htmlentities(ExpressionParser::stringValue($expressionResult), ENT_QUOTES, 'UTF-8');
                             $newAttrVal = str_replace($toReplace, $stringVal, $attr->value);
                             $node->setAttribute($attr->name, $newAttrVal);
                             break;
                     }
                 }
             }
         }
     }
     // if a repeat attribute was found, don't recurse on it's child nodes, the repeat handling already did that
     if (isset($node->childNodes) && $node->childNodes->length > 0) {
         $removeNodes = array();
         // recursive loop to all this node's children
         foreach ($node->childNodes as $childNode) {
             if (($removeNode = $this->parseNode($childNode)) !== false) {
                 $removeNodes[] = $removeNode;
             }
         }
         if (count($removeNodes)) {
             foreach ($removeNodes as $removeNode) {
                 $removeNode->parentNode->removeChild($removeNode);
             }
         }
     }
     return false;
 }
Example #8
0
 public function reproduce()
 {
     return new self($this->element->cloneNode(true));
 }
 /**
  * Resolves a path and removes the PLACEHOLDER-Tags
  * 
  * @param DOMNode $node 	// the result node on which $result will be appended
  * @param DOMNode $result	// the extracted node from the target DOM
  */
 private function resolvePath(DOMNode $root, DOMNode $result)
 {
     $curNode = $root->parentNode;
     $copy = $root->cloneNode(true);
     $appended = false;
     // bring result and root to the same level
     $sourceDOM = $this->currentDOM;
     $targetDOM = $this->currentTargetDOM;
     $subPath = null;
     while ($curNode) {
         // Search for a placeholder tag
         if ($curNode->nodeName != "PLACEHOLDER") {
             $curNode = $curNode->parentNode;
             $result = $result->parentNode;
             continue;
         }
         // get previous node
         $lastKnown = $curNode->parentNode;
         while ($result->parentNode && $result->parentNode->nodeName != $lastKnown->nodeName) {
             $result = $result->parentNode;
             if (!$subPath) {
                 $subPath = $targetDOM->importNode($result, false);
                 if (!$appended) {
                     $subPath->appendChild($copy);
                 }
                 $appended = true;
             } else {
                 $newPath = $targetDOM->importNode($result);
                 $newPath->appendChild($subPath);
                 $subPath = $newPath;
             }
         }
         if ($subPath) {
             $lastKnown->appendChild($subPath);
             $lastKnown->removeChild($curNode);
         }
         $curNode = $lastKnown;
         $curNode = $curNode->parentNode;
         $subPath = null;
     }
     if ($appended) {
         return $copy;
     }
     return $root;
 }
Example #10
0
 private function clonar(DOMNode $nd, $deep = false)
 {
     return $nd->cloneNode($deep);
 }