n:ifcontent does not work with empty tags
- bernhard
- Member | 51
Please see this fiddle:
https://fiddle.nette.org/latte/#…
This behaviour is a problem for me! The background is that I'm using the ProcessWire CMS and that CMS has the capability to directly edit fields on the frontend:
https://i.imgur.com/A0rEt88.gif
This is great, but that means that the CMS injects some additional markup into the template.
So a simple <h1>My Headline</h1>
gets something like
<h1><span class='pw-edit-copy'>My Headline</span><span class='pw-edit-orig'>My Headline</span></h1>
That means that n:ifcontent does not work on these tags, which is annoying. I can use n:if instead and make sure that I return the raw value of the field there, but that's also a little annoying.
Could there be something like n:iftext ? I'd love to build such a feature on my own, but unfortunately I didn't understand the docs regarding how to create custom tags :(
Any pointers would be great! Thx in advance!
- Infanticide0
- Member | 103
<span> in <p> is content, I expect this behaviour.
n:iftext would be very useful, probably easy to implement (copy&paste
n:ifcontent tag class with some changes)
<p n:ifcontent><span n:ifcontent></span></p>
<p n:ifcontent><span n:tag-if="$var">{$var}</span></p>
- bernhard
- Member | 51
Hey @Infanticide0 yeah I agree that markup is content – <svg> for example would also not be text, but markup and so the tag should appear. I just tried to explain my use case, but the headline is a little misleading I guess, sorry.
I'm quite experienced with PHP but it's not easy for me to copy/paste IfContentNode.php – I'd really appreciate a step by step tutorial. The docs unfortunately don't explain it well enough for me :(
- Infanticide0
- Member | 103
@bernhard
I've never done a Latte extension, it will probably need some tuning. Still
don't understand it completely.
Hope this helps.
template:
+)<p class="keep" n:ifcontent><a href="#"><u>latte</u></a><b></b></p><br>
-)<p class="hide" n:ifcontent></p><br>
+)<p class="keep" n:iftext><a href="#"><u>latte</u></a><b></b></p><br>
-)<p class="hide" n:iftext><a href="#"><u></u></a><b></b></p><br>
+)<p class="keep" n:iftext><a href="#"><u></u></a><b>nette</b></p><br>
output:
+)<p class="keep"><a href="#"><u>latte</u></a><b></b></p><br>
-)<br>
+)<p class="keep"><a href="#"><u>latte</u></a><b></b></p><br>
-)>nothing<<br>
+)<p class="keep"><a href="#"><u></u></a><b>nette</b></p><br>
class MyExtension extends \Latte\Extension
{
public function getTags(): array
{
return [
"n:iftext" => [IfTextNode::class, 'create']
];
}
}
/**
* n:iftext
*/
class IfTextNode extends StatementNode
{
public AreaNode $content;
public int $id;
public ElementNode $htmlElement;
/** @return \Generator<int, ?array, array{AreaNode, ?Tag}, static> */
public static function create(Tag $tag, TemplateParser $parser): \Generator
{
$node = $tag->node = new static;
$node->id = $parser->generateId();
[$node->content] = yield;
$node->htmlElement = $tag->htmlElement;
if (!$node->htmlElement->content) {
throw new CompileException("Unnecessary n:ifcontent on empty element <{$node->htmlElement->name}>", $tag->position);
}
return $node;
}
/** @return bool TRUE = keep, FALSE = remove */
private function iterateNode(Node $node): bool {
if($node instanceof TextNode)
return trim($node->content) !== "";
if(!($node instanceof ElementNode))
return true;
if($node->content instanceof Node) {
foreach ($node->content as $key => $value) {
if($this->iterateNode($value)) {
return true;
}
}
}
return false;
}
public function print(PrintContext $context): string
{
$saved = $this->htmlElement->content;
$keep = $this->iterateNode($this->htmlElement);
if($keep)
{
$this->htmlElement->content = new AuxiliaryNode(fn() => <<<XX
ob_start();
try {
{$saved->print($context)}
} finally {
\$ʟ_ift[$this->id] = rtrim(ob_get_flush()) === '';
}
XX);
return <<<XX
ob_start(fn() => '');
try {
{$this->content->print($context)}
} finally {
if (\$ʟ_ift[$this->id] ?? null) {
ob_end_clean();
} else {
echo ob_get_clean();
}
}
XX;
} else {
return "echo '>nothing<';"; // TODO ""
}
}
public function &getIterator(): \Generator
{
yield $this->content;
}
}
- David Grudl
- Nette Core | 8218
I think it is enough to copy the IfContentNode class and replace
rtrim(ob_get_flush())
with rtrim(strip_tags(ob_get_flush()))
- Infanticide0
- Member | 103
@bernhard
update your app config .neon file (usually common.neon)
latte:
strictTypes: yes
extensions:
- App\MyExtension // register your extension