You are here

function _glossify_process_domnode in Glossify 6.3

Helper function to traverse DOM in predictable order.

Parameters

$domnode object: node object.

$dom object: DOM object.

$rx string: Regular expression to match.

$replacement: Text to substitute.

$excl_mode integer: Exclusion mode value.

$exclude_tags array: Tags to match for exclude / include functionality.

$only_first boolean: Flag to indicate whether to match all text occurances.

$next_node: Can be set to return actual next sibling in event of text placement.

$level: Tracks DOM hierarchy level for debugging.

Return value

boolean TRUE indicates text replacement was done.

1 call to _glossify_process_domnode()
_glossify_replace_terms_phpdom in ./glossify.module
Uses PHP's built in DOM extension if available. Adapted from http://stackoverflow.com/questions/3151064/find-and-replace-keywords-by-...

File

./glossify.module, line 568

Code

function _glossify_process_domnode($domnode, $dom, $rx, $replacement, $excl_mode, $exclude_tags, $only_first = FALSE, &$next_node = NULL, $level = 0) {
  $result = false;

  // Flag to indicate text replacement has happened.
  switch ($domnode->nodeType) {
    case XML_TEXT_NODE:
      $exclude_this = false;

      // Find real parent by looking at ancestors and skip anything with class="glossify_term".
      // In practice, if every element in the document had a "glossify_term" class manually added,
      // the upward traversal will still stop at the parent body element, which is created by
      // the loadHTML processing of the text.
      if (!empty($exclude_tags)) {
        $tmpnode = $domnode;
        $real_parent = '';
        while ($tmpnode->parentNode) {
          if ($tmpnode->parentNode
            ->hasAttributes()) {
            $parent_class = $tmpnode->parentNode->attributes
              ->getNamedItem('class');
            if (is_object($parent_class)) {
              if (preg_match('/glossify_term/', $parent_class->nodeValue) !== 0) {
                $tmpnode = $tmpnode->parentNode;
                continue;
              }
            }
          }
          $real_parent = $tmpnode->parentNode->nodeName;
          break;
        }

        // Test for exclusion / inclusion.
        if ($excl_mode == 0 && isset($exclude_tags[$real_parent]) || $excl_mode == 1 && !isset($exclude_tags[$real_parent])) {

          // Include
          $exclude_this = true;
        }
      }

      // Save next sibling before possible replaceChild. DO NOT CLONE the DOMnode!
      $next_sibling = $domnode->nextSibling;
      if (!$exclude_this) {
        $replaced = preg_replace($rx, $replacement, $domnode->wholeText, $only_first ? 1 : -1, $replace_done);
        if ($replace_done) {
          $new_node = $dom
            ->createDocumentFragment();
          $replaced = preg_replace('/&(?!amp;)/', '&', $replaced);
          if (@$new_node
            ->appendXML($replaced)) {
            $domnode->parentNode
              ->replaceChild($new_node, $domnode);
            $result = true;

            // Set return value of variable to indicate next actual sibling.
            $next_node = $next_sibling;
          }
        }
      }
      break;
    default:
      if ($domnode
        ->hasChildNodes()) {
        $child = $domnode->firstChild;
        while ($child) {

          // Exclude these elements (and hence all their children) here.
          if ($child->nodeType != XML_TEXT_NODE && ($child->nodeName == 'iframe' || $child->nodeName == 'object')) {
            continue;
          }
          else {
            $nxtnode = NULL;
            $result = _glossify_process_domnode($child, $dom, $rx, $replacement, $excl_mode, $exclude_tags, $only_first, $nxtnode, $level + 1) || $result;
            if ($result && $only_first) {
              break;
            }
          }
          if (is_object($nxtnode)) {
            $child = $nxtnode;
          }
          else {
            $child = $child->nextSibling;
          }
        }
      }
      break;
  }
  return $result;
}