Working on IntrinsicHtml and nested render closures.

This commit is contained in:
JesseBrault0709 2024-05-10 20:24:07 +02:00
parent 6ee903bde0
commit 5b1a1bcdec
5 changed files with 42 additions and 34 deletions

View File

@ -0,0 +1,4 @@
---
import groowt.view.web.lib.Echo
---
<Echo greeting="Hello!"><p>${context}</p></Echo>

View File

@ -56,24 +56,23 @@ class IntrinsicHtml extends DelegatingWebViewComponent implements WithHtml {
if (this.isVoidElement && this.hasChildren()) {
throw new ComponentRenderException('A void html element cannot have children.')
}
return {
it << '<'
it << this.name
return { writer ->
writer << '<'
writer << this.name
if (!this.attr.isEmpty()) {
it << ' '
this.formatAttr(it)
writer << ' '
this.formatAttr(writer)
}
it << '>'
writer << '>'
if (this.hasChildren()) {
this.children.each {
def renderer = it.getRenderer(this)
renderer.call(it.child)
it.renderTo(writer, this)
}
}
if (!this.isVoidElement) {
it << '</'
it << this.name
it << '>'
writer << '</'
writer << this.name
writer << '>'
}
}
}

View File

@ -4,21 +4,28 @@ import groovy.lang.Closure;
import groowt.view.component.ComponentTemplate;
import groowt.view.component.ViewComponent;
import groowt.view.component.runtime.ComponentWriter;
import org.jetbrains.annotations.Nullable;
import groowt.view.component.runtime.DefaultComponentWriter;
import java.util.Objects;
import java.io.Writer;
public class WebViewComponentChild {
private static final class ChildRenderClosure extends Closure<Void> {
private final ViewComponent parent;
private final @Nullable Object child;
private final Object child;
private final ComponentWriter writer;
public ChildRenderClosure(ComponentTemplate template, ViewComponent parent, @Nullable Object child) {
public ChildRenderClosure(
ComponentTemplate template,
ViewComponent parent,
ComponentWriter writer,
Object child
) {
super(template, template);
this.parent = parent;
this.child = child;
this.writer = writer;
this.setDelegate(this.parent);
this.setResolveStrategy(Closure.DELEGATE_FIRST);
}
@ -27,23 +34,19 @@ public class WebViewComponentChild {
return this.parent;
}
public void doCall(ComponentWriter writer) {
writer.append(Objects.requireNonNull(this.child));
}
public void doCall(ComponentWriter writer, Object givenChild) {
writer.append(givenChild);
public void doCall() {
this.writer.append(this.child);
}
}
private final ComponentTemplate template;
private final ComponentWriter out;
private final ComponentWriter componentWriter;
private final Object child;
public WebViewComponentChild(ComponentTemplate template, ComponentWriter out, Object child) {
public WebViewComponentChild(ComponentTemplate template, ComponentWriter componentWriter, Object child) {
this.template = template;
this.out = out;
this.componentWriter = componentWriter;
this.child = child;
}
@ -52,13 +55,14 @@ public class WebViewComponentChild {
}
public void render(ViewComponent parent) {
final var cl = this.getRenderer(parent);
cl.call(this.child);
new ChildRenderClosure(this.template, parent, this.componentWriter, this.child).call();
}
public Closure<Void> getRenderer(ViewComponent parent) {
final var cl = new ChildRenderClosure(this.template, parent, null);
return cl.curry(this.out);
public Writer renderTo(Writer out, ViewComponent parent) {
final var componentWriter = new DefaultComponentWriter(out);
final var childRenderClosure = new ChildRenderClosure(this.template, parent, componentWriter, this.child);
childRenderClosure.call();
return out;
}
}

View File

@ -1,6 +1,5 @@
package groowt.view.web.transpile.resolve;
import groowt.view.web.WebViewComponentBugError;
import groowt.view.web.compiler.WebViewComponentTemplateCompileUnit;
import groowt.view.web.util.Either;
import org.codehaus.groovy.ast.ClassNode;
@ -30,10 +29,12 @@ public class ModuleNodeComponentClassNodeResolver extends CachingComponentClassN
// try pre-pending package and asking for fqn
final var packageName = this.moduleNode.getPackageName();
final String fqn;
if (packageName.endsWith(".")) {
throw new WebViewComponentBugError(new IllegalStateException("Package name illegally ends with '.'"));
fqn = this.moduleNode + nameWithoutPackage;
} else {
fqn = this.moduleNode.getPackageName() + "." + nameWithoutPackage;
}
final var fqn = this.moduleNode.getPackageName() + "." + nameWithoutPackage;
final var withPackage = this.getClassForFqn(fqn);
if (withPackage.isRight()) {
return withPackage;

View File

@ -22,8 +22,8 @@ class IntrinsicHtmlTests extends AbstractWebViewComponentTests {
@Test
@Disabled('Until we figure out nested closure delegates')
void canUseEchoAttrProperty() {
this.doTest('<Echo greeting="Hello!"><p>$greeting</p></Echo>', '<p>Hello!</p>')
void canUseEchoAttrPropertyViaContext() {
this.doTest('<Echo greeting="Hello!"><p>${context}</p></Echo>', '<p>Hello!</p>')
}
}