MVC View adding in quotations to html attribute - html

I am working on a small project and in the partial navigation view I am checking if a page is selected and highlighting the menu.
var controller = HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString().ToLower();
var home = string.Empty;
var content = string.Empty;
switch(controller) {
case "home":
home = "class=current";
break;
case "content":
content = "class=current";
break;
}
In the view I am then doing:
<li #home>Home</li>
Originally in my code I had
home = "class='current'";
Notice I had quotations around it, but when I executed the code the html source looks like
So when I remove the quatations and run it again, since it's adding them in by default, it works, even though the debugger looks like
So the project is working, my question is why is it by default adding in the quotations?

I'm not certain that MVC is adding the quotes, that is probably the Chrome DevTools doing it. If you "View page source", I don't think you will see the quotes.
Just FYI, because of these kinds of things I usually don't include the attribute in such strings, just the value...
<li class="#home">

MVC doesn't add quotes for #home. If you decompile this page, you could get codes like below:
public class _Page_Views_Home_Index_cshtml : WebViewPage<object>
{
// Methods
public override void Execute()
{
((dynamic) base.ViewBag).Title = "Home Page";
base.BeginContext("~/Views/Home/Index.cshtml", 0x27, 2, true);
this.WriteLiteral("\r\n");
base.EndContext("~/Views/Home/Index.cshtml", 0x27, 2, true);
string str = HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString();
string str2 = string.Empty;
string str3 = string.Empty;
string str4 = str;
if (str4 != null)
{
if (!(str4 == "Home"))
{
if (str4 == "content")
{
str3 = "class=current";
}
}
else
{
str2 = "class=current";
}
}
base.BeginContext("~/Views/Home/Index.cshtml", 0x1a6, 9, true);
this.WriteLiteral("\r\n\r\n<div ");
base.EndContext("~/Views/Home/Index.cshtml", 0x1a6, 9, true);
base.BeginContext("~/Views/Home/Index.cshtml", 0x1b0, 4, false);
this.Write(str2);
....
}
}
The Write methods will finally calls WebUtility.HtmlDecode method, this method replaces special chars, but will not add quotes.
Hope this helps.

Related

Access checkbox value of an item in an array - Sitecore

I cannot seem to get the value of a checkbox field of "NoIndexNoFollow" I have set in my content.
I have tried two of the follow code samples below.
1) I get FALSE for every item even if I check the box in the content editor.
foreach (var item in Model.SiteSearchResults)
{
Sitecore.Data.Fields.CheckboxField checkboxField = Sitecore.Context.Item.Fields["NoIndexNoFollow"];
if (checkboxField.Checked)
{ *CODE*}
}
2) Nothing populates here.
foreach (var item in Model.SiteSearchResults)
{
var toindex = Sitecore.Context.Item.Fields["NoIndexNoFollow"].ToString();
if (toindex == "1")
{ *CODE* }
}
I am getting no value from these items.....Not sure the right way to call a checkbox field even though either of these seem to be working for other examples I am looking at.
You can use extensions methods to make the method re-useable, but the key thing to take away from these solutions is utilising the utility function from Sitecore MainUtil.GetBool(checkboxField.Value, false);
using System;
using Sitecore;
using Sitecore.Data.Fields;
using Sitecore.Resources.Media;
namespace MyProject.Extensions
{
public static class FieldExtensions
{
public static bool IsChecked(this Field checkboxField)
{
if (checkboxField == null)
{
throw new ArgumentNullException(nameof(checkboxField));
}
return MainUtil.GetBool(checkboxField.Value, false);
}
}
public static class ItemExtensions
{
public static bool IsChecked(this Item item, ID fieldId)
{
var checkboxField = item.Fields[fieldId];
if (checkboxField == null)
{
throw new ArgumentNullException(nameof(checkboxField));
}
return MainUtil.GetBool(checkboxField.Value, false);
}
}
}
MyRendering.cshtml - using FieldExtensions
#using MyProject.Extensions
#model Sitecore.Mvc.Presentation.RenderingModel
#{
var noIndexNoFollow = Model.Item.Fields["NoIndexNoFollow"].IsChecked();
}
MyRendering.cshtml - using ItemExtensions
#using MyProject.Extensions
#using Sitecore.Mvc
#model Sitecore.Mvc.Presentation.RenderingModel
#{
var noIndexNoFollow = Model.Item.IsChecked(Model.Item.Fields["NoIndexNoFollow"].ID);
}
In your comment you wrote that Model.SiteSearchResults is a list of Sitecore ID.
You need to get item with this ID first and then check the value of the field using for example MainUtil.GetBool() method like:
foreach (var id in Model.SiteSearchResults)
{
if (Sitecore.MainUtil.GetBool(Sitecore.Context.Database.GetItem(id)["NoIndexNoFollow"], false))
{
<text>checked</text>
}
else
{
<text>not checked</text>
}
}
foreach (var item in Model.SiteSearchResults)
{
Database database = Sitecore.Context.Database;
Item myItem = database.GetItem(item.ItemId);
var fieldValue = myItem.Fields["NoIndexNoFollow"];
string noIndexValue = Convert.ToString(fieldValue);
}
So after thinking more about what you guys said, I came up with a little easier solution that works perfect for what I need. I really appreciate all the insights!

How can I remove html tags for parsing the actual value and then put them back?

I am working on highlighting the search result in search difference app and I met some problems.
On the input we get some text inside <pre> tag, that already have some highlighted text using <span> tag.
<ng-container *ngIf="settings?.allowHtmlTransform">
<pre [innerHtml]="row?.value" ></pre>
</ng-container>
My job is to highlight current search result and this is the problem. The row.value I need to parse is something like <div class="NORMAL>Sample <span class="MISSING">Text</span></div>. There are decent amount of highlight classes (ex. MODIFIED, MISSING, EXTRA etc.)
I need to highlight search result (for example "a") but it starts looking inside tags and breaks formatting (for Highlight i use the same <span class="CURRENT">)</span>
The question is how can I parse value without these tags, but when I will return highlighted value they would stay on their place? Maybe there are some beautiful solutions?
It has been 2 weeks since I asked the question and as I got back to work I found solution myself. Maybe anyone find it helpful. So the idea was to split string into parts divided by "<" and ">". And then we can check whether each part is html tag or not and add highlight only to text parts.
So here is the code. There are things to be improved but still it worked well for my case.
class Highlighter {
static hlcolors: Map<IHlType, string> = new Map([
[IHlType.success, 'success'],
[IHlType.highlight, 'currHl']
]);
static getHlVal(value: string, type: IHlType): string {
let clazz = Highlighter.hlcolors.get(type);
return '<span class="' + clazz + '">' + value + '</span>';
}
static hlByPhrase(value: string, type: IHlType, phrase: string): string {
return value.replace(phrase, Highlighter.getHlVal(phrase, type));
}
static parsehl(value: string, type: IHlType, phrase: string){
let temp = [];
let temp1 = value;
while(temp1.length > 0){
let stPos = temp1.indexOf("<");
let enPos = temp1.indexOf(">");
if(stPos === 0){
temp.push(temp1.slice(stPos, enPos+1));
temp1 = temp1.slice(enPos+1);
}
else {
temp.push(temp1.slice(0, stPos));
temp1 = temp1.slice(stPos);
}
}
let res = "";
for(let i = 0; i<temp.length; i++){
if(temp[i].includes("<div") || temp[i].includes("<span") || temp[i].includes("</div") || temp[i].includes("</span"))
res += temp[i];
else res += temp[i].replace(phrase, Highlighter.getHlVal(phrase, type));
}
return res;
}
}

Can we search or filter " data-tag='to-do' " in onenote API ? If yes then how we can do this?

How can we use OneNote tags (like data-tag='to-do') with search or filter in OneNote API. I tried using provide operators but found no success.
I tried in this way --
$url = "https://www.onenote.com/api/v1.0/me/notes";
//$url .= "/pages?search=hello";
$url .= "/pages?filter=data-tag eq 'to-do'";
I want to search data-tag and then extract the data from OneNote pages which contains the data-tag='to-do'.
Any help is appreciated and thanks in advance.
You'll have to run through all your pages.
For each pages, you can retrieve its content with a GET call to https://www.onenote.com/api/v1.0/me/notes/pages/%s/content?includeIds=true
From there you get a string that you can parse.
I'll advise you to use jsoup.
With jsoup you can then write (assuming contentcontains your page's content):
Document doc = Jsoup.parse(content);
Elements todos=doc.select("[data-tag^=\"to-do\"]");
for(Element todo:todos) {
System.out.println(todo.ownText());
}
Sadly OneNote API doesn't support it yet, so I've written my custom parser which extracts notes with data-tags from page content. Here it is:
public class OneNoteParser
{
static public List<Note> ExtractTaggedNotes(string pageContent, string tag = "*")
{
List<Note> allNotes = new List<Note>();
string[] dataTagString = { "data-tag=\""};
string[] dirtyNotes = pageContent.Split(dataTagString, StringSplitOptions.RemoveEmptyEntries);
//First one in this array can be dropped as it doesn't contain todo
for (int i = 1; i < dirtyNotes.Length; i )
{
string curStr = dirtyNotes[i];
Note curNote = new Note();
// Firstly we need to extract all the tags from it (sample html: data-tag="to-do:completed,important" ....)
string allTags = curStr.Substring(0,curStr.IndexOf("\""));
curNote.Tags = new List<string>(allTags.Split(','));
// Now we have to jump to the next ">" symbol and start finding the text after it
curStr = curStr.Substring(curStr.IndexOf(">"));
int depth = 1;
bool addAllowed = false;
for (int j = 0; j < curStr.Length - 1; j )
{
// Finding next tag opener "<" symbol
if (curStr[j] == '<')
{
addAllowed = false;
// Checking if it is not "</" closer
if (curStr[j 1] == '/')
{
// Means this is a tag closer. Decreasing depth
depth--;
}
else
{
// Means this is an tag opener. Increasing depth
depth ;
}
}
else if (curStr[j] == '>')
{
addAllowed = true;
if (j > 0 && curStr[j - 1] == '/')
{
// Means this is a tag closer. Decreasing depth
depth--;
}
}
else
{
if (depth < 1)
{
// Found end of the tag. Saving index and exiting for loop
break;
}
if (addAllowed)
curNote.Text = curStr[j]; // Appending letter to string
}
}
// Filtering by tag and adding to final list
if (tag == "*" || curNote.Tags.Any(str => str.Contains(tag)))//curNote.Tags.Contains(tag, StringComparer.CurrentCultureIgnoreCase))
allNotes.Add(curNote);
}
return allNotes;
}
}
And here is the class Note
public class Note
{
public string Text;
public List<string> Tags;
public Note()
{
Tags = new List<string>();
}
}
To extract todo-s simply call this function:
OneNoteParser.ExtractTaggedNotes(pageContent, "to-do");
Also you can extract other tags like this:
OneNoteParser.ExtractTaggedNotes(pageContent, "important");
OneNoteParser.ExtractTaggedNotes(pageContent, "highlight");
//...

Selenium and html agility pack drops html

I'm using the HTML Agility Pack and Selenium to crawl a site, find particular tables, and then parse those tables. Everything works fine individually, but when I run the app, it sometimes drops huge chunks of HTML from within the table. When I track down the page on the site with the data, the HTML is there. For whatever reason, it isn't there when the crawler is running.
Here's the code. The rows[r].InnerHtml is NOT the HTML from page. Anyone have any thoughts on what might be happening here?
public IMyInterface CreateObjectFromHtmlRow(HtmlNode rowNode)
{
try
{
var columns = rowNode.SelectNodes("td");
MyClass obj = new MyClass()
{
OnlineId = columns[0].InnerText.Trim(),
FirstName = columns[1].InnerText.Trim(),
MiddleInitial = columns[2].InnerText.Trim(),
LastName = columns[3].InnerText.Trim(),
Residence = columns[4].InnerText.Trim(),
};
return obj;
}
catch (Exception exc)
{
_logger.LogFormat("Error trying to parse row: {0}", exc.Message);
return null;
}
}
IMyInterface obj = null;
obj = _repository.CreateObjectFromHtmlRow(rows[r]);
if (obj == null)
{
_logger.LogFormat("Unable to create object from this data: {0}", rows[r].InnerHtml);
}
else
{
// Do something useful
}
Thanks for your help.
WW

Encompassing object attributes with HTML and return in JSON

currently, i have written the following json search method.
[HttpPost]
public JsonResult Search(string videoTitle)
{
var auth = new Authentication() { Email = "abc#smu.abc", Password = "abc" };
var videoList = server.Search(auth, videoTitle);
String html = "";
foreach(var item in videoList){
var video = (Video)item;
html += "<b>"+video.Title+"</b>";
}
return Json(html, JsonRequestBehavior.AllowGet);
}
On screen, it returns this.
"\u003cb\u003eAge of Conan\u003c/b\u003e"
what should i do? The reason why i want to do this is so that i can make use of CSS to style tags so that it looks aesthetically better as the items drop down from the search input.
thanks
If you want to return pure HTML you shouldn't return JSON, you should rather use the ContentResult:
[HttpPost]
public ContentResult Search(string videoTitle)
{
var auth = new Authentication() { Email = "smu#smu.com", Password = "test" };
var videoList = server.Search(auth, videoTitle);
String html = "";
foreach(var item in videoList)
{
var video = (Video)item;
html += "<b>"+video.Title+"</b>";
}
return Content(html, "text/html");
}
You can request that with standard jQuery.get() and insert directly into DOM.