/**
* 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;
}