Compiling javascript templates with Jammit gem for Rails? - ruby-on-rails

We're on Rails (3.0.3 / 1.9) using Jammit for static compression and all the other front-end goodies it provides.
I'm trying to work Javscript templates in to replace some ugly front-end code, but it looks like the default JST compiler can't handle Windows line breaks:
assets.yml file:
embed_assets: on
javascripts:
plugins:
- app/views/**/*.jst
When I have _topicPreview.jst all on one line it compiles fine:
<div class='TopicPreview <%= typeName %>'><div class='Title'> <%= summary %> </div><div class='Meta'> <span class='LastUpdate'> <%= updatedAt %> </span> <span class='PostCount'> | <%= postsCount %> Posts | </span> <span class='LikeCount'> <%= likesCount %> Likes </span> </div></div>
The page loads and I have the JST._topicPreview([JSON version of topic]) method available. Beautiful.
Half the appeal of JST is the readability / maintainability though, so I would like my JST to have proper formatting. As soon as I add line breaks into the JST file the page throws Uncaught SyntaxError: Unexpected Token ILLEGAL in window.JST['_topicPreview'] = template('...[the escaped JST file]...')
In the code trace I can see that it parses and escapes single quotes, so I was surprised it couldn't handle the line breaks.
Has anyone else encountered this problem?
Is there a cleaner fix than hacking some extra string replaces into the template generation code?
Meta:
I'm pretty new to javascript templates, but should they have their own StackOverflow tag?
Edit
Looks like this is a known issue with a pending fix to be merged into the gem.
Windows line breaks in Jammit JST compiler

Fix has been added to the gem. Windows developers rejoice.

Related

Kramdown not showing in heroku (Rails app)

I am using gem kramdown, locally is working, but not in production. Here are the results locally:
content: "~~~ ruby\r\ndef what?\r\n 42\r\nend\r\n~~~",
kramdown_to_html(subthema.content.html_safe)
=> "<div class=\"language-ruby highlighter-coderay\"><div
class=\"CodeRay\">\n <div class=\"code\"><pre><span
style=\"color:#080;font-weight:bold\">def</span> <span
style=\"color:#06B;font-weight:bold\">what?</span>\n <span
style=\"color:#00D\">42</span>\n<span style=\"color:#080;font-
weight:bold\">end</span>\n</pre></div>\n</div>\n</div>\n"
As you see, the piece of code is translated into right HTML, every code-word is within a span and every span has its own class (then with CSS you give the styling).
In production though, here are the results, doing exactly the same:
irb(main):010:0> subthema.content.html_safe
=> "~~~ ruby\r\ndef what?\r\n 42\r\nend\r\n~~~"
irb(main):011:0> kramdown_to_html(subthema.content)
=> "<pre><code class=\"language-ruby\">def what?\n 42\nend\n</code>
</pre>\n"
As you see, the span tags are not there. In Heroku, Kramdown just achieves to create pre and code tagsm but not the spans.
Any help in this topic?
Thanks in advance.

Capybara::Poltergeist::MouseEventFailed after Haml update (4.0.7 => 5.0.2) [RAILS]

Hi we are currently updating our HAML file from version 4.0.7 to 5.0.2. After the update a lot of cucumber tests break saying;
Firing a click at co-ordinates [422.5, 414] failed.
Poltergeist detected another element with CSS selector 'html.javascript body div.ui-widget-overlay.ui-front' at this position.
It may be overlapping the element you are trying to interact with.
If you don't care about overlapping elements, try using node.trigger('click').
(Capybara::Poltergeist::MouseEventFailed)
It breaks at the parts where i'm using interpolation in i18n texts like this:
You_are_on_a_device: You are on a %{type} device
And in the view im using something like this:
%p.dialog{'data-attribute' => t('you_are_on_a_device', type: 'small').html_safe, hidden: true}
I can't seem to find the breaking change from the Haml Changelog
Does anybody know whats causing this and what i can do to fix this?
Solved:
The solution was to put the data attributes value in an interpolated string like this:
%p.dialog{'data-attribute' => "#{t('you_are_on_a_device', type: 'small').html_safe}", hidden: true}
and in my config/initializers/haml.rb
Haml::Template.options[:escape_html] = false
It was because of the html escaping that has become standard in HAML 5.0.0, where it wasn't in HAML 4.0.7
Disabling html escaping is NOT a good practice because it makes your app prone to XSS attacks. For example, when an attacker type in their username <script>alert('Vasya')</script> other users will see an alert every time Vasya's name will appear on the page. Try the following code:
%p= "<script>alert('Vasya')</script>"
I installed haml 5.0.2 in a fresh rails project (rails 4.2.6) and I tried to render the following page:
%h1 HAML
%p.dialog{'data-attribute' => t('you_are_on_a_device', type: 'small').html_safe, hidden: true}
%p.dialog{'data-attribute' => "#{t('you_are_on_a_device', type: 'small').html_safe}", hidden: true}
I don't see any differences in the rendered p tags (I've tried both escape_html true and false):
<h1>HAML</h1>
<p class="dialog" data-attribute="You are on a <a href="http://mywebsite.nl/type">small</a> device" hidden=""></p>
<p class="dialog" data-attribute="You are on a <a href="http://mywebsite.nl/type">small</a> device" hidden=""></p>
I guess that the Failed to click on element issue is caused by other reason, maybe you upgraded capybara or capybara-related gem while upgrading haml
Also it is a good practice to render data-attributes using hash notation:
%p.dialog{data: { attribute: t('you_are_on_a_device', type: 'small').html_safe }, hidden: true}
See more detailed documentation on the haml data attributes here

Nokogiri results different from brower inspect

I am trying to scrape a site but the results returned for just the links is different from when I inspect it with the browser.
In my browser I get normal links but all the a HREF links all become javascript:void(0); from Nokogiri.
Here is the site:
https://www.ctgoodjobs.hk/jobs/part-time
Here is my code:
url = "https://www.ctgoodjobs.hk/jobs/part-time"
response = open(url) rescue nil
next unless response
doc = Nokogiri::HTML(open(url))
links = doc.search('.job-title > a').text
is not that easy, urls are "obscured" using a js function, that's why you're getting javascript: void(0) when asking for the hrefs... looking at the html, there are some hidden inputs for each link, and, there is a preview url that you can use to build the job preview url (if that's what you're looking for), so you have this:
<div class="result-list-job current-view">
<input type="hidden" name="job_id" value="04375145">
<input type="hidden" name="each_job_title_url" value="barista-senior-barista-咖啡調配員">
<h2 class="job-title">Barista/ Senior Barista 咖 啡 調 配 員</h2>
<h3 class="job-company">PACIFIC COFFEE CO. LTD.</h3>
<div class="job-description">
<ul class="job-desc-list clearfix">
<li class="job-desc-loc job-desc-small-icon">-</li>
<li class="job-desc-work-exp">0-1 yr(s)</li>
<li class="job-desc-salary job-desc-small-icon">-</li>
<li class="job-desc-post-date">09/11/16</li>
</ul>
</div>
<a class="job-save-btn" title="save this job" style="display: inline;"> </a>
<div class="job-batch-apply"><span class="checkbox" style="background-position: 0px 0px;"></span><input type="checkbox" class="styled" name="job_checkbox" value="04375145"></div>
<div class="job-cat job-cat-de"></div>
</div>
then, you can retrieve each job_id from those inputs, like:
inputs = doc.search('//input[#name="job_id"]')
and then build the urls (i found the base url at joblist_preview.js:
urls = inputs.map do |input|
"https://www.ctgoodjobs.hk/english/jobdetails/details.asp?m_jobid=#{input['value']}&joblistmode=previewlist&ga_channel=ct"
end
Take the output of a browser and that of a tool like wget, curl or nokogiri and you will find the HTML the browser presents can differ drastically from the raw HTML.
Browsers these days can process DHTML, Nokogiri doesn't. You can only retrieve the raw HTML using something that lets you see the content without the browser, like the above mentioned tools, then compare that with what you see in a text editor, or what nokogiri shows you. Don't trust the browser - they're known to lie because they want to make you happy.
Here's a quick glimpse into what the raw HTML contains, generated using:
$ nokogiri "https://www.ctgoodjobs.hk/jobs/part-time"
Nokogiri dropped me into IRB:
Your document is stored in #doc...
Welcome to NOKOGIRI. You are using ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]. Have fun ;)
Counting the hits found by the selector returns:
>> #doc.search('.job-title > a').size
30
Displaying the text found shows:
>> #doc.search('.job-title > a').map(&:text)
[
[ 0] "嬰 兒 奶 粉 沖 調 機 - 兼 職 產 品 推 廣 員 Part Time Promoter (時 薪 高 達 HK$90, 另 設 銷 售 佣 金 )",
...
[29] "Customer Services Representative (Part-time)"
]
Looking at the actual href:
>> #doc.search('.job-title > a').map{ |n| n['href'] }
[
[ 0] "javascript:void(0);",
...
[29] "javascript:void(0);"
]
You can tell the HTML doesn't contain anything but what Nokogiri is telling you, so the browser is post-processing the HTML, processing the DHTML and modifying the page you see if you use something to look at the HTML. So, the short fix is, don't trust the browser if you want to know what the server sends to you.
This is why scraping isn't very reliable and you should use an API if at all possible. If you can't, then you're going to have to roll up your sleeves and dig into the JavaScript and manually interpret what it's doing, then retrieve the data and parse it into something useful.
Your code can be cleaned up and simplified. I'd write it much more simply as:
url = "https://www.ctgoodjobs.hk/jobs/part-time"
doc = Nokogiri::HTML(open(url))
links = doc.search('.job-title > a').map(&:text)
The use of search(...).text is a big mistake. text, when applied to a NodeSet, will concatenate the text of each contained node, making it extremely difficult to retrieve the individual text. Consider this:
require 'nokogiri'
doc = Nokogiri::HTML(<<EOT)
<html>
<body>
<p>foo</p>
<p>bar</p>
</body>
</html>
EOT
doc.search('p').class # => Nokogiri::XML::NodeSet
doc.search('p').text # => "foobar"
doc.search('p').map(&:text) # => ["foo", "bar"]
The first result foobar would require being split apart to be useful, and unless you have special knowledge of the content, trying to figure out how to do it will be a major pain.
Instead, use map to iterate through the elements and apply &:text to each one, returning an array of each element's text.
See "How to avoid joining all text from Nodes when scraping" and "Taking apart a DHTML page" also.

MediaWiki Scribunto extension's "Listen" module not generating expected HTML

I have a MediaWiki installation (1.23) with the Scribunto extension and Module:Listen. I try to invoke this module from an article like so:
{{Listen
|filename = Noise.ogg
|title = Noise
|description = Some noise
}}
This generates the little infobox, but the embedded sound player itself does not appear. I looked at the generated HTML, and the module is just making a second ordinary href to the file:
<div class="haudio">
<div style="padding:2px 0;">Noise</div>
<div style="padding-right:4px;">File:Noise.ogg</div>
<div class="description" style="padding:2px 0 0 0;">Some noise</div></div>
Rather than the second href to the file, I'd expect to see a or similar. Am I missing some template or Lua module?
You need to have TimedMediaHandler installed for the sound player to show up!

Bootstrap 'small' tag not playing nicely with link_to rails helpers

I'm having an issue getting the '-' (dash) to be directly in front of the link that uses "#natelie_h" as the anchor text. It breaks it on to the next link for some reason.
<div class="span3">
<blockquote><p>"My favourite part of the service is the information pack that comes with the flies"</p><p><small><%= link_to "#natelie_h", "https://twitter.com/natelie_h", :target => "_blank" %> </small></p></blockquote>
</div>
Here you can see what I mean: http://www.clockworkflies.com/ (customer quotes, near the bottom).
That is because and in have a display:block, and "-" is added before but "-" is inline, so is shown on new line
Try
blockquote small a:before {
content: "— ";
}
in css, instead of "blockquote small:before"
Another option is to set not display:block but display:inline-block for blockquote small and blockquote small a. But IE6 and IE7 does not support this css variable

Resources