Haml: Control whitespace around text - ruby-on-rails

In my Rails template, I'd like to accomplish final HTML to this effect using HAML:
I will first link somewhere, then render this half of the sentence if a condition is met
The template that comes close:
I will first
= link_to 'link somewhere', 'http://example.com'
- if #condition
, then render this half of the sentence if a condition is met
You may, however, note that this produces a space between the link and the comma. Is there any practical way to avoid this whitespace? I know there's syntax to remove whitespace around tags, but can this same syntax be applied to just text? I really don't like the solution of extra markup to accomplish this.

A better way to do this has been introduced via Haml's helpers:
surround
= surround '(', ')' do
%a{:href => "food"} chicken
Produces:
(<a href='food'>chicken</a>)
succeed:
click
= succeed '.' do
%a{:href=>"thing"} here
Produces:
click
<a href='thing'>here</a>.
precede:
= precede '*' do
%span.small Not really
Produces:
*<span class='small'>Not really</span>
To answer the original question:
I will first
= succeed ',' do
= link_to 'link somewhere', 'http://example.com'
- if #condition
then render this half of the sentence if a condition is met
Produces:
I will first
link somewhere,
then render this half of the sentence if a condition is met

You can also do this using Haml's "trim whitespace" modifier. Inserting > after a Haml declaration will prevent whitespace from being added around it:
I will first
%a{:href => 'http://example.com'}> link somewhere
- if #condition
, then render this half of the sentence if a condition is met
produces:
I will first<a href='http://example.com'>link somewhere</a>, then render this half of the sentence if a condition is met
However, as you can see, the > modifier also strips the whitespace in front of the link, removing the desired space between the words and the link. I haven't figured a pretty way around this yet, except to add to the end of "I will first", like so:
I will first
%a{:href => 'http://example.com'}> link somewhere
- if #condition
, then render this half of the sentence if a condition is met
Which finally produces the desired output without lots of hard-to-read interpolation:
I will first <span>link somewhere</span>, then render this half of the sentence if a condition is met

Alright, here's the solution I'm settling on:
Helper
def one_line(&block)
haml_concat capture_haml(&block).gsub("\n", '').gsub('\\n', "\n")
end
View
I will first
- one_line do
= link_to 'link somewhere', 'http://example.com'
- if #condition
, then render this half of the sentence
\\n
if a condition is met
That way, whitespace is excluded by default, but I can still explicitly include it with a "\n" line. (It needs the double-backslash because otherwise HAML interprets it as an actual newline.) Let me know if there's a better option out there!

You can use the 'aligator syntax' of HAML
Whitespace Removal: > and <
and < give you more control over the whitespace near a tag. > will remove all whitespace surrounding a tag, while < will remove all whitespace immediately within a tag. You can think of them as alligators eating the whitespace: > faces out of the tag and eats the whitespace on the outside, and < faces into the tag and eats the whitespace on the inside. They’re placed at the end of a tag definition, after class, id, and attribute declarations but before / or =.
http://haml.info/docs/yardoc/file.REFERENCE.html#whitespace_removal__and_

Once approach I've taken to this sort of thing is to use string interpolation:
I will first #{link_to 'Link somewhere'}#{', then render this half of the sentence if a condition is met' if condition}
I don't like the look of the literal string in the interpolation, but I've used it with previously declared strings or dynamically generated strings before.

You can do this to keep the leading space:
%a{:href => 'http://example.com'}>= ' link somewhere'
The space is in the quotes.

Although not well documented, this is cleanly achieved using HAML whitespace preservation (>) combined with an ASCII space (& #32;), and not with helpers:
%a{:href=>'/home'}> Home link
,
%a{:href=>'/page'} Next link
This will produce what you want:
<a href='/home'>Anchor text</a>,
<a href='/page'>More text</a>
But I agree, HAML needs to come up with a better way of doing this, as it does add unnecessary ASCII characters to the page (but it's still more efficient than using helpers).

There's the angle bracket "whitespace munching" syntax, otherwise write a helper method for it.

I came across a similar problem and found this so I thought I would post another solution which doesn't require a helper method. Use Ruby interpolation #{} to wrap the link and if statements:
I will first
#{link_to 'link somewhere', 'http://example.com'}#{if true : ", then render this half of the sentence if a condition is met" end}
This works in 3.0.18, it may also work in earlier releases.

Yet another option that I've used in the past:
- if #condition
%span> , then some more text after the link.

You could also always do:
= link_to url_path do
= ["part_1", "part_2"].join(", ")

The solution that I got working is:
I will first
= link_to 'link somewhere', 'http://example.com'
- if #condition
= ", then render this half of the sentence if a condition is met"
You can use =, though = is used to output the result of Rails code, but here it will server the purpose.

The preserve function worked for me
.white-space-pre= preserve "TEXT"

Related

Can Haml omit tags where the Ruby content evaluates to nil?

If I have a line in a Rails template that evaluates to nil, is there a way to have Haml not bother to generate output for that line rather than create an empty tag? For instance given this:
%h4= #my_hash[:optional]
...imagine that there's no data for that hash-key. I don't want to end up with:
<h4></h4>
I'd like no output at all from that line because empty tags can still affect page layout, particularly if you're using something CSS-heavy like Bootstrap.
I can write this everywhere:
-if #my_hash[:optional]
%h4= #my_hash[:optional]
but it's long-winded and ugly.
(It seems like lots of people would want to do this, but I couldn't find any mention of either a way to do it in the Haml docs, or people on SO or elsewhere asking how it could be done. So clearly everybody already knows how to do it except me, right?)
Update: Thanks for the suggestions. The thing is, it doesn't seem to matter what you put after the equals sign here:
%h4= amazing_intelligent_helper_method_but_sadly_too_late()
because Haml has already decided to output a tag at that point, the only question is what goes in the tag? If the expression after the equals sign evaluates to nil, Haml doesn't put any content in the tag - but it still outputs the tag itself.
%h4= nil #output: <h4></h4>
%h4= '' #output: <h4></h4>
%h4= false #unexpected output: <h4>false</h4>
%h4= #Haml::SyntaxError 'There's no Ruby code for = to evaluate.'
So at the moment, I don't have a one-line way of omitting empty tags. But surely I'm not the only one who wants to do this? When you look at some of the esoteric options Haml supports, I'd have really expected this feature to already be in there somewhere.
Just append the condition to the line ala Ruby statement modifiers:
%h4= #my_hash[:optional] if #my_hash[:optional]
Still long winded but at least its on one line now.
Here are some other techniques that were discussed but they're not any shorter or prettier: HAML: Create container/wrapper element only if condition is true
Try this code
%h4= #my_hash[:optional] unless #my_hash[:optional].blank?
Even though this is my question I thought I'd suggest a semi-OK-ish answer I've just thought of in the hope that someone will look at it and say 'Aha! I can do better than that.'
I could put this in the view
!= h4_if #my_hash[:options]
and I throw this in my helper file:
TAGS_TO_DELETE_WHEN_EMPTY = ['h1', 'h2', 'h3', 'h4', 'p', 'span']
TAGS_TO_DELETE_WHEN_EMPTY.each do |tag|
new_method_name = (tag + '_if').to_sym
define_method new_method_name do |content = nil|
"<#{tag}>#{content}</#{tag}" if content
end
end
then I only get an h4 tag if there's content for it. I can use these little conditional helper methods, coupled with Haml's unescaped ruby evaluator '!=', to get what I'm looking for. Downsides include: even though it's very concise in the view, and easy to extend, it doesn't look much like regular Haml. Also, I'm not 100% sure it won't upset Haml in some way if I use much of it.
Plus I'm still hoping someone will tell me there's an option in Haml to not output empty tags, because then I don't need to write any additional code at all (which is my favourite solution to problems).

Creating a link with link_to and gsub

I have a body of text being fed into a textarea and if any of the text matches URI.regexp, I need to make that link active with a target: '_blank' on the a tag in the textarea.
Here is my current code. I also tried this with .match which would correc
def comment_body(text)
text = auto_link(text)
text.gsub!(URI.regexp) do |match|
link_to(match, match, target: '_blank')
end
end
This outputs:
https://facebook.com">https://facebook.com in my view
and
https://facebook.com in the inspected HTML.
In the gsub docs it says that metacharacters will be interpreted literally, which is what I believe is messing me up here.
Any tips on how to properly construct this URL?
Thanks!
The auto_link gem does exactly what you need.
You can look at its code to see how its using gsub.
EDIT: this solution requires setting sanitize to false, which often is not a good idea!
I've found a solution without using auto_link (I'm using Rails 5 too). I know this is an oldish thread but I've spent some time trying to find a solution that would allow the insertion of target="_blank" and found this. Here I'm creating a helper to search text in a text box for links and then add essentially make them linkable in the view.
def formatted_comment(comment)
comment = comment.body
URI.extract(comment, ['http', 'https']).each do |uri|
comment = comment.gsub( uri, link_to(uri, uri, target: "_blank"))
end
simple_format(comment, {}, class: "comment-body", sanitize: false)
end
The key thing here was simple_format kept sanitizing, so it's important to add both {} and sanitize:false.
***Note that setting sanitize to false may bring up other issues like allowing javascript to run in a comment, but this solution will allow the insertion of target="_blank" into a link.
One solution using just a simple gsub with back references would be something like this: (You can certainly modify the regex to meet your needs.)
str = 'here is some text about https://facebook.com and you really http://www.google.com should check it out.'
linked_str = str.gsub( /((http|https):\/\/(www.|)(\w*).(com|net|org))/,
'\4' )
Example output:
print linked_str
#=> here is some text about facebook and you really google should check it out.

Remove whitespace from inside html tags

How can I remove whitespace from within html tags?
For example:
"\r\n\t This is a paragraph\r\n".strip
=> "This is a Paragraph"
But what about when:
"<p>\r\n\t This is a paragraph\r\n</p>".strip
=> "<p>\r\n\t This is a paragraph\r\n</p>"
How can I get ruby to remove the whitespace from inside the tags (while retaining the p tags)?
In rails , there is a method name 'squish', for example:
"<p>\r\n\t This is a paragraph\r\n</p>".squish => "<p> This is a paragraph </p>"
Returns the string, first removing all whitespace on both ends of the string, and then changing remaining consecutive whitespace groups into one space each.
It leaves a space. If you want to get "<p>This is a paragraph</p>", I think you should use regex , it's more complicated than this. ^_^
If you want to use it in view. You can do with the below statement.
<%= strip_tags("<p>\r\n\t This is a paragraph\r\n</p>").strip %>
suppose if you want to use it in controller you can do with this statement.
self.class.helpers.strip_tags("<p>\r\n\t This is a paragraph\r\n</p>").strip
strip_tags method will removes all html tags from string.
I hope this will helps.

rails truncate method adds special characters

I have this html text:
<p> I'm a html text</p>
To show it on my web page, I first sanitize it and remove the tags:
sanitize(best_practice.milestone.description, :tags=>[])
I then shows ok, the is removed.
But if I decide to truncate the text like this:
sanitize(best_practice.milestone.description, :tags=>[]).truncate(30)
The is visible again on my web page. All the special chars will actually be visible.
What can I do to avoid truncate to make this special chars visible?
Dealing with sanitize helpers and truncation can be tricky. There are a lot of different sanitize helpers: h, CGI::escapeHTML, sanitize, strip_tags, html_safe, etc. Sanitization and truncation do not work well together if a string is truncated between an opening and a closing tag or right in the middle of a special HTML character.
The following statement seems to work
sanitize(text, :tags=>[]).truncate(30, :separator => " ").html_safe
The trick is to a pass a :separator option to truncate text at a natural break.

how to create a strong element inside a p

In haml, how do I render the following incredibly basic HTML:
<p>Results found for <strong>search term</strong>
where 'search term' is actually a Ruby variable called #query?
I'm trying the following,
%p results found for <strong>= #query</strong>
But that renders = #query literally. If I try:
%p results found for <strong>
= #query
</strong>
then the query term renders correctly, but is on a new line.
Also, I'm wondering if there's a better way to render <strong> in haml, while keeping everything on the same line.
I'm aware of the haml documentation, but as far as I can see there isn't an example of using a simple inline Ruby variable.
-----UPDATE-------
The following code works, and shows how to use a variable that's not within tags:
%p
= #trials_found_count
results found for
%strong= #query
But I find it really unreadable - it's hard to tell that it renders as just one line of HTML without adding a comment above.
Is there a way I can put all this code on a single line? Or is this just how haml works?
HAML is whitespace delimited. Nested tags go on the line below and one level in from the tag above. Embedded Ruby from which you want to display output is opened with an '='. Embedded Ruby which you don't want to display such as the start of loops uses '-' These are equivalent to <%= %> and <% %> respectively in erb.
What you want would look like this:
%p
results found for
%strong= #query
Which would produce the html:
<p>results found for <strong>#query</strong></p>
It should be noted that the '=' to start Ruby evaluation can only come at the beginning of the line or after a tag declaration and that only one tag declaration can occur per line.
The Ruby Evaluation section of the reference you linked covers embedded Ruby in detail and the haml tutorial which covers embedded ruby and many other haml basics is here:
http://haml-lang.com/tutorial.html
Here's how I'd do it:
%p No results found for <strong>#{h #query}</strong>
I'm not sure, but you might need a non-breaking space to preserve the space between the for and the <strong>
%p results found for
%strong= #query

Resources