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()) { if (this.isVoidElement && this.hasChildren()) {
throw new ComponentRenderException('A void html element cannot have children.') throw new ComponentRenderException('A void html element cannot have children.')
} }
return { return { writer ->
it << '<' writer << '<'
it << this.name writer << this.name
if (!this.attr.isEmpty()) { if (!this.attr.isEmpty()) {
it << ' ' writer << ' '
this.formatAttr(it) this.formatAttr(writer)
} }
it << '>' writer << '>'
if (this.hasChildren()) { if (this.hasChildren()) {
this.children.each { this.children.each {
def renderer = it.getRenderer(this) it.renderTo(writer, this)
renderer.call(it.child)
} }
} }
if (!this.isVoidElement) { if (!this.isVoidElement) {
it << '</' writer << '</'
it << this.name writer << this.name
it << '>' writer << '>'
} }
} }
} }

View File

@ -4,21 +4,28 @@ import groovy.lang.Closure;
import groowt.view.component.ComponentTemplate; import groowt.view.component.ComponentTemplate;
import groowt.view.component.ViewComponent; import groowt.view.component.ViewComponent;
import groowt.view.component.runtime.ComponentWriter; 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 { public class WebViewComponentChild {
private static final class ChildRenderClosure extends Closure<Void> { private static final class ChildRenderClosure extends Closure<Void> {
private final ViewComponent parent; 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); super(template, template);
this.parent = parent; this.parent = parent;
this.child = child; this.child = child;
this.writer = writer;
this.setDelegate(this.parent); this.setDelegate(this.parent);
this.setResolveStrategy(Closure.DELEGATE_FIRST); this.setResolveStrategy(Closure.DELEGATE_FIRST);
} }
@ -27,23 +34,19 @@ public class WebViewComponentChild {
return this.parent; return this.parent;
} }
public void doCall(ComponentWriter writer) { public void doCall() {
writer.append(Objects.requireNonNull(this.child)); this.writer.append(this.child);
}
public void doCall(ComponentWriter writer, Object givenChild) {
writer.append(givenChild);
} }
} }
private final ComponentTemplate template; private final ComponentTemplate template;
private final ComponentWriter out; private final ComponentWriter componentWriter;
private final Object child; private final Object child;
public WebViewComponentChild(ComponentTemplate template, ComponentWriter out, Object child) { public WebViewComponentChild(ComponentTemplate template, ComponentWriter componentWriter, Object child) {
this.template = template; this.template = template;
this.out = out; this.componentWriter = componentWriter;
this.child = child; this.child = child;
} }
@ -52,13 +55,14 @@ public class WebViewComponentChild {
} }
public void render(ViewComponent parent) { public void render(ViewComponent parent) {
final var cl = this.getRenderer(parent); new ChildRenderClosure(this.template, parent, this.componentWriter, this.child).call();
cl.call(this.child);
} }
public Closure<Void> getRenderer(ViewComponent parent) { public Writer renderTo(Writer out, ViewComponent parent) {
final var cl = new ChildRenderClosure(this.template, parent, null); final var componentWriter = new DefaultComponentWriter(out);
return cl.curry(this.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; package groowt.view.web.transpile.resolve;
import groowt.view.web.WebViewComponentBugError;
import groowt.view.web.compiler.WebViewComponentTemplateCompileUnit; import groowt.view.web.compiler.WebViewComponentTemplateCompileUnit;
import groowt.view.web.util.Either; import groowt.view.web.util.Either;
import org.codehaus.groovy.ast.ClassNode; import org.codehaus.groovy.ast.ClassNode;
@ -30,10 +29,12 @@ public class ModuleNodeComponentClassNodeResolver extends CachingComponentClassN
// try pre-pending package and asking for fqn // try pre-pending package and asking for fqn
final var packageName = this.moduleNode.getPackageName(); final var packageName = this.moduleNode.getPackageName();
final String fqn;
if (packageName.endsWith(".")) { 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); final var withPackage = this.getClassForFqn(fqn);
if (withPackage.isRight()) { if (withPackage.isRight()) {
return withPackage; return withPackage;

View File

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