How to rendering partials within a partials in middleman - ruby

I have some Haml partials, many of which contain the boilerplate
.container
.row
.col-lg-12
When I try to abstract that out ala = partial "site_section", I get:
syntax error, unexpected keyword_end, expecting end-of-input end;end;end;end
I'm using ruby 2.2.2.
How do I render a Haml partial within a Haml partial in Middleman?
Thanks
update
This is apparently some kind of special case dealing with my partial (above). I have other partials-within-partials rendering just fine.
update
With respect to this this repo, the layout would actually be:
_site_section:
.container
.row
.col-lg-12
_nested_section:
= partial "site_section"
MOAR (nested) HAML
index.haml:
=partial "nested_section"

Because of the way HAML works the following is invalid:
= partial "site_section"
MOAR (nested) HAML
If you want to add more text or HAML then you can achieve it for example by putting the text at the same level of the previous line
= partial "site_section"
MOAR (nested) HAML
Or nesting it within a div:
= partial "site_section"
.more
MOAR (nested) HAML
So If what you are trying to do is to nest extra HAML to the output of the site_section partial, then you have to put the nested extra HAML in the nested partial:
.container
.row
.col-lg-12
= partial 'nested_stuff'
= partial 'nested_stuff'
Hope this helps, I updated the repo with the working example.

Related

How to output data from Yaml variables (written in markdown) into an HTML Haml file?

In a Yaml data file aaa.yml I have:
yyy: |
[foo](http://example.com) bar.
I want to pull this data from a Haml file (zzz.html.haml).
1. If I do zzz.html.haml:
%p
= data.aaa.yyy
Middleman renders zzz.html:
<p> [foo](http://example.com) bar</p>
2. If I do:
%p
:markdown
= data.aaa.yyy
Middleman renders:
<p>= data.aaa.yyy</p>
How can I make it render:
<p>foo bar</p>
?
You have a string that contains markdown, and you want to render that markdown and include the result in your output.
One way would be to use the Haml :markdown filter. You can’t use normal Haml syntax inside a filter (like you’ve tried), but you can use interpolation inside #{...}, so you could do
:markdown
#{data.aaa.yyy}
A better way, if the string is a standalone chunk, might be to create a helper method that renders markdown, and call that.
Wherever you have your helpers add something like:
def markdown s
# I'm using kramdown here, but you can use whatever processor you prefer.
Kramdown::Document.new(s).to_html
end
Then in your Haml:
= markdown(data.aaa.yyy)
Yay! Turns out there's this helper, which was already in my config.rb but didn't work by itself:
def markdown(text)
Tilt['markdown'].new { text }.render
end
When I installed this helper (from #matt's answer) with the first one:
def markdown s
Kramdown::Document.new(s).to_html
end
Then = markdown(foo.bar) worked, which made my day!! :D

Rendering nested HAML templates with blocks as parameters

I am currently using an helper method to render a HAML nested partial/template in Sinatra. For the sake of simplicity I just wrote a minimal example but of course my code is much larger. The point is that I want to factorise inner_template instead of copy/pasting everywhere:
require 'sinatra'
require 'haml'
helpers do
def inner_template(&block)
haml_tag('div', :class => 'title', &block)
end
end
get '/' do
haml :index
end
__END__
## layout
%html
= yield
## index
%div.div1
- inner_template do
%span Item 1
- inner_template do
%span Item 2
This correctly renders the page like this:
<html>
<div class='div1'>
<div class='title'>
<span>Item 1</span>
</div>
<div class='title'>
<span>Item 2</span>
</div>
</div>
</html>
The problem is that my real life inner_template method has a consequent number of tags, and I find it quite inelegant (and cumbersome when I must edit it). I also want to keep all the inner-most blocks (my items) on the same page, otherwise I'll end up with dozens of small files and it will be a headache to maintain that.
I am under the impression that, since I can use an helper method which only uses haml_tag methods, there must be a way to make everything work in pure HAML. But I cannot figure out how to do it properly. For instance if I just try the obvious way:
require 'sinatra'
require 'haml'
get '/' do
haml :index
end
__END__
## layout
%html
= yield
## index
%div.div1
= haml :inner_template do
%span Item 1
= haml :inner_template do
%span Item 2
## inner_template
%div.title
= yield
This doesn't work, the inner_template is rendered after its "inner" block (as to what exactly yields the value 1, I do not know):
<html>
<div class='div1'>
<span>Item 1</span>
<div class='title'>
1
</div>
<span>Item 2</span>
<div class='title'>
1
</div>
</div>
</html>
I tried a very long list of hacks, I also tried to use content_for or similar solutions (which only seem to apply to old versions of Sinatra anyway), but I cannot find examples that match my approach (which could be a hint that it's just not possible). And it looks like the block is not passed at all to the HAML renderer when calling haml.
So I would like to know whether or not this can be done in pure HAML (and how, or why not)?

making a page break when pdf generated with wicked_pdf

sample.erb.html
<p>Page 1</p1>
<p>Page 2</p2>
So, everything after "Page 1" I want to print on the 2nd page.
How can I do this?
There's one solution in SO but it didn't work for me.
For example, in case of Prawn, it has a nice feature called start_new_page
in your css
p{page-break-after: always;}
Update
After a couple of questions, I will expand my answer and how I use it in my apps.
1 Some times, the wickedpdf helpers doesn't work, so I add an initializer
_config/initializers/wiked_pdf.rb_
module WickedPdfHelper
def wicked_pdf_stylesheet_link_tag(*sources)
sources.collect { |source|
"<style type='text/css'>#{Rails.application.assets.find_asset("#{source}.css")}</style>"
}.join("\n").gsub(/url\(['"](.+)['"]\)(.+)/,%[url("#{wicked_pdf_image_location("\\1")}")\\2]).html_safe
end
def wicked_pdf_image_tag(img, options={})
image_tag wicked_pdf_image_location(img), options
end
def wicked_pdf_image_location(img)
"file://#{Rails.root.join('app', 'assets', 'images', img)}"
end
def wicked_pdf_javascript_src_tag(source)
"<script type='text/javascript'>#{Rails.application.assets.find_asset("#{source}.js").body}</script>"
end
def wicked_pdf_javascript_include_tag(*sources)
sources.collect{ |source| wicked_pdf_javascript_src_tag(source) }.join("\n").html_safe
end
WickedPdf.config = {
}
end
2 In application controller create a config method with the general config params
_app/controllers/application_controller.rb_
class ApplicationController < ActionController::Base
def pdf_config
WickedPdf.config = {
:wkhtmltopdf => "/usr/local/bin/wkhtmltopdf",
:orientation => 'Landscape',
:layout => "pdf.html",
:footer => {
:left => "Rectores Lideres Transformadores",
#:left => "#{Entidad.find(#current_user.entidad).nombre}",
:right => "#{Time.now}",
:font_size => 5,
:center => '[page] de [topage]'
},
:disposition => 'attachment'
}
end
end
3 Create a common layout for all of your pdf files. Here I use my application css in order to maintain the same look and feel of web page in pdf reports, only I have to use the same classes and id's
app/layouts/pdf.html.erb
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<%= wicked_pdf_stylesheet_link_tag "application" %> ----- HERE YOUR APPLICATION CSS -----
</head>
<div id="content">
<%= yield %>
</div>
</body>
</html>
4 Add pdf redirection in your controllers
_app/controllers/users_controller.rb_
def index
#users = User.all
respond_to do |format|
format.pdf do
pdf_config
render :pdf => "filename"
end
end
end
5 Now, in your css, choose which html id is the page brake
#brake{page-break-after: always;}
I had the same problem and I discovered something that might help. This was my page break CSS code:
.page-break {
display: block;
clear: both;
page-break-after: always;
}
This didn't work because of TWO reasons:
I. In one of the SASS imported file I had this line of code:
html, body
overflow-x: hidden !important
II. The other problem was bootstrap
#import "bootstrap"
It looks like because of the float: left in:
.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
float: left;
}
the page break is no longer working. So, just add this after you import bootstrap.
.col-xs-1, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9, .col-xs-10, .col-xs-11, .col-xs-12 {
float: initial !important;
}
For anyone still having this problem but none of these answers, like for me, just aren't working:
I gave up on using CSS to fix the page breaks and instead generated 2 pdfs and merged them together and used the resulting file instead, that way there is no possible way for a page break to not exist.
To merge files, an array of pdf file names, I used
system("pdftk #{files.join(' ')} cat output merged_file_name.pdf")
Update
I don't remember where I generated 2 pdfs but I did manage to do these page breaks in a single pdf file by manually counting the pixels in the .html.erb files.
<% #pixel_height = 0 %> and <% #page_height = 980 %>. view the pdf as html to see how many pixels each section takes up. Add to #pixel_height.
In places a page break would make sense, I check #pixel_height + 20 >= #page_height (20 being the number of pixels a <tr> took up for most of our pdfs) and rendering a manual page break and resetting #pixel_height to 0. The manual page break closes all the html tags, adds a 0 pixel tall div with a page-break-after: always, and opens the html tags again.
I've only had 2 problems with this method:
If some text in the pdf is too long, it will line-break and throw off the #pixel_count causing a automatic page break in an odd spot and a manual page break also in an odd spot
WickedPdf is slow
To combat these 2 issues, we've been slowly migrating our pdfs to Prawn, specifically Prawn::Table. It is much faster and it calculates the height of each row before it draws the pdf so page breaks are more predictable and consistent
One quick method is to use below HTML:
<div style="page-break-before: always;"></div>
From this line onwards HTML Content will come in next page

Selectively using yield_content in Padrino application.haml template

In a Haml based Padrino solution I have an application.haml like this:
!!!
%html
%head
%title "blah"
%body
#header
= yield_content :headcontent
#container
...
For :headcontent, in my page (e.g. index.haml) I have
- content_for :headcontent do
#headcontent
%h2= "Index header stuff"
#content
...
What I want to do is make it so that content pages like index.haml can optionally specify - content for :headcontent. That is I want application.haml to contain some default :headcontent that only is rendered if a page does not do - content for :headcontent.
How do I do this?
In your main file, you should be able to use content_for?, like this:
- if content_for?(:headcontent)
= yield_content :headcontent
- else
something else

How to structure a layout template in Haml

I have a web page that uses Haml for layouts. "layout.haml" is a separate layout file which is used when rendering any actual Haml page.
layout.haml looks something like:
-# layout.haml
!!! XML
!!!
%html
%head
...
%body
...
#content= yield
This is of course already in the document's <body> so manipulating things in the header is not directly possible. For instance <title> is changed via #title. A bigger problem is the fact that every page-specific JavaScript needs to be loaded in the body. Moreover, layout.haml already contains JavaScript, so jQuery is usually instantiated multiple times.
Are there any suggestions for a better template structure?
This solution is for Ruby on Rails only:
You can use yield(:location) and the content_for(:location) methods. "Using the content_for Method" has more information.
layout.haml:
!!!
%html
%head
%title= yield(:title)
= yield(:head)
%body
= yield
view.haml:
- content_for(:title, 'My title')
- content_for(:head) do
= javascript_include_tag :foo
%h1 My view!
I use partials:
!!!
%html
= partial('trst_sys/shared/html-head')
%body{:id => "srv",:'data-lang' => current_lang}
#main.wrap
%header#header
= partial('trst_sys/shared/header')
%nav#menu
= partial('trst_sys/shared/menu')
%section#content
%article#xhr_content
= yield
%article#xhr_msg.hidden
%section#sidebar
= partial('trst_sys/shared/sidebar')
%section#main_footer.wrap
%footer#footer.wrap
= partial('trst_sys/shared/footer')

Resources