lapis
lapis copied to clipboard
etlua using content_for
Is there a way to leverage content_for in an etlua template the same way I would in a lapis Widget? For example, in a lapis widget I would do something like this to ensure my javascript loads in the same place and at the bottom of my page:
@content_for "javascript", ->
if @Post.Languages
script src: '/content/js/highlight.pack.js'
script ->
raw "var languages = #{util.to_json(@Post.Languages)};\n"
raw [[
hljs.configure({
languages: languages
});
hljs.initHighlightingOnLoad();
]]
Is there a way to do this in an etlua template?
do you have tried a lua expression inside your template?
I've tried a few things. I've found I can do the following at the beginning of my home etlua template:
<% function scripts() %>
<% if Post.languages then %>
<script src='/content/js/highlight.pack.js'></script>
<script>
var languages = <%- Post.languages %>;
hljs.configure({
languages: languages
});
hljs.initHighlightingOnLoad();
</script>
<% end %>
<% end %>
and then <% scripts() %>
at the end of my template to render what is in the scripts
method.
However, if I try <% content_for('javascript', scripts) %>
then I get the following error:
/usr/local/share/lua/5.1/lapis/html.lua:403: attempt to call field 'capture' (a nil value)
Traceback
stack traceback:
/usr/local/share/lua/5.1/lapis/html.lua:403: in function 'content_for'
[string "etlua"]:137: in function 'run'
/usr/local/share/lua/5.1/lapis/etlua.lua:153: in function 'thing'
/usr/local/share/lua/5.1/lapis/application.lua:250: in function 'write'
/usr/local/share/lua/5.1/lapis/application.lua:145: in function 'render'
/usr/local/share/lua/5.1/lapis/application.lua:418: in function </usr/local/share/lua/5.1/lapis/application.lua:412>
[C]: in function 'xpcall'
/usr/local/share/lua/5.1/lapis/application.lua:412: in function 'dispatch'
/usr/local/share/lua/5.1/lapis/nginx.lua:181: in function </usr/local/share/lua/5.1/lapis/nginx.lua:179>
It is possible to do <% content_for('javascript', 'Hello World!') %>
. If I convert scripts
to return a string with the same content, it just gets rendered as a raw string rather than html which I need.
@zach-binary did you find a solution for this in the end? I'm stuck with the same problem
I'm not sure what yall are trying to do with content_for
but I've only ever used that in layouts.
What you might be looking for is render
<% render("views.my_widget") %>
That will allow you to include any etlua template inside of another. If you need it to always appear in a specific area of the page, that's what layouts are for:
<% render("views.header") %>
<% render("views.nav") %>
<% content_for("inner") %>
<% render("views.footer") %>
content_for("inner")
returns whatever view the route is rendering. More Info. Hope that helps.
@kraftman unfortunately no, I don't maintain my lapis site anymore but looking back at the source code I wasn't able to find a workaround for this problem.
To clarify the problem, I wanted to be able to override parts of my layout with content inside an action. Think about elements in html that have to be in a fixed place, like the title tag. I wanted to be able to say, inside of the view, what the title should be.
@content_for
supports this according to the documentation
class MyView extends Widget
content: =>
@content_for "title", "This is the title of my page!"
@content_for "footer", ->
div class: "custom_footer", "The Footer"
class MyLayout extends Widget
content: =>
html ->
body ->
div class: "title", ->
@content_for "title"
@content_for "inner"
@content_for "footer"
This only works if you generate html using moonscript. I think the problem is that content_for
wasn't able to handle etlua templates for the second parameter. It assumes it's using the moonscript DSL to generate html and that's what results the error above.
I'm not sure if this was addressed or not.
To further clarify, I had scripts that were loaded on my home page but nowhere else, so I only wanted to load them there, but I wanted them at the bottom of the page, which I can only do in the layout, in order to prevent scripts from blocking the rendering of the page.
Thanks. I was hoping to do something similar, with with 'css' or 'js' in the layout.etlua, being replaced by the child templates, so that I'm not always loading large css files, and additional css files are in the header still, not spread randomly throughout depending on my render() blocks.