/** * Finish invocation. * @return Texy\HtmlElement|FALSE */ public function solve(Texy\HandlerInvocation $invocation, $content, Texy\Modifier $mod = NULL) { $texy = $this->texy; // find hard linebreaks if ($texy->mergeLines) { // .... // ... => \r means break line $content = Regexp::replace($content, '#\\n +(?=\\S)#', "\r"); } else { $content = Regexp::replace($content, '#\\n#', "\r"); } $el = new Texy\HtmlElement('p'); $el->parseLine($texy, $content); $content = $el->getText(); // string // check content type // block contains block tag if (strpos($content, $texy::CONTENT_BLOCK) !== FALSE) { $el->setName(NULL); // ignores modifier! // block contains text (protected) } elseif (strpos($content, $texy::CONTENT_TEXTUAL) !== FALSE) { // leave element p // block contains text } elseif (preg_match('#[^\\s' . Texy\Patterns::MARK . ']#u', $content)) { // leave element p // block contains only replaced element } elseif (strpos($content, $texy::CONTENT_REPLACED) !== FALSE) { $el->setName($texy->nontextParagraph); // block contains only markup tags or spaces or nothing } else { // if {ignoreEmptyStuff} return FALSE; if (!$mod) { $el->setName(NULL); } } if ($el->getName()) { // apply modifier if ($mod) { $mod->decorate($texy, $el); } // add <br /> if (strpos($content, "\r") !== FALSE) { $key = $texy->protect('<br />', $texy::CONTENT_REPLACED); $content = str_replace("\r", $key, $content); } } $content = strtr($content, "\r\n", ' '); $el->setText($content); return $el; }
/** * Callback for:. * * 1) .... .(title)[class]{style}> * 2) .... * + ... * + ... * 3) .... * * @return HtmlElement|FALSE */ public function patternList(BlockParser $parser, array $matches) { list(, $mMod, $mBullet) = $matches; // [1] => .(title)[class]{style}<> // [2] => bullet * + - 1) a) A) IV) $el = new HtmlElement(); $bullet = $min = NULL; foreach ($this->bullets as $type => $desc) { if (preg_match('#' . $desc[0] . '#Au', $mBullet)) { $bullet = isset($desc[3]) ? $desc[3] : $desc[0]; $min = isset($desc[3]) ? 2 : 1; $el->setName($desc[1] ? 'ol' : 'ul'); $el->attrs['style']['list-style-type'] = $desc[2]; if ($desc[1]) { // ol if ($type[0] === '1' && (int) $mBullet > 1) { $el->attrs['start'] = (int) $mBullet; } elseif ($type[0] === 'a' && $mBullet[0] > 'a') { $el->attrs['start'] = ord($mBullet[0]) - 96; } elseif ($type[0] === 'A' && $mBullet[0] > 'A') { $el->attrs['start'] = ord($mBullet[0]) - 64; } } break; } } $mod = new Modifier($mMod); $mod->decorate($this->texy, $el); $parser->moveBackward(1); while ($elItem = $this->patternItem($parser, $bullet, FALSE, 'li')) { $el->add($elItem); } if ($el->count() < $min) { return FALSE; } // event listener $this->texy->invokeHandlers('afterList', [$parser, $el, $mod]); return $el; }
/** * Finish invocation. * @return HtmlElement|string|FALSE */ public function solveTag(Texy\HandlerInvocation $invocation, HtmlElement $el, $isStart, $forceEmpty = NULL) { $texy = $this->texy; // tag & attibutes $allowedTags = $texy->allowedTags; // speed-up if (!$allowedTags) { return FALSE; // all tags are disabled } // convert case $name = $el->getName(); $lower = strtolower($name); if (isset($texy->dtd[$lower]) || $name === strtoupper($name)) { // complete UPPER convert to lower $name = $lower; $el->setName($name); } if (is_array($allowedTags)) { if (!isset($allowedTags[$name])) { return FALSE; } $allowedAttrs = $allowedTags[$name]; // allowed attrs } else { // allowedTags === Texy\Texy::ALL if ($forceEmpty) { $el->setName($name, TRUE); } $allowedAttrs = $texy::ALL; // all attrs are allowed } // end tag? we are finished if (!$isStart) { return $el; } $elAttrs =& $el->attrs; // process attributes if (!$allowedAttrs) { $elAttrs = []; } elseif (is_array($allowedAttrs)) { // skip disabled $allowedAttrs = array_flip($allowedAttrs); foreach ($elAttrs as $key => $foo) { if (!isset($allowedAttrs[$key])) { unset($elAttrs[$key]); } } } // apply allowedClasses $tmp = $texy->_classes; // speed-up if (isset($elAttrs['class'])) { if (is_array($tmp)) { $elAttrs['class'] = explode(' ', $elAttrs['class']); foreach ($elAttrs['class'] as $key => $value) { if (!isset($tmp[$value])) { unset($elAttrs['class'][$key]); // id & class are case-sensitive } } } elseif ($tmp !== $texy::ALL) { $elAttrs['class'] = NULL; } } // apply allowedClasses for ID if (isset($elAttrs['id'])) { if (is_array($tmp)) { if (!isset($tmp['#' . $elAttrs['id']])) { $elAttrs['id'] = NULL; } } elseif ($tmp !== $texy::ALL) { $elAttrs['id'] = NULL; } } // apply allowedStyles if (isset($elAttrs['style'])) { $tmp = $texy->_styles; // speed-up if (is_array($tmp)) { $styles = explode(';', $elAttrs['style']); $elAttrs['style'] = NULL; foreach ($styles as $value) { $pair = explode(':', $value, 2); $prop = trim($pair[0]); if (isset($pair[1]) && isset($tmp[strtolower($prop)])) { // CSS is case-insensitive $elAttrs['style'][$prop] = $pair[1]; } } } elseif ($tmp !== $texy::ALL) { $elAttrs['style'] = NULL; } } foreach (['src', 'href', 'name', 'id'] as $attr) { if (isset($elAttrs[$attr])) { $elAttrs[$attr] = is_string($elAttrs[$attr]) ? trim($elAttrs[$attr]) : ''; if ($elAttrs[$attr] === '') { unset($elAttrs[$attr]); } } } if ($name === 'img') { if (!isset($elAttrs['src']) || !$texy->checkURL($elAttrs['src'], $texy::FILTER_IMAGE)) { return FALSE; } $texy->summary['images'][] = $elAttrs['src']; } elseif ($name === 'a') { if (!isset($elAttrs['href']) && !isset($elAttrs['name']) && !isset($elAttrs['id'])) { return FALSE; } if (isset($elAttrs['href'])) { if ($texy->linkModule->forceNoFollow && strpos($elAttrs['href'], '//') !== FALSE) { if (isset($elAttrs['rel'])) { $elAttrs['rel'] = (array) $elAttrs['rel']; } $elAttrs['rel'][] = 'nofollow'; } if (!$texy->checkURL($elAttrs['href'], $texy::FILTER_ANCHOR)) { return FALSE; } $texy->summary['links'][] = $elAttrs['href']; } } elseif (preg_match('#^h[1-6]#i', $name)) { $texy->headingModule->TOC[] = ['el' => $el, 'level' => (int) substr($name, 1), 'type' => 'html']; } $el->validateAttrs($texy->dtd); return $el; }