Grails custom tag library out multiple lines - taglib

I am making a custom tag library in which I have to output html contents to the view using tag library. And we can output the contents like-
def globalCSS = { attrs, body ->
out << '<!-- BEGIN GLOBAL MANDATORY STYLES -->'
out << '<link href="http://fonts.googleapis.com/css?family=Open+Sans:400,300,600,700&subset=all" rel="stylesheet" type="text/css">'
out << '<link rel="stylesheet" type="text/css" href="'+g.resource(dir: 'assets/global/plugins/font-awesome/css', file: 'font-awesome.min.css', absolute: true)+'"/>'
out << '<link rel="stylesheet" type="text/css" href="'+g.resource(dir: 'assets/global/plugins/simple-line-icons', file: 'simple-line-icons.min.css', absolute: true)+'"/>'
out << '<link rel="stylesheet" type="text/css" href="'+g.resource(dir: 'assets/global/plugins/bootstrap/css', file: 'bootstrap.min.css', absolute: true)+'"/>'
out << '<link rel="stylesheet" type="text/css" href="'+g.resource(dir: 'assets/global/plugins/uniform/css', file: 'uniform.default.css', absolute: true)+'"/>'
out << '<!-- END GLOBAL MANDATORY STYLES -->'
}
Now the problem is that if I try to enter multiple lines in one out then it throws an error that-
def globalCSS = { attrs, body ->
out << 'Bla bla bla
Super bla bla
Awesome bla bla'
}
Error-
Multiple markers at this line
- implements groovy.lang.Script.run
- Groovy:expecting ''', found '\r' # line 10,
So is there anyway to post multiple lines in one out? As it would be easy for me to copy paste the HTML code which I need to output so please suggest a way to do that.

see http://groovy.codehaus.org/Strings+and+GString for the section Multiline Strings. Use ''' or """ to sourround multi line strings in groovy.
If you have a block of text which you wish to use but don't want to have to encode it all (e.g. if its a block of HTML or something) then you can use the """ syntax.
def text = """\
hello there ${name}
how are you today?
"""
The trailing \ in the first line means, that the linebreak there should be ignored (for readability)

Related

How can I include .less file in Zend Framework 2?

I can include .less file in such way:
<link rel="stylesheet/less" type="text/css" href="<?= $this->basePath('backoffice/less/master.less') ?>">
but how can I do this using ZF2, like have done with .css file
->prependStylesheet($this->basePath('backoffice/css/style.css'))
To create this link
<link rel="stylesheet/less" type="text/css" href="/backoffice/less/master.less">
You should be able to do:
->prependStylesheet(array(
'rel' => 'stylesheet/less',
'type' => 'text/css',
'href' => $this->basePath('backoffice/less/master.less')
))
Not tested - only theoretically by looking into code.

Add text just before the closing tag using Nokogiri

I'm using a Nokogiri-based helper to truncate text without breaking HTML tags:
require "rubygems"
require "nokogiri"
module TextHelper
def truncate_html(text, max_length, ellipsis = "...")
ellipsis_length = ellipsis.length
doc = Nokogiri::HTML::DocumentFragment.parse text
content_length = doc.inner_text.length
actual_length = max_length - ellipsis_length
content_length > actual_length ? doc.truncate(actual_length).inner_html + ellipsis : text.to_s
end
end
module NokogiriTruncator
module NodeWithChildren
def truncate(max_length)
return self if inner_text.length <= max_length
truncated_node = self.dup
truncated_node.children.remove
self.children.each do |node|
remaining_length = max_length - truncated_node.inner_text.length
break if remaining_length <= 0
truncated_node.add_child node.truncate(remaining_length)
end
truncated_node
end
end
module TextNode
def truncate(max_length)
Nokogiri::XML::Text.new(content[0..(max_length - 1)], parent)
end
end
end
Nokogiri::HTML::DocumentFragment.send(:include, NokogiriTruncator::NodeWithChildren)
Nokogiri::XML::Element.send(:include, NokogiriTruncator::NodeWithChildren)
Nokogiri::XML::Text.send(:include, NokogiriTruncator::TextNode)
On
content_length > actual_length ? doc.truncate(actual_length).inner_html + ellipsis : text.to_s
it appends the ellipse just after the last tag.
On my view I call
<%= truncate_html(news.parsed_body, 700, "... Read more.").html_safe %>
The issue is that the text that is being parsed is wrapped in <p></p> tags, causing the view to break:
"Lorem Ipsum</p>
... Read More"
Is it possible to append the ellipse to the last part of the last node using Nokogiri, so the final output becomes:
"Loren Ipsum... Read More</p>
Since you didn't supply any input data you get to interpolate from this:
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
<html>
<body>
<p>foo bar baz</p>
</body>
</html>
EOT
paragraph = doc.at('p')
text = paragraph.text
text[4..-1] = '...'
paragraph.content = text
puts doc.to_html
# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# >> <html>
# >> <body>
# >> <p>foo ...</p>
# >> </body>
# >> </html>
You're making it much harder than it really is. Nokogiri is smart enough to know whether we're passing markup, or simply text, and content will create a text node or an element depending on which it is.
This code simply:
Finds the p tag.
Extracts the text from it.
Replaces the text from a given point to the end with '...'.
Replaces the content of the paragraph with that text.
If you only want to append to that text it becomes even easier:
paragraph = doc.at('p')
paragraph.content = paragraph.text + ' ...Read more.'
puts doc.to_html
# >> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
# >> <html>
# >> <body>
# >> <p>foo bar baz ...Read more.</p>
# >> </body>
# >> </html>

application_helper.rb not refreshing after restart server Rails

I have an Rails app using i18n. It's fine until I try to modify the application_helper.rb there is a part that stands:
def language_css(language)
case language
when 'en'
return raw '<link rel="stylesheet" type="text/css" href="/assets/stylesheets/en.css">'
when 'es-MX'
return raw '<link rel="stylesheet" type="text/css" href="/assets/stylesheets/es.css">'
when 'fr'
return raw '<link rel="stylesheet" type="text/css" href="/assets/stylesheets/fr.css">'
when 'jp'
return raw '<link rel="stylesheet" type="text/css" href="/assets/stylesheets/jp.css">'
when 'ch'
return raw '<link rel="stylesheet" type="text/css" href="/assets/stylesheets/ch.css">'
when 'ar'
return raw '<link rel="stylesheet" type="text/css" href="/assets/stylesheets/ar.css">'
default
return raw '<link rel="stylesheet" type="text/css" href="/assets/stylesheets/es.css">'
end
end
I tried to change default "es.css" for "en.css" but I see no changes. The es.css file is still the default css file, not en.css.
So I even tried CtrlC and rails s, several times, no luck.
There is no problem with reloading, your case statement is simply not doing what you think. default here is a method call, not a keyword. You’re looking for else. Properly indented, this becomes clear:
case language
when 'en'
return raw '<link rel="stylesheet" type="text/css" href="/assets/stylesheets/en.css">'
# Skipping some cases because they’re not needed for the example
when 'ar'
return raw '<link rel="stylesheet" type="text/css" href="/assets/stylesheets/ar.css">'
default
return raw '<link rel="stylesheet" type="text/css" href="/assets/stylesheets/es.css">'
end
As we can see, the second and third lines of the when 'ar' case are never reached, because it always returns. You instead want else:
case language
when 'en'
return raw '<link rel="stylesheet" type="text/css" href="/assets/stylesheets/en.css">'
# Skipping some cases because they’re not needed for the example
when 'ar'
return raw '<link rel="stylesheet" type="text/css" href="/assets/stylesheets/ar.css">'
else
return raw '<link rel="stylesheet" type="text/css" href="/assets/stylesheets/es.css">'
end
Your code can ultimately be written more simply as:
def language_css(language)
css_file = {
'en' => 'en.css',
'es-MX' => 'es.css',
'fr' => 'fr.css',
'jp' => 'jp.css',
'ch' => 'ch.css',
'ar' => 'ar.css',
}.fetch(language, 'es.css')
raw %(<link rel="stylesheet" type="text/css" href="/assets/stylesheets/#{css_file}">)
end
I am wondering if you just have a bug in your code you're missing. I'd rewrite your method entirely.
def language_css(language)
asset = language.downcase
return raw stylesheet_link_tag(asset) if Rails.application.assets.find_asset("#{asset}.css").present?
raw stylesheet_link_tag('es')
end
You'll need to rename es.css to es-mx.css.

Using asset pipeline outside of ERB

Is there a way to use the rails asset pipeline outside of erg? When I call stylesheet_link_tag(), I get a normal /stylesheets/ link instead of an /assets/ like I'd expect. I suspect that the stache gem just needs to register something with the asset pipeline, but I'm not sure what.
I'm using this gem: https://github.com/agoragames/stache
The code I'm using:
module Layouts
class Application < ::Stache::View
include ActionView::Helpers::AssetTagHelper::StylesheetTagHelpers
def title
'foobar'
end
def stylesheets
[
[stylesheet_link_tag('reset', :media => 'all')]
]
end
def javascripts
end
end
end
It's generating:
<link href="/stylesheets/reset.css" media="all" rel="stylesheet" type="text/css" />
It should be generating (it does this in erb templates):
<link href="/assets/reset.css?body=1" media="all" rel="stylesheet" type="text/css" />
Using rails 3.2.3.
Try
def stylesheets
[
[stylesheet_link_tag("#{ActionController::Base.helpers.asset_path('reset.css')}", :media => 'all')]
]
end
also read https://stackoverflow.com/a/9341764/643500
The proper solution is to remove the:
include ActionView::Helpers::AssetTagHelper::StylesheetTagHelpers
line at the top.

How do I omit script elements from HTML using XPath in Nokogiri in Ruby on Rails?

Say I start with everything inside the body element:
Nokogiri::HTML( doc ).xpath( "/html/body/node()" ).to_html
which contains some <script> and <noscript>. How do I get rid of these?
You might want to change your XPath expression to:
Nokogiri::HTML( doc ).xpath( "/html/body/node()[not(self::script or self::noscript)]" ).to_html
#!/usr/bin/env ruby
require 'nokogiri'
html = <<EOT
<html>
<head>
<script>
<!-- dummy script !>
</script>
</head>
<body>
<script><!-- dummy script !></script>
<noscript>dummy script</noscript>
</body>
</head>
EOT
doc = Nokogiri::HTML(html)
Here's the gist of it:
doc.at('body').search('script,noscript').remove
puts doc.to_xml
>> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
>> <html>
>> <head>
>> <meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
>> <script>
>> <!-- dummy script !>
>> </script>
>> </head>
>> <body>
>>
>> </body>
>> </html>
For simplicity, I'm using Nokogiri's ability to use CSS accessors, rather than XPath.
doc.at('body').search('script,noscript').remove
looks for the first occurrence of the <body> tag, then looks inside for all <script> and <noscript> tags, removing them.
The gap between the resulting <body> tags are the result of the carriage returns in text nodes that trailed the actual target tags.

Resources