Skip to content

Instantly share code, notes, and snippets.

@nedtwigg
Created March 22, 2023 18:03
Show Gist options
  • Save nedtwigg/21ed9275b4ba9cdb89e0029abc60e2e2 to your computer and use it in GitHub Desktop.
Save nedtwigg/21ed9275b4ba9cdb89e0029abc60e2e2 to your computer and use it in GitHub Desktop.
package common
import gg.jte.TemplateEngine
import gg.jte.TemplateOutput
// you need to define this interface yourself. It needs to have the render method,
// and you can add other methods if you want
interface JteModel {
fun render(engine: TemplateEngine, output: TemplateOutput)
}
// JteModelPlugin then generates code that looks like this
class main(
val title: String,
val description: String,
val content: gg.jte.Content,
) : common.JteModel {
override fun render(engine: TemplateEngine, output: TemplateOutput) {
engine.render("pages/main.jte", mapOf(
"title" to title,
"description" to description,
"content" to content,
), output)
}
}
class aboutUs(
) : common.JteModel {
override fun render(engine: TemplateEngine, output: TemplateOutput) {
engine.render("pages/Marketing/aboutUs.jte", mapOf(
), output)
}
}
// to pass data into the templates without arguments, you can use thread locals like this
object JteCtx {
class Module : Jooby.Module {
override fun configure(env: Env, conf: Config, binder: Binder) {
Multibinder.newSetBinder(binder, org.jooby.Renderer::class.java)
.addBinding()
.toInstance(Jte())
}
}
class Jte : org.jooby.Renderer {
override fun render(value: Any, ctx: org.jooby.Renderer.Context) {
if (value is JteModel) {
locals.set(ctx.locals())
val output = Utf8ByteOutput()
val codeResolver = DirectoryCodeResolver(Paths.get("src/main/jte"))
val templateEngine = TemplateEngine.create(codeResolver, ContentType.Html)
value.render(templateEngine, output)
val buffer = ByteArrayOutputStream()
output.writeTo { bytes, offset, length -> buffer.write(bytes, offset, length) }
ctx.type(MediaType.html).length(output.contentLength.toLong()).send(buffer.toByteArray())
}
}
}
val locals = ThreadLocal.withInitial { mapOf<String, Any>() }
@JvmStatic
fun fp(input: String): String {
val fingerprinted = locals.get().get(CustomAssets._PERMANENT) as Map<String, String>?
return if (fingerprinted == null) {
CustomAssets.ASSETS_FINGERPRINT_RAW + input
} else {
val fp = fingerprinted[input] ?: throw NoSuchElementException("No such fingerprinted $input")
CustomAssets.ASSETS + "/permanent/" + fp
}
}
@JvmStatic
fun style(fileset: String): RockerRaw {
var threadLocals = locals.get()
val linkTags =
(threadLocals.get(fileset + CustomAssets._STYLES)
?: throw NoSuchElementException(
"No such styles $fileset, available: $threadLocals.keys"))
as String
return RockerRaw.raw(linkTags)
}
@JvmStatic
fun script(fileset: String): RockerRaw {
var threadLocals = locals.get()
val linkTags =
(threadLocals.get(fileset + CustomAssets._SCRIPTS)
?: throw NoSuchElementException(
"No such scripts $fileset, available: ${threadLocals.keys}"))
as String
return RockerRaw.raw(linkTags)
}
}
@nedtwigg
Copy link
Author

This is example output from JteModelPlugin which is listed at this gist.

casid/jte#205 for further context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment