/** * Determines if the arguments to the given element are valid based on * any validators attached to this CodeDefinition. * * @param $el the ElementNode to validate * @return true if the ElementNode's {option} and {param} are OK, false if they're not */ public function hasValidInputs(ElementNode $el) { if ($this->usesOption() && $this->optionValidator && !$this->optionValidator->validate($el->getAttribute())) { /* The option argument to $el does not pass the option validator. */ return false; } if (!$this->parseContent() && $this->bodyValidator) { /* We only evaluate the content if we're not parsing the content. */ $content = ""; foreach ($el->getChildren() as $child) { $content .= $child->getAsBBCode(); } if (!$this->bodyValidator->validate($content)) { /* The content of the element is not valid. */ return false; } } return true; }
/** * Accepts an ElementNode that is defined by this CodeDefinition and returns the HTML markup of the element. * This is a commonly overridden class for custom CodeDefinitions so that the content can be directly manipulated. * * @param el the element to return an html representation of * * @return the parsed html of this element (INCLUDING ITS CHILDREN) */ public function asHtml(ElementNode $el) { $html = $this->getReplacementText(); if ($this->usesOption()) { $html = str_ireplace('{option}', $el->getAttribute(), $html); } if ($this->parseContent()) { $content = ""; foreach ($el->getChildren() as $child) { $content .= $child->getAsHTML(); } } else { $content = ""; foreach ($el->getChildren() as $child) { $content .= $child->getAsBBCode(); } } $html = str_ireplace('{param}', $content, $html); return $html; }
/** * Constructs the document element node */ public function __construct() { parent::__construct(); $this->setTagName("Document"); }
protected function getContent(ElementNode $el) { if ($this->parseContent()) { $content = ""; foreach ($el->getChildren() as $child) { $content .= $child->getAsHTML(); } } else { $content = ""; foreach ($el->getChildren() as $child) { $content .= $child->getAsBBCode(); } } return $content; }
/** * Constructs the parse tree from a string of bbcode markup. * * @param string $str the bbcode markup to parse */ public function parse($str) { $this->reset(); $parent = $this->treeRoot; $tokenManager = new TokenManager($str); $nodeid = 1; $inTag = false; while ($tokenManager->hasCurrent()) { // tokens are either "[", "]" or a string that contains neither a opening bracket nor a closing bracket if ($inTag) { // this token should be a tag name // explode by = in case there's an attribute $pieces = explode('=', $tokenManager->getCurrent(), 2); // check if it's a closing tag if (substr($pieces[0], 0, 1) == "/") { $tagName = substr($pieces[0], 1); $closing = true; } else { $tagName = $pieces[0]; $closing = false; } if (($this->codeExists($tagName, isset($pieces[1])) || $closing && $this->codeExists($tagName, true)) && $tokenManager->hasNext() && $tokenManager->next() == "]") { if ($closing) { $closestParent = $parent->closestParentOfType($tagName); if ($closestParent != null && $closestParent->hasParent()) { // closing an element... move to this element's parent $parent->getCodeDefinition()->decrementCounter(); $parent = $closestParent->getParent(); $tokenManager->advance(); $tokenManager->advance(); $inTag = false; continue; } } else { // new element $el = new ElementNode(); $code = $this->getCode($tagName, isset($pieces[1])); $code->incrementCounter(); $el->setNestDepth($code->getCounter()); $el->setCodeDefinition($code); $el->setTagName($tagName); $el->setNodeId($nodeid++); if (isset($pieces[1])) { $el->setAttribute($pieces[1]); } $parent->addChild($el); $parent = $el; $tokenManager->advance(); $tokenManager->advance(); $inTag = false; continue; } } // the opening bracket that sent us in here was really just plain text $node = new TextNode("["); $node->setNodeId($nodeid++); $parent->addChild($node); $inTag = false; // treat this token as regular text, and let the next if...else structure handle it as regular text } if ($tokenManager->getCurrent() == "[") { $inTag = true; } else { $node = new TextNode($tokenManager->getCurrent()); $node->setNodeId($nodeid++); $parent->addChild($node); } $tokenManager->advance(); } }
/** * @param ElementNode|null $entryNode * @return string */ public function getHtml($entryNode = null) { $html = ''; $nodeList = null; if ($entryNode === null) { $nodeList = $this->nodeTree->childNodes; } else { if ($entryNode->hasChildren() === false) { return $html; } $nodeList = $entryNode->childNodes; } foreach ($nodeList as $node) { if ($node instanceof ElementNode === false) { $html .= $node->content; continue; } $tagStr = ($node->namespace !== null ? $node->namespace . ':' : '') . $node->tagName; $attrs = array(); foreach ($node->attributesNamed as $key => $val) { $attrs[] = $key . '="' . $val->value . '"'; } $attrStr = count($attrs) > 0 ? ' ' . implode(' ', $attrs) : ''; $html .= '<' . $tagStr . $attrStr . $node->tagExtension . ($node->tagType === ElementNode::TAG_SELF_CLOSING ? ' /' : '') . '>' . $node->content; if ($node->tagType === ElementNode::TAG_OPEN && $node->closed === true || $node->tagType === ElementNode::TAG_CLOSE) { $html .= $this->getHtml($node) . '</' . $tagStr . '>'; } } return $html; }