Why won't CSS render around an element containing nil? - html

I have a problem with CSS not working properly in a combination of HAML, Backbone-text-injection, and some Rails JSON rendering.
The offending code is here:
%td{:class => 'zone_a'}
= start_time(z.zone, 'A')
start_time just does :
def start_time(zone, letter)
if zone
program = zone.programs.where(:identifier => letter).first
if program
program_zone = ProgramZone.where(:program_id => program.id, :zone_id => zone.id).first
if program_zone.run_time.to_i > 946684800
return program_zone.run_time.strftime("%H:%M")
else
return nil
end
else
return nil
end
else
return nil
end
end
And the nil which is returned renders in the page.
Let's look at what it looks like when we have a box with a value and then three boxes with nil:
The top and bottom black borders called from the %tr.inspection_zone element, that is supposed to affect all %td elements in the entire row, is having no effect here.
So this is the question - a legit SO question.
I "solved" this by putting in a non-breaking space:
%td{:class => 'zone_a'}
= " ".html_safe + start_time(z.zone, 'A')
What I'm looking for is not a work-around but rather a reason why CSS won't effect an element with a nil text/html value. And from that reason, there is probably a better solution than what I've done. I feel like my approach is just duct-taping a busted pipe.
EDIT:
Adding the rendered HTML:
Without the
<td class="zone_b"></td>
With the
<td class="zone_b">
</td>
Here is an image of the CSS - it's the same either way:

Related

While loop keeps repeating itself when it should break

My goal is to create a pre-written code - or function - that I can apply to multiple questions, where I only need to fill in the information shown on the lower half. The top half code must remain general, because I do not want to replace pieces of the code every time I use it, and would rather have it do so automatically, making it Reusable.
At the moment my code keeps repeating itself even when I type in the correct answers ('Fully', 'Partially', 'None')
def enter_preset_option():
global subj_desc
subj_desc = input(question)
i = 0
while i < len(options):
if str(subj_desc.lower()) == options[i]:
print("Great!")
break
else:
print("Invalid input. Please try again!")
i += 1
enter_preset_option()
question = "Is the property fully fenced or partially fenced? (Answer 'Fully', 'Partially' or 'None'): "
options = ['fully', 'partially', 'none']
attribute = "Fenced"
enter_preset_option()
fenced = subj_desc
print(fenced)

Trying to get the routeName but it's always empty

I tried to get the routeName from the URL because i need to set another class in the Layout of the body if i'm on the /Category page.
#{string classContent = Request.QueryString["routeName"] != "/Category" ? "container" : "";};
<div id="Content" class="body-wrapper #classContent">
My problem is, Request.QueryString["routeName"] is always empty and couldn't find why.
Does someone know why it's always empty or has a better approach for setting a different class if you're on a certain page?
In the end i solved it with that code:
var segments = Request.Url.AbsolutePath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
string classContent = "container";
if (segments.Count() > 1) { classContent = segments[1] != "category" ? "" : "container";}
Request.Url.AbsolutePath gets the whole URL.
After that i split the whole URL and save it into a list.
Then i test if the list is long enough to be on another site except home.
In the end i look if the second part of the url is /Category and save the Css class appropriate to the output of the url.

Formatting divs using Pandoc

I am using Pandoc to convert Pandoc Markdown documents to HTML5 documents. In my md input, I write custom divs using a special Pandoc syntax, for example :
::: Resources
A nice document
Informative website
:::
The resulted HTML is this :
<div class="Resources">
<p>A nice document Informative website</p>
</div>
I would like the output to be something like this instead :
<div class="Resources">
<div>A nice document</div>
<div>Informative website</div>
</div>
Ie. I want the two resources to be in two different containers. I did not find any solution to do that (it is possible that the pandoc filters can, but I don't quite understand how to write them).
Thank you very much for any kind of help. Cheers.
If the main goal is to have separate Resource blocks, I'd suggest to use a list inside the div:
::: Resources
- A nice document
- Informative website
:::
This will give
<div class="Resources">
<ul>
<li>A nice document</li>
<li>Informative website</li>
</ul>
</div>
It's not what you want yet, but get's us half way there. It already marks all resources as separate blocks. This simplifies our task to refine the document structure further through filtering. The following uses pandoc's Lua filter functionality; put the code into a file and pass it to pandoc via the --lua-filter command line parameter.
local list_to_resources = {
BulletList = function (el)
local resources = {}
local resource_attr = pandoc.Attr('', {'Resource'}, {})
for i, item in ipairs(el.content) do
resources[i] = pandoc.Div(item, resource_attr)
end
return resources
end
}
function Div (el)
-- return div unaltered unless it is of class "Resources"
if not el.classes:includes'Resources' then
return nil
end
return pandoc.walk_block(el, list_to_resources)
end
Calling pandoc with this filter will produce your desired output:
<div class="Resources">
<div class="Resource">
A nice document
</div>
<div class="Resource">
Informative website
</div>
</div>
For the sake of completeness, I'll also add a solution to the question when taking it literally. However, I do not recommend using it for various reasons:
It is far less "markdowny". Using only linebreaks to separate items is uncommon in Markdown and goes against its philosophy of having readable text without surprises.
The necessary code is more complex and fragile.
You won't be able to add additional information to the Resources div, as it will always be mangeled-up by the filter. With the previous solution, only bullet lists have a special meaning.
That being said, here's the code:
-- table to collect elements in a line
local elements_in_line = {}
-- produce a span from the collected elements
local function line_as_span()
local span = pandoc.Span(elements_in_line)
elements_in_line = {}
return span
end
local lines_to_blocks = {
Inline = function (el)
print(el.t)
if el.t == 'SoftBreak' then
return line_as_span()
end
table.insert(elements_in_line, el)
return {}
end,
Para = function (el)
local resources = {}
local content = el.content
-- last line is not followed by SoftBreak, add it here
table.insert(content, line_as_span())
local attr = pandoc.Attr('', {'Resource'})
for i, line in ipairs(content) do
resources[i] = pandoc.Div(pandoc.Plain(line.content), attr)
end
return resources
end
}
function Div (el)
-- return div unaltered unless it is of class "Resources"
if not el.classes:includes'Resources' then
return nil
end
return pandoc.walk_block(el, lines_to_blocks)
end

Download HTML Text with Ruby

I am trying to create a histogram of the letters (a,b,c,etc..) on a specified web page. I plan to make the histogram itself using a hash. However, I am having a bit of a problem actually getting the HTML.
My current code:
#!/usr/local/bin/ruby
require 'net/http'
require 'open-uri'
# This will be the hash used to store the
# histogram.
histogram = Hash.new(0)
def open(url)
Net::HTTP.get(URI.parse(url))
end
page_content = open('_insert_webpage_here')
page_content.each do |i|
puts i
end
This does a good job of getting the HTML. However, it gets it all. For www.stackoverflow.com it gives me:
<body><h1>Object Moved</h1>This document may be found here</body>
Pretending that it was the right page, I don't want the html tags. I'm just trying to get Object Moved and This document may be found here.
Is there any reasonably easy way to do this?
When you require 'open-uri', you don't need to redefine open with Net::HTTP.
require 'open-uri'
page_content = open('http://www.stackoverflow.com').read
histogram = {}
page_content.each_char do |c|
histogram[c] ||= 0
histogram[c] += 1
end
Note: this does not strip out <tags> within the HTML document, so <html><body>x!</body></html> will have { '<' => 4, 'h' => 2, 't' => 2, ... } instead of { 'x' => 1, '!' => 1 }. To remove the tags, you can use something like Nokogiri (which you said was not available), or some sort of regular expression (such as the one in Dru's answer).
See the section "Following Redirection" on the Net::HTTP Documentation here
Stripping html tags without Nokogiri
puts page_content.gsub(/<\/?[^>]*>/, "")
http://codesnippets.joyent.com/posts/show/615

Why do I get a blank record for every table row?

I have the following code, thanks to another SO question/answer:
page = agent.page.search("table tbody tr").each do |row|
time = row.css("td:nth-child(1)").text.strip
source = row.css("td:nth-child(2)").text.strip
destination = row.css("td:nth-child(3)").text.strip
duration = row.css("td:nth-child(4)").text.strip
Call.create!(:time => time, :source => source, :destination => destination, :duration => duration)
end
It's working well and when I run the rake task it correctly puts the data into the correct table row in my Rails application, however, for some reason after successfully creating a record for a row it's also creating a blank record.
I can't figure it out. From the looks of the code it's issuing the create! command within each row.
You can see the full rake task at https://gist.github.com/1574942 and
the other question leading to this code is "Parse html into Rails without new record every time?".
Based on the comment:
I think you could be right, I have looked at the HTML at the remote webpage and they are adding a wrapping around every table row which is assigned a class. I wonder if there is any way of getting the script to skip empty rows?
If you're seeing an HTML structure like:
<table>
<tbody>
<tr>
<tr>
<td>time</td>
<td>source</td>
<td>destination</td>
<td>duration</td>
</tr>
</tr>
</tbody>
</table>
Then this will show the problem:
require 'nokogiri'
require 'pp'
html = '<table><tbody><tr><tr><td>time</td><td>source</td><td>destination</td><td>duration</td></tr></tr></tbody></table>'
doc = Nokogiri::HTML(html)
page = doc.search("table tbody tr").each do |row|
time = row.css("td:nth-child(1)").text.strip
source = row.css("td:nth-child(2)").text.strip
destination = row.css("td:nth-child(3)").text.strip
duration = row.css("td:nth-child(4)").text.strip
hash = {
:time => time,
:source => source,
:destination => destination,
:duration => duration
}
pp hash
end
That outputs:
{:time=>"", :source=>"", :destination=>"", :duration=>""}
{:time=>"time",
:source=>"source",
:destination=>"destination",
:duration=>"duration"}
The reason you are getting the blank rows is because the HTML is malformed. The outside <tr> shouldn't be there. The fix is easy and will work with HTML that is correct also.
Also, the inner css access is not quite correct, but why that is so is subtle. I'll get to that.
To fix the first, we'll add a conditional test:
page = doc.search("table tbody tr").each do |row|
becomes:
page = doc.search("table tbody tr").each do |row|
next if (!row.at('td'))
After running, the output is now:
{:time=>"time",
:source=>"source",
:destination=>"destination",
:duration=>"duration"}
That's really all you need to fix the problem, but there are some things in the code that are doing things the hard way which requires some 'splainin', but first here's the code change:
From:
time = row.css("td:nth-child(1)").text.strip
source = row.css("td:nth-child(2)").text.strip
destination = row.css("td:nth-child(3)").text.strip
duration = row.css("td:nth-child(4)").text.strip
Change to:
time, source, destination, duration = row.search('td').map{ |td| td.text.strip }
Running that code outputs what you want:
{:time=>"time",
:source=>"source",
:destination=>"destination",
:duration=>"duration"}
so things are hunky-dory still.
Here's the problem with your original code:
css is an alias to search. Nokogiri returns a NodeSet for both. text will return an empty string from an empty NodeSet, which you'd get for each of the row.css("td:nth-child(...)").text.strip calls that looked at the outer <tr>. So, Nokogiri was failing to do what you wanted silently, because it was syntactically correct and logically correct given what you told it to do; It just failed to meet your expectations.
Using at, or one of its aliases, like css_at, looks for the first matching accessor. So, theoretically we could continue to use row.at("td:nth-child(1)").text.strip with multiple assignments for each accessor, and that would have immediately revealed you had a problem with the HTML because the text would have blown up. But that's not zen-like enough.
Instead, we can iterate over the cells returned in the NodeSet using map and let it gather the needed cell contents and strip them, then do a parallel assignment to the variables:
time, source, destination, duration = row.search('td').map{ |td| td.text.strip }
Again, running this:
require 'nokogiri'
require 'pp'
html = '<table><tbody><tr><tr><td>time</td><td>source</td><td>destination</td><td>duration</td></tr></tr></tbody></table>'
doc = Nokogiri::HTML(html)
page = doc.search("table tbody tr").each do |row|
next if (!row.at('td'))
time, source, destination, duration = row.search('td').map{ |td| td.text.strip }
hash = {
:time => time,
:source => source,
:destination => destination,
:duration => duration
}
pp hash
end
Gives me:
{:time=>"time",
:source=>"source",
:destination=>"destination",
:duration=>"duration"}
Retrofit that into your code and you get:
page = agent.page.search("table tbody tr").each do |row|
next if (!row.at('td'))
time, source, destination, duration = row.search('td').map{ |td| td.text.strip }
Call.create!(:time => time, :source => source, :destination => destination, :duration => duration)
end
And you probably don't need the page =.