Middleman: choosing information from data files in frontmatter - ruby

I am using Middleman static page generator and I would like to pull information from data files based on selection made in frontmatter.
Example
I have data file located at data/cta.yaml with different variants of Call-To-Action text that can be repeated on various pages, meaning that each CTA text can be used on more than one page.
data/cta.yaml:
basic: This is default CTA
special: Something special here
other: Some other CTA
Then I have layout.erb:
<body>
<%= yield %>
<p class="cta">No data yet</p>
</body>
And test.html.erb:
---
title: Some page for testing
cta: It works with layout if I do not reference 'data/cta.yaml'
---
Some page content.
If I want to use, let's say, first CTA text, I could use <p class="cta"><%= data.cta.basic %></p> either in layout.erb layout file or remove it from layout and move it directly to the end of test.html.erb template file. Or, I could drop data file altogether and simply type CTA text for each page in frontmatter. However, I would prefer to keep CTA text in data file and all HTML in layout.erb and then be able to "choose" information from cta.yaml in test.html.erb frontmatter.
I tried to change
<p class="cta"><%= data.cta.basic %></p>
in layout.erb to
<p class="cta"><%= current_page.data.cta %></p>
and then in test.html.erb frontmatter:
---
title: Some page for testing
cta: data.cta.basic
---
but that resulted in verbatim data.cta.basic text instead of "This is default CTA" from cta.yaml data file.
Question
Is it possible at all to use frontmatter to select which text from data file should be used for given page?

As I mentioned in my comment, the frontmatter is parsed before the ERB, that’s the reason you are seeing data.cta.basic instead of the correct cta.
You could add a helper to achieve this though.
Here’s my helper
module CtaHelpers
def page_cta
cta = current_page.data.cta
data.cta.send(cta)
end
end
Here’s my test.html.erb file:
---
cta: special
---
<p class="cta"><%= page_cta %></p>
The test.html.erb file is calling the helper that determines from the Frontmatter which CTA to use, so the output is:
Something special here

Related

Phoenix different title per page with root module

This question is similar to (but not an exact duplicate of) Phoenix Framework - page titles per route.
Ideally, i want to create titles like in the described question, but I am using a root layout since my project uses Phoenix LiveView. The HTML skeleton including the head and title HTML tag are part of the root template (root.html.eex). The app template extends on that from my understanding. I implemented the code from the above question
<title>
<%= if Kernel.function_exported?(#view_module, :title, 2) do %>
<%= #view_module.title(Phoenix.Controller.action_name(#conn), assigns) %> - StHub
<% else %>
StHub
<% end %>
</title>
and created a title function inside of my specific page view
defmodule StHubWeb.WowsView do
use StHubWeb, :view
def title(_action, _assigns) do
"Dashboard"
end
end
but the else branch of the code is triggered. Upon further inspection, I think that the issue is with using a root template, because the #view_module while rendering the root template is StHubWeb.LayoutView, and only inside of the LayoutView/app.html.eex template, the #view_module is my actual view (StHubWeb.WowsView).
I am not sure how to solve this other than removing the root template, but then my LiveView will have to contain the entire HTML skeleton all the time.
Maybe there is a way for me to define a title function in my LayoutView that will grab the title from StHubWeb.WowsView, but I am not sure how to do that.
Thanks for the help!

How to call js and css files inside a html.erb file

I'm quite new to Ruby and ERB and for this case I'm using only Ruby and not rails.
E:\ruby
-app.rb
-plan.html.erb
-check.css
-track.js [js + jquery framework]
Inside app.rb I've the following lines
text = File.open(("final.html"), "w+")
text.puts ERB.new(File.read("plan.html.erb")).result binding
I'm not sure how to call the .js and .css files inside the .html.erb file. Kindly let me know if I've to post the .html.erb file in case that would be helpful to debug further, thanks.
You can include the JavaScript in the .html.erb file in the same way you load the text file. The simplest (code wise) solution is doing something along the lines of this:
plan.html.erb
<script>
<%= File.read('some/file.js') %>
</script>
However if you are expecting a <script src="some/file.js"></script> as result you'll have to create your own helper or use an existing one from some light weight web framework. A simple example might be:
lib/html_helpers.rb
require 'builder'
module HtmlHelpers
def javascript_include_tag(path)
Builder::XmlMarkup.new.script('', src: path)
#=> %{<script src="#{html_escaped_path}"></script>}
end
end
plan.html.erb
<% require 'html_helpers' %>
<% include HtmlHelpers %>
<%= javascript_include_tag('some/file.js') %>
Keep in mind that the first solution doesn't escape any HTML characters. Meaning that if your script contains </script> everything following that tag will be interpreted as HTML.

Middleman Blog: Custom layout not loading

In Middleman, I am trying to set up a blog site, using custom layout for the blog. My problem is that the main layout is loading, but the blog layout for my articles is not. The article files are being served in with their plain body.
In source/layouts/ I have two files: layout.erb and article_layout.erb.
My intent is to use article_layout.erb for my blog articles.
In config.rb I have the following:
activate :blog do |blog|
blog.sources = "articles/{category}/{year}-{month}-{day}-{title}.html"
blog.layout = "article_layout"
end
I have also tried moving article_layout.erb to source/articles/ as well as prepending the config.rb file like this: blog.layout = "layouts/article_layout"
Another failed approach is to comment out the above option and configure the layout by adding this line instead: page "/articles/*", layout: "article_layout".
So far none of these approach show a difference. Since the default layout is not being rendered I would expect some sort of error message if the path to the layout cannot be found, but nothing shows up.
I managed to replicate your problem with my own Middleman blog setup.
The docs are unclear on this because there is a broken link in the layout section of Blogging.
You need to use the nested layout feature of Middleman and wrap your custom layout in:
<% wrap_layout :layout do %>
<% end %>
So your article_layout.erb would look something like this:
<% wrap_layout :layout do %>
<div class="article-container">
<article>
<h2 class="article-title"><%= current_page.title %></h2>
<%= yield %>
</article>
</div>
<% end %>
And keep your custom layout in the source/layouts folder.
Here are the docs for Nested Layouts for your reference.
I hope this helps.

Frontmatter in Padrino

In Middleman, there is a feature called frontmatter. Basically, you can put some YAML in front of your view and access it in the view and the layout like this:
---
my_list:
- one
- two
- three
---
<h1>List</h1>
<ol>
<% current_page.data.my_list.each do |f| %>
<li><%= f %></li>
<% end %>
</ol>
Is there a similar thing in Padrino?
Such feature does not come with padrino, where you usually would let these values be filled by your controllers.
Depending on your use case, you might use the content_for output helper (http://www.padrinorb.com/guides/application-helpers).
This might help if e.g. want to define the title (as in html/head/title) -- which is usually set by the layout template -- in the "nested" template of your page.

inserting blocks of text in haml

In my Jekyll blog I use the include tag to put the contents of a file into the document. However if I attempt to do this with a HAML based document the indentation of the included text is wrong. :preserve does not work because it requires indentation. Is there a way to specify a block of text without depending on indentation?
%html
%body
- preserve do
<strong>included text from file</strong>
- end
It seems that in current version of Haml :text filter was removed. Now you can use :plain filter. No processing is performed for the text inside this block. You can paste multiline blocks of text or HTML code there. HTML will appear on the page unescaped.
:plain
Some text <b>or HTML</b>.
For text, use filters:
:text
some text
:erb
<%= render :partial ... %>
http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#filters

Resources