prototype findElements querySelectorAll error - prototypejs

i'm call the "down" function but am getting an invalid argument using 1.6.1_rc2
here's the html snippet:
<TR id=000000214A class="activeRow searchResultsDisplayOver" conceptID="0000001KIU">
<TD>
<DIV class=gridRowWrapper>
<SPAN class=SynDesc>Asymmetric breasts</SPAN>
<DIV class=buttonWrapper>
<SPAN class=btnAddFav title="Add to Favorites"> </SPAN>
</DIV>
</DIV>
</TD>
</TR>
here's the code:
var description = row.down('span.SynDesc').innerHTML;
row is a dom reference to the element.
prototype is appending a # then the id of the element:
findElements: function(root) {
root = root || document;
var e = this.expression, results;
switch (this.mode) {
case 'selectorsAPI':
if (root !== document) {
var oldId = root.id, id = $(root).identify();
id = id.replace(/[\.:]/g, "\\$0");
e = "#" + id + " " + e;
}
results = $A(root.querySelectorAll(e)).map(Element.extend); <-- e = "#000000214A span.SynDesc"
root.id = oldId;
return results;
case 'xpath':
return document._getElementsByXPath(this.xpath, root);
default:
return this.matcher(root);
}
i get an "invalid argument" error?
if i put a breakpoint before the offending line and change e to be equal to "span.SynDesc" it works fine.
help. :)

I ran into this. Changing the TR's ID to start with a letter should fix the problem. It turns out that legal HTML IDs match /^[A-Za-z][A-Za-z0-9_:.-]*$/.

Related

Apply different DIV in For each loop

I am working on MVC 5. Using WEB API, fetch the data now it is time to apply the HTML PAGE design and CSS.
#foreach (var item in Model)
{
if (Model.First() == item)
{
///APPLY FIRST RECORD CSS:- Works FINE
}
else {
<div class="row">
<div class="col-sm-4">
</div>
</div>
}
}
In the else portion, every time it generates the new ROW for a SINGLE record. But I am interested to display record 2 3 4 in SECOND ROW. 5 6 7 Record in the THIRD ROW and so on.
If it is the first item, open a div and then put the items in it. Close the div when the number of columns is 3 or close the div if the item is at the end of the list.
The following algorithm does this for you
#{
int i = 0;
int columnCounter = 1;
bool newRow = false;
}
#foreach (var item in Model)
{
//add and open div row
if (i == 0 || newRow)
{
newRow = false;
#:<div class="row" style="border:2px solid red;">
}
<div class="col-md-4" style="padding:0;">
<div style="height:40px;background:#f6f6f6;width:100%;text-align:center;">
<span>Column #i</span>
</div>
</div>
//close div row if column count == 3 or reach of end list
if (columnCounter == 3 || i == Model.Count - 1)
{
newRow = true;
columnCounter = 1;
#:</div>
}
else
{
columnCounter = columnCounter + 1;
}
}
result:

Separate LI's by child element

i have the following code:
HtmlAgilityPack.HtmlNodeCollection nodeCollection = bodyNode.SelectNodes("//ul[#class='myClass']//li");
which grabs about 250 LI's
the UL format is a bit weird and it goes like this:
<ul>
<li>
<h5>Parent</h5>
Some more tags here...
</li>
<li>
<h4>Child of the prev li</h4>
</li>
<li>
<h4>Child of the prev li</h4>
</li>
<!-- and so on -->
<!-- Then again -->
<li>
<h5>Parent</h5>
Some more tags here...
</li>
<li>
<h4>Child of the prev li</h4>
</li>
<li>
<h4>Child of the prev li</h4>
</li>
<!-- child li's are not constant, this is only for demo -->
</ul>
i need to separate the LI's into groups where each group contains the parent LI and all the children LI's
anyone can help with this?
If I understood correctly this is want you want
HtmlNodeCollection liList = doc.DocumentNode.SelectNodes("//ul//li");
List<List<HtmlNode>> liGroups = new List<List<HtmlNode>>();
List<HtmlNode> liGroup = null;
foreach (HtmlNode li in liList)
{
if (li.InnerText.Contains("Parent"))
{
if (liGroup != null)
liGroups.Add(liGroup);
liGroup = new List<HtmlNode>();
liGroup.Add(li);
}
else
{
liGroup.Add(li);
}
}
liGroups.Add(liGroup);
What you will have at the end is a list liGroups that will have other list liGroup. For your above html it will show that liGroups have 2 liGroup because in your above html you have 2 parents and both two liGroup will have 3 li (1 parent + 2 childs) because both parents have same amount of children.
After that you do with them whatever you want for example:
MessageBox.Show(liGroups[0][2].InnerText); //Show from the first group the 3rd's li InnerText
var tree = new Dictionary<HtmlNode, List<HtmlNode>>();
foreach (var node in nodeCollection)
if (node.SelectSingleNode("h5[text()='Parent']") != null)
tree.Add(node, new List<HtmlNode>());
else
tree.Last().Value.Add(node);
or
var groups = nodeCollection.Group();
static class Extensions
{
public static ILookup<HtmlNode, HtmlNode> Group(this HtmlNodeCollection collection)
{
return collection.Where(n => !n.IsParent()).ToLookup(n => n.GetParent());
}
public static bool IsParent(this HtmlNode node, string header = "Parent")
{
var h = node.Element("h5");
return h != null && h.InnerText == header;
}
public static HtmlNode GetParent(this HtmlNode node)
{
while (!node.IsParent())
node = node.PreviousSibling;
return node;
}
}

How to make this Razor View work like the ASPX one does?

I have been struggling to get a partial View working in Razor. The View engine cannot make sense of the code below but it is simple using the ASPX View engine. Can anyone show me how to get this to work with Razor? Note that I am just writing out a calendar so the <tr> tag happens at the end of every week. The first sign of a problem is that the Razor code will not format in the VS editor and it complains that the 'while' block is missing its closing brace. I have tried all kinds of combinations, even using a delegate. (I think the cause of the problem may be the conditional TR tag because it is highlighted as an error because it is not closed.)
Razor (doesn't work)
<table class="calendarGrid">
<tr class="calendarDayNames">
<th>Monday</th>
<th>Tuesday</th>
<th>Wednesday</th>
<th>Thursday</th>
<th>Friday</th>
<th>Saturday</th>
<th>Sunday</th>
</tr>
#{
var loopDate = gridStartDate;
}
#while (loopDate <= gridEndDate)
{
if (loopDate.DayOfWeek == DayOfWeek.Monday)
{
<tr class="calendarWeek">
}
<td class="calendarDay">
<span class="calendarDayNumber">#loopDate.Day</span>
#if (Model.AllCalendarDays.ContainsKey(loopDate.Date))
{
foreach (var ev in Model.AllCalendarDays[loopDate.Date])
{
<span class="calendarEvent">#ev.Venue</span>
}
}
</td>
#{
loopDate = loopDate.AddDays(1);
#if (loopDate.DayOfWeek == DayOfWeek.Monday)
{
</tr>
}
}
}
ASPX (works)
<table class="calendarGrid">
<tr class="calendarDayNames">
<th>Monday</th>
<th>Tuesday</th>
<th>Wednesday</th>
<th>Thursday</th>
<th>Friday</th>
<th>Saturday</th>
<th>Sunday</th>
</tr>
<%
var loopDate = gridStartDate;
while (loopDate <= gridEndDate)
{
if (loopDate.DayOfWeek == DayOfWeek.Monday)
{
%>
<tr class="calendarWeek">
<%} %>
<td class="calendarDay">
<span class="calendarDayNumber">
<%: loopDate.Day %></span>
<% if (Model.AllCalendarDays.ContainsKey(loopDate.Date))
{
foreach (var ev in Model.AllCalendarDays[loopDate.Date])
{ %>
<span class="calendarEvent">
<%: ev.Venue %></span>
<% }
} %>
</td>
<% {
loopDate = loopDate.AddDays(1);
if (loopDate.DayOfWeek == DayOfWeek.Monday)
{ %>
</tr>
<% }
}
} %>
</table>
Working solution in Razor based on #jgauffin's view model suggestion and #dommer's ugly raw html solution. Combined together they're almost aesthetically acceptable. :)
View model now has iterator
public IEnumerable<Tuple<DateTime, IList<CalendarEventDto>>> GridItems()
{
var loopDate = GridStartDate;
while (loopDate <= GridEndDate)
{
yield return new Tuple<DateTime, IList<CalendarEventDto>>(loopDate.Date, AllCalendarDays[loopDate.Date]);
loopDate = loopDate.AddDays(1);
}
}
Okay, the Tuple is lazy but I will probably create another model to hold more complex information about the date and events (IsPast/greyed, etc).
The pesky View
#foreach (var item in Model.GridItems())
{
if (item.Item1.DayOfWeek == DayOfWeek.Monday)
{
#Html.Raw("<tr class=\"calendarWeek\">");
}
#Html.Raw("<td class=\"calendarDay\">");
#Html.Raw(string.Format("<span class=\"calendarDayNumber\">{0}</span>", item.Item1.Day));
foreach (var ev in item.Item2)
{
#Html.Raw(string.Format("<span class=\"calendarEvent\">{0}</span>", Server.HtmlEncode(ev.Venue)));
}
#Html.Raw("</td>");
if (item.Item1.DayOfWeek == DayOfWeek.Sunday)
{
#Html.Raw("</tr>");
}
}
Note that when I reformat the View source in VS, it gets egregiously tabbed, with the if statement having about 10 tabs to the left of it, but there are no compilation warnings and it does what I want. Not nice, or easy though. I think the Razor devs should provide some support for explicit breakout and breakin to code and markup so that when the parser cannot parse it unambiguously, we can tell it what we intended.
#Andrew Nurse's solution
Andrew 'works on the ASP.Net team building the Razor parser!'. His solution runs okay but still produces compiler warnings and is obviously confusing Visual Studio because the code cannot be reformatted without ending up in a big glob on a few lines:
<tbody>
#foreach (var calDay in Model.GridItems())
{
if (calDay.DayOfWeek == DayOfWeek.Monday)
{
#:<tr class="calendarWeek">
}
<td class="calendarDay">
<span class="calendarDayNumber">#calDay.Day</span>
#foreach (var ev in calDay.CalendarEvents)
{
<span class="calendarEvent">#ev.Venue</span>
}
</td>
if (calDay.DayOfWeek == DayOfWeek.Sunday)
{
#:</tr>
}
}
</tbody>
The primary issues here were these lines:
if (loopDate.DayOfWeek == DayOfWeek.Monday)
{
<tr class="calendarWeek">
}
...
#if (loopDate.DayOfWeek == DayOfWeek.Monday)
{
</tr>
}
The problem is that Razor uses the tags to detect the start and end of markup. So since you didn't close the "tr" tag inside the first if, it doesn't actually switch back to code, so it doesn't see the "}" as code. The solution is to use "#:", which lets you put a line of markup without regard for tags. So replacing those lines with this should work and be more concise than using Html.Raw:
if (loopDate.DayOfWeek == DayOfWeek.Monday)
{
#:<tr class="calendarWeek">
}
...
#if (loopDate.DayOfWeek == DayOfWeek.Monday)
{
#:</tr>
}
I would move all logic to the viewmodel which leaves the following code in your view:
#while (Model.MoveNext())
{
#Model.WeekHeader
<td class="calendarDay">
<span class="calendarDayNumber">#Model.DayNumber</span>
#foreach (var ev in Model.CurrentDayEvents)
{
<span class="calendarEvent">#ev.Venue</span>
}
</td>
#Model.WeekFooter
}
And the new model:
public class CalendarViewModel
{
private DateTime _currentDate;
public string WeekHeader
{
get
{
return _currentDate.DayOfWeek == DayOfWeek.Monday ? "<tr class="calendarWeek">" : "";
}
}
public string WeekFooter
{
get
{
return _currentDate.DayOfWeek == DayOfWeek.Monday ? "</tr>" : "";
}
}
public IEnumerable<DayEvent>
{
get
{
return AllCalendarDays.ContainsKey(loopDate.Date) ? AllCalendarDays[loopDate.Date] ? new List<DayEvent>();
}
}
public bool MoveNext()
{
if (_currentDate == DateTime.MinValue)
{
_currentDate = gridStartDate;
return true;
}
_currentDate = _currentDate.AddDays(1);
return _currentDate <= gridEndDate;
}
}
MAJOR EDIT: Okay, what happens if you do this?
<table class="calendarGrid">
<tr class="calendarDayNames">
<th>Monday</th>
<th>Tuesday</th>
<th>Wednesday</th>
<th>Thursday</th>
<th>Friday</th>
<th>Saturday</th>
<th>Sunday</th>
</tr>
#{
var loopDate = gridStartDate;
while (loopDate <= gridEndDate)
{
if (loopDate.DayOfWeek == DayOfWeek.Monday)
{
#Html.Raw("<tr class=\"calendarWeek\">");
}
#Html.Raw("<td class=\"calendarDay\">");
#Html.Raw("<span class=\"calendarDayNumber\">" + loopDate.Day + "</span>");
if (Model.AllCalendarDays.ContainsKey(loopDate.Date))
{
foreach (var ev in Model.AllCalendarDays[loopDate.Date])
{
#Html.Raw("<span class=\"calendarEvent\">" + ev.Venue + "</span>");
}
}
#Html.Raw("</td>");
loopDate = loopDate.AddDays(1);
if (loopDate.DayOfWeek == DayOfWeek.Monday)
{
#Html.Raw("</tr>");
}
}
}
Have you tried adding <text> tags around the contents of the blocks?
I think the Razor parse only works when it's obvious where the blocks end. It may be getting confused by the fact you have an if, a td and then some more code, all inside the block.
There's more info on this here: http://weblogs.asp.net/scottgu/archive/2010/12/15/asp-net-mvc-3-razor-s-and-lt-text-gt-syntax.aspx

AJAX getting truncated on paragraph

I'm having a strange problem when trying to updated a div with a couple of paragrahs of text from AJAX.
Here are functions I'm using:
var receivePapers = getXmlHttpRequestObject();
function get_papers(myCat){
if (receivePapers.readyState == 4 || receivePapers.readyState == 0) {
receivePapers.open("GET", 'http://server/path/tocode/file.php?get_papers=1&student_id=1&category=' + myCat, true);
receivePapers.onreadystatechange = handlereceivePapers;
receivePapers.send(null);
}
}
function handlereceivePapers() {
if (receivePapers.readyState == 4) {
var container_div = document.getElementById('paper_container');
var xmldoc = receivePapers.responseXML;
var paper_nodes = xmldoc.getElementsByTagName("paper");
var n_papers = paper_nodes.length;
// Clear the whole container div.
container_div.innerHTML = "";
container_div.innerHTML = "<table class='categoryHeader' width='100%'><tr><th class ='categoryHeader' width='80%' ><br/> " + paper_nodes[1].getElementsByTagName("category")[0].firstChild.nodeValue + "</br> <br/><br/></th></tr>";
container_div.innerHTML += "<tr><td>";
for (i = 0; i < n_papers; i++) {
var paper_id = paper_nodes[i].getElementsByTagName("paper_id");
var paper_title = paper_nodes[i].getElementsByTagName("paper_title");
var paper_desc = paper_nodes[i].getElementsByTagName("paper_desc");
var paper_time = paper_nodes[i].getElementsByTagName("paper_time");
var user_real_name = paper_nodes[i].getElementsByTagName("user_real_name");
var summary_div = document.createElement('div');
summary_div.innerHTML += "<table class='paper'><tr><td class='paperLike' width=80px rowspan=2 valign='top'><div id='" + paper_id[0].firstChild.nodeValue + "'> <img src='images/Like.png' style='padding-top:5px' border='0' /></div></td><td><table width='100%'><tr><td class='paperTitle' style='background-color:white; text-align=left; '><a class='paperTitle' style='padding-left:0;' href='#" + paper_id[0].firstChild.nodeValue + "'>" + paper_title[0].firstChild.nodeValue + "</a></td><td class='paperName' style='margin-right:0; width:200px; background-color:white; text-align:right; vertical-align:text-top;'><span align='right' style='background-color:white; text-align:right; vertical-align:text-top; ' > " + user_real_name[0].firstChild.nodeValue + "</span></td></tr></table></td><td rowspan='2' class='paperLength' style='width:80px; text-align:right; padding-top:8px;' >" + paper_time[0].firstChild.nodeValue + " minutes</td></tr><tr><td class='paperDescription' align='left' colspan='1'>" + paper_desc[0].firstChild.nodeValue + "</td></tr></table>";
container_div.appendChild(summary_div);
}
container_div.innerHTML += "</tr></td></table";
}
}
Here is the XML that's getting returned:
<root>
<paper id="23">
<paper_id>23</paper_id>
<paper_title>title</paper_title>
<paper_desc>
First paragraph of desc
<br/>
<br/>
Second paragraph of desc
<br/>
<br/>
Third paragraph of desc
<br/>
</paper_desc>
<paper_time>45</paper_time>
<user_real_name>Bob Student</user_real_name>
<user_id>2322</user_id>
<category>Languages</category>
</paper>
...
When I push the content to container_div only the first paragraph is showing up. If I stick a Javascript alert() in to return paper_desc it only contains the first paragraph. I've tried looking for other nodes but this says there's only 1 node:
alert(paper_nodes[i].getElementsByTagName("paper_desc").length);
You use paper_desc[0].firstChild.nodeValue
paper_desc[0] is a set of nodes: text nodes and br nodes. You get only the first child of this set, so you get only the first text.
Your alert() call only shows you have only one paper_desc node, not how many nodes you have inside.
I also found strange that you used paper_nodes[1] but I don't know if there is a second node in your XML and if you really want to target it.

Multiline texbox validation

I want to validate maxlegnth of 5 characters in each row of the multiline textbox
Help me
Here's an example: A TextArea and span to show the validation results.
<textarea cols="30" rows="10" onblur="validateRows(this)"></textarea><br/>
<span id="validationResults" style="color:red"></span>
Here's the JavaScript code to validate each row:
function validateRows(e){
var content = e.value.split("\n");
for(var line in content){
var charLength = content[line].length - 1;
var lineNumber = parseInt(line) + 1;
if(charLength > 5){
document.getElementById("validationResults").innerHTML += "* line "
+ lineNumber + " has " + charLength
+ " characters" + "<br/>";
}
}
}
This is a C# version. Can be used either in Web applications for server side validation or Windows applications. (In Web applications for client side validation, Jose Basilio's code is appropriate)
public static bool HasMax5CharsPerLine(TextBox target)
{
foreach (string Line in target.Text.Split(new char[] {'\n'}))
if (Line.Length > 5)
return false;
return true;
}
using split function(both in C# and Javascript) and then check length it.
var temp = [TextFromTextBox].split('\n');
foreach(var s in temp)
{
if(!ValidateFunction(s))
{
// code for show exception
}
}

Resources