Setting InnerHtml property using HtmlAgilityPack produces unexpected results - c#

I am using HtmlAgilityPack and C# in order to convert older IE tags as well as Javascript to be compatible with other browsers. Here is an example:
Old code:
<script for="thisForm" event="onsubmit()" language="JScript">
var Checked = false
var Counter = 0
for (;Counter < this.choice.length; Counter++)
{
if (this.choice[Counter].checked)
{
Checked = true
this.action = this.choice[Counter].value
}
}
if (!Checked)
{
alert ("Please make a selection")
return false
}
</script>
I convert to:
<script ftype="text\JScript">
function thisForm_onsubmit(el)
{
var Checked = false
var Counter = 0
for (;Counter < el.choice.length; counter++)
{
if (el.choice[counter].checked)
{
checked = true
el.action = el.choice[counter].value
}
}
if (!checked)
{
alert ("please make a selection")
return false
}
}
</script>
What I did above is removed for, event, and language attributes from script tag, added type="text/JScript" attribute and wrapped the javascript into a function code.
I do it by simply additing HtmlNode attributes and then replacing InnerHtml property value. So far it worked fine for me untill I encountered the above function. somehow instead of giving me the result above, I get the following:
<script type="text/JScript">
function thisForm_onsubmit(el)
{
var Checked = false
var Counter = 0
for (;Counter < el.choice.length; counter++)
{
if (el.choice[counter].checked)
{
checked = true
el.action = el.choice[counter].value
}
}
if (!checked)
{
alert ("please make a selection")
return false
}
}
el.choice.length;="" counter++)="" {="" if="" (el.choice[counter].checked)="" {="" checked="true" el.action="el.choice[Counter].value" }="" }="" if="" (!checked)="" {="" alert="" ("please="" make="" a="" selection")="" return="" false="" }="" }=""></ el.choice.length; counter++)
{
if (el.choice[counter].checked)
{
checked = true
el.action = el.choice[counter].value
}
}
if (!checked)
{
alert ("please make a selection")
return false
}
}
></script>
The strange part that the text I am assigning to the InnerHtml is correct, but scriptNode.InnerHtml shows different value
Here is my C# code:
if (scriptNode.Attributes["for"] != null)
{
{
if (scriptNode.Attributes["for"] != null)
ctrl = scriptNode.Attributes["for"].Value;
if (scriptNode.Attributes["event"] != null)
evt = scriptNode.Attributes["event"].Value;
if (scriptNode.Attributes["type"] != null)
typ = scriptNode.Attributes["type"].Value;
if (scriptNode.Attributes["language"] != null)
lang = scriptNode.Attributes["language"].Value;
if (scriptNode.InnerHtml != null)
code = scriptNode.InnerHtml;
func_name = ctrl + "_" + evt;
if (ctrl != "window")
new_script = Environment.NewLine + "function " + RemoveBrackets(func_name) + "(el)" + Environment.NewLine;
else
new_script = Environment.NewLine + "function " + AddBrackets(RemoveBrackets(func_name)) + Environment.NewLine;
new_script += "{" + Environment.NewLine;
new_script += "\r\n" + ReplaceThis(sFile, ctrl, evt, code, "this", "el") + "\r\n" + "}" + "\r\n";
//remove for and event attributes
scriptNode.Attributes["for"].Remove();
scriptNode.Attributes["event"].Remove();
//remove depraciated "language" attribute
//and replace it with "type" attribute
if (scriptNode.Attributes["language"] != null)
scriptNode.Attributes["language"].Remove();
if (scriptNode.Attributes["type"] == null)
scriptNode.Attributes.Add("type", "text/" + lang);
//replace old javascript with a function code
//HERE new_script variable contains the correct value but when I check scriptNode.InnerHtml after assignment, it shows the messed up code.
scriptNode.InnerHtml = new_script;
It is very strange and I can't seem to find a solution.
I have tried using HtmlEncode
scriptNode.InnerHtml = HtmlDocument.HtmlEncode(new_script);
And that produced the correct script, as specified above in second example, but replaced all the < and > with < and > etc.
So the result was:
<script type="text/JScript">
function thisForm_onsubmit(el)
{
var Checked = false
var Counter = 0
for (;Counter < el.choice.length; Counter++)
{
if (el.choice[Counter].checked)
{
Checked = true
el.action = el.choice[Counter].value
}
}
if (!Checked)
{
alert ("Please make a selection")
return false
}
}
</script>
I thought of using InnerText instead of InnerHtml, which makes more sense since what I am changing is not really HTML but InnerText property is read-only.
Can anyone shed some light on why this is happening and if there is a workaround?

The modified script contains special character < which I really suspect caused the problem. < can easily misinterpreted as first character of an opening HTML tag, especially when it is used via InnerHtml property.
Here is one possible workaround. Assume that new_script is a string variable containing the modified Javascript, including the opening and closing tags (<script type="text/JScript"></script>). You can try to load new_script into a new HtmlDocument. Then replace the old script in the 1st
HtmlDocument with the new script from the 2nd HtmlDocument instance :
.....
var newDoc = new HtmlDocument();
newDoc.LoadHtml(new_script);
var newScript = newDoc.DocumentNode.SelectSingleNode("//script");
scriptNode.ParentNode.ReplaceChild(newScript, script);
dotnetfiddle demo

Related

txtbox string and innerText/innerHTML (HTMLAGILITYPACK) are returning a false comparison

I have pulled some information from the internet using HTMLAGilityPack. No problem.
I then pass the innerHTML through a method I took from stackoverflow (this is to remove mark ups etc and make it plaintext).
I then call a boolean to determine if the new output is the same as a txtInput on the form. It is returning false even though they are the same?
I know nothing about unicode, UT-8, Cry, character bytes etc.. Though i'm assuming the binary are different? even though they appear the same? How can I get around this problem.
This is the string in the input box, the same one it pulls from HTMLAGilitypack
"When I Grow Up (feat. Lauren Ward & Bailey Ryon)"
This is the 2 outputs side by side.
As you can see from the pictures, face value they look exactly the same. Yet it returns false. Please how can I fix this?
Here is my code:
This checks if the values are different and always returns false.
private bool CheckText(string node)
{
string value = HtmlToPlainText(txtSong.Text);
if (value == node)
return true;
else
return false;
}
This is the method that actually pulls the data, If it matches it will open the page, if it doesn't it retry.
private void pullTable(int pageNum, string keyWord, int resultStart)
{
int countCheck = 0;
while (countCheck == 0)
{
System.Threading.Thread.Sleep(3000);
HtmlWeb web = new HtmlWeb();
string amazon = "https://www.amazon.co.uk/s/ref=nb_sb_noss_2?url=search-alias%3Ddigital-music&page=" + pageNum + "";
if (txtSong.Text != "")
{
string temp = txtSong.Text.Replace("(", "%28");
temp = temp.Replace(")", "%26");
amazon = amazon + "&field-keywords=" + temp;
}
if (txtArtist.Text != "")
{
string temp = txtArtist.Text.Replace("(", "%28");
temp = temp.Replace(")", "%26");
amazon = amazon + "&field-author=" + temp;
}
if (radioArtistAZ.Checked)
amazon = amazon + "&sort=artist-album-asc-rank";
else if (radioArtistZA.Checked)
amazon = amazon + "&sort=artist-album-desc-rank";
else if (radioSongAZ.Checked)
amazon = amazon + "&sort=title-asc-rank";
else if (radioSongZA.Checked)
amazon = amazon + "&sort=title-desc-rank";
{
}
var doc = web.Load(amazon);
System.Threading.Thread.Sleep(200);
var nodes = doc.DocumentNode.SelectNodes("//body");
try
{
nodes = doc.DocumentNode.SelectNodes("//tr[starts-with(#id, 'result_')]/td[2]/div/a");
}
catch (Exception)
{
}
try
{
for (int i = 0; i < 50; i++)
{
// string tempValue = nodes[i].InnerHtml.Replace("&", "&");
var plainText = HtmlToPlainText(nodes[i].InnerText);
if (CheckText(plainText))
{
AppendTextBox("Opening on page " + pageNum);
System.Diagnostics.Process.Start(amazon);
found = 1;
countCheck = 1;
return;
}
else
{
}
}
countCheck = 1;
AppendTextBox("Not found on page " + pageNum);
}
catch (Exception)
{
AppendTextBox("error on page " + pageNum);
System.Threading.Thread.Sleep(1500);
}
}
}

site freezes after closing the print window

I am using jquery.printElement.js to print. When I click on print button a print window opens with print and cancel button. If I print the document or cancel the print window every thing works fine, but if I close the window with the close button in the title bar [x] than everything stops working after dispose of print window on chrome version 35.
/// <reference path="http://code.jquery.com/jquery-1.4.1-vsdoc.js" />
/*
* Print Element Plugin 1.2
*
* Copyright (c) 2010 Erik Zaadi
*
* Inspired by PrintArea (http://plugins.jquery.com/project/PrintArea) and
* http://stackoverflow.com/questions/472951/how-do-i-print-an-iframe-from-javascript-in-safari-chrome
*
* Home Page : http://projects.erikzaadi/jQueryPlugins/jQuery.printElement
* Issues (bug reporting) : http://github.com/erikzaadi/jQueryPlugins/issues/labels/printElement
* jQuery plugin page : http://plugins.jquery.com/project/printElement
*
* Thanks to David B (http://github.com/ungenio) and icgJohn (http://www.blogger.com/profile/11881116857076484100)
* For their great contributions!
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
* Note, Iframe Printing is not supported in Opera and Chrome 3.0, a popup window will be shown instead
*/
; (function (window, undefined) {
var document = window["document"];
var $ = window["jQuery"];
$.fn["printElement"] = function (options) {
var mainOptions = $.extend({}, $.fn["printElement"]["defaults"], options);
//iframe mode is not supported for opera and chrome 3.0 (it prints the entire page).
//http://www.google.com/support/forum/p/Webmasters/thread?tid=2cb0f08dce8821c3&hl=en
if (mainOptions["printMode"] == 'iframe') {
if ($.browser.opera || (/chrome/.test(navigator.userAgent.toLowerCase())))
mainOptions["printMode"] = 'popup';
}
//Remove previously printed iframe if exists
$("[id^='printElement_']").remove();
return this.each(function () {
//Support Metadata Plug-in if available
var opts = $.meta ? $.extend({}, mainOptions, $(this).data()) : mainOptions;
_printElement($(this), opts);
});
};
$.fn["printElement"]["defaults"] = {
"printMode": 'iframe', //Usage : iframe / popup
"pageTitle": '', //Print Page Title
"overrideElementCSS": null,
/* Can be one of the following 3 options:
* 1 : boolean (pass true for stripping all css linked)
* 2 : array of $.fn.printElement.cssElement (s)
* 3 : array of strings with paths to alternate css files (optimized for print)
*/
"printBodyOptions": {
"styleToAdd": 'padding:10px;margin:10px;', //style attributes to add to the body of print document
"classNameToAdd": '' //css class to add to the body of print document
},
"leaveOpen": false, // in case of popup, leave the print page open or not
"iframeElementOptions": {
"styleToAdd": 'border:none;position:absolute;width:0px;height:0px;bottom:0px;left:0px;', //style attributes to add to the iframe element
"classNameToAdd": '' //css class to add to the iframe element
}
};
$.fn["printElement"]["cssElement"] = {
"href": '',
"media": ''
};
function _printElement(element, opts) {
//Create markup to be printed
var html = _getMarkup(element, opts);
var popupOrIframe = null;
var documentToWriteTo = null;
if (opts["printMode"].toLowerCase() == 'popup') {
popupOrIframe = window.open('about:blank', 'printElementWindow', 'width=650,height=440,scrollbars=yes');
documentToWriteTo = popupOrIframe.document;
}
else {
//The random ID is to overcome a safari bug http://www.cjboco.com.sharedcopy.com/post.cfm/442dc92cd1c0ca10a5c35210b8166882.html
var printElementID = "printElement_" + (Math.round(Math.random() * 99999)).toString();
//Native creation of the element is faster..
var iframe = document.createElement('IFRAME');
$(iframe).attr({
style: opts["iframeElementOptions"]["styleToAdd"],
id: printElementID,
className: opts["iframeElementOptions"]["classNameToAdd"],
frameBorder: 0,
scrolling: 'no',
src: 'about:blank'
});
document.body.appendChild(iframe);
documentToWriteTo = (iframe.contentWindow || iframe.contentDocument);
if (documentToWriteTo.document)
documentToWriteTo = documentToWriteTo.document;
iframe = document.frames ? document.frames[printElementID] : document.getElementById(printElementID);
popupOrIframe = iframe.contentWindow || iframe;
}
focus();
documentToWriteTo.open();
documentToWriteTo.write(html);
documentToWriteTo.close();
_callPrint(popupOrIframe);
};
function _callPrint(element) {
if (element && element["printPage"])
element["printPage"]();
else
setTimeout(function () {
_callPrint(element);
}, 50);
}
function _getElementHTMLIncludingFormElements(element) {
var $element = $(element);
//Radiobuttons and checkboxes
$(":checked", $element).each(function () {
this.setAttribute('checked', 'checked');
});
//simple text inputs
$("input[type='text']", $element).each(function () {
this.setAttribute('value', $(this).val());
});
$("select", $element).each(function () {
var $select = $(this);
$("option", $select).each(function () {
if ($select.val() == $(this).val())
this.setAttribute('selected', 'selected');
});
});
$("textarea", $element).each(function () {
//Thanks http://blog.ekini.net/2009/02/24/jquery-getting-the-latest-textvalue-inside-a-textarea/
var value = $(this).attr('value');
//fix for issue 7 (http://plugins.jquery.com/node/13503 and http://github.com/erikzaadi/jQueryPlugins/issues#issue/7)
if ($.browser.mozilla && this.firstChild)
this.firstChild.textContent = value;
else
this.innerHTML = value;
});
//http://dbj.org/dbj/?p=91
var elementHtml = $('<div></div>').append($element.clone()).html();
return elementHtml;
}
function _getBaseHref() {
var port = (window.location.port) ? ':' + window.location.port : '';
return window.location.protocol + '//' + window.location.hostname + port + window.location.pathname;
}
function _getMarkup(element, opts) {
var $element = $(element);
var elementHtml = _getElementHTMLIncludingFormElements(element);
var html = new Array();
html.push('<html><head><title>' + opts["pageTitle"] + '</title>');
if (opts["overrideElementCSS"]) {
if (opts["overrideElementCSS"].length > 0) {
for (var x = 0; x < opts["overrideElementCSS"].length; x++) {
var current = opts["overrideElementCSS"][x];
if (typeof (current) == 'string')
html.push('<link type="text/css" rel="stylesheet" href="' + current + '" >');
else
html.push('<link type="text/css" rel="stylesheet" href="' + current["href"] + '" media="' + current["media"] + '" >');
}
}
}
else {
$("link", document).filter(function () {
return $(this).attr("rel").toLowerCase() == "stylesheet";
}).each(function () {
html.push('<link type="text/css" rel="stylesheet" href="' + $(this).attr("href") + '" media="' + $(this).attr('media') + '" >');
});
}
//Ensure that relative links work
html.push('<base href="' + _getBaseHref() + '" />');
html.push('</head><body style="' + opts["printBodyOptions"]["styleToAdd"] + '" class="' + opts["printBodyOptions"]["classNameToAdd"] + '">');
html.push('<div class="' + $element.attr('class') + '">' + elementHtml + '</div>');
html.push('<script type="text/javascript">function printPage(){focus();print();' + ((!$.browser.opera && !opts["leaveOpen"] && opts["printMode"].toLowerCase() == 'popup') ? 'close();' : '') + '}</script>');
html.push('</body></html>');
return html.join('');
};
})(window);
Is there any way to identify the close event and end it peacefully OR do not show the [x] option at the right top corner?
Hi i struggled with this for the past 3 days, and came to the conclusion of the following:
these lines:
if (mainOptions["printMode"] == 'iframe') {
if ($.browser.opera || (/chrome/.test(navigator.userAgent.toLowerCase())))
mainOptions["printMode"] = 'popup';
}
are obsoletes and they seems to cause issues in Chrome, it happens that by the time when this plugin was created, Chrome and Opera have issues when printing an iframe content.
As of today that's not longer an issue (and since Opera uses Webkit as Chrome, i must assume this also happens to work on Opera as well).
So for now removes those lines and you will notice that the print dialog will not have the blank window anymore, hence you should not have this problem.

IHTMLDocument Events are not working with the COM BrowserControl

I'm trying to automate a website, and I have the following piece of code to change the value of a dropdown (select):
private bool ChangeElementSelection(mshtml.IHTMLDocument3 document, string id, string value)
{
var el = document.getElementById(id);
if (el != null)
{
log.Write("Setting HTML element " + id + " value to " + value + " (by ID)");
el.setAttribute("value", value);
var el3 = (el as IHTMLElement3);
el3.FireEvent("onchange");
return true;
}
log.Write("Could not find HTML element " + id + " (by ID)");
return false;
}
The website I am visiting uses JQuery to catch the "change" event for the select element. It does not expect any parameters. Yet the script is not triggered. Why ?

Postback not working on mouse click in Safari

So I have a dropdown context box, which I use to select which item I am going to be working with.
Now everything seems to be working on all browsers except Safari. I have a type function that works fine in safari if you focus on the box and type the name in and hit enter. However my issue is with the mouse click. If I select an item from the dropdown and click it, the postback doesn't work until I hit enter on the keyboard.
Here is my .ascx.cs file
...
if (cboContext.Visible)
{
string postBackFunction = "function contextPostback() {\n"
+ "var newValue = document.getElementById(\"" + cboContext.ClientID + "\").value;\n"
+ "if (newValue != " + cboContext.SelectedValue + ") " + Page.ClientScript.GetPostBackEventReference(cboContext, "") + ";\n}";
Page.ClientScript.RegisterClientScriptBlock(typeof(string), "contextPostback", postBackFunction, true);
if (Request.UserAgent.ToLower().IndexOf("chrome") > -1)
{
cboContext.Attributes.Add("onkeypress", "if (typeAhead(event,'" + cboContext.ClientID + "') == 1) contextPostback();");
cboContext.Attributes.Add("onclick", "contextPostback();");
}
else if (Request.UserAgent.ToLower().IndexOf("safari") > -1)
{
cboContext.Attributes.Add("onclick", "contextPostback();");
cboContext.Attributes.Add("onkeypress", "if (typeAhead(event,'" + cboContext.ClientID + "') == 1) contextPostback();");
cboContext.Attributes.Add("onkeydown", "if (typeAhead(event,'" + cboContext.ClientID + "') == 1) contextPostback();");
cboContext.Attributes.Add("onkeyup", "if (typeAhead(event,'" + cboContext.ClientID + "') == 1) contextPostback();");
}
else
{
cboContext.Attributes.Add("onkeydown", "if (typeAhead(event,'" + cboContext.ClientID + "') == 1) contextPostback();");
cboContext.Attributes.Add("onclick", "contextPostback();");
}
}
Here is the typeAhead() function
function typeAhead(e, nextFocus) {
//don't trap Ctrl+keys
if ((window.event && !window.event.ctrlKey) || (e && !e.ctrlKey)) {
// timer for current event
var now = new Date();
....
if (inputBuffer.accumString == "" || now - inputBuffer.last < inputBuffer.delay) {
//check for browsers
var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
var is_safari = navigator.userAgent.toLowerCase().indexOf('safari') > -1;
// make shortcut event object reference
var evt = e || window.event;
// get reference to the select element
var selectElem = evt.target || evt.srcElement;
// get typed character ASCII value
var charCode = evt.keyCode || evt.which;
// get the actual character, converted to uppercase
var newChar = "";
// get reference to the actual form selection list
// added cross browser fix to enable the context switcher to work properly
if (is_chrome) {
var selection = document.getElementById("ctl00_ContextSwitch1_cboContext").selectedIndex;
}
else {
var selection = document.getElementById(nextFocus);
}
....
Now I have a section in the typeAhead for the chrome browser, but everything I try for safari doesn't seem to allow me to use the mouse click to select an item.
Any help would be appreciated.
simple fix. safari recognizes onchange so once I added that, it worked fine.

ASP.NET How to use Counter with '<%=

I want to make a multiple upload, iam using some script from this forum.
the scripts is perfectly works, but when i merge it with my project.
javascript can't get the value of my element.
i found out the problem is because i have many ID PANEL in the page, i need to change to getElementByID('<%="FileUpdate.ClientID%>').value (the original : getElementByID("FileUpdate").value)
THE PROBLEM IS :
I have to use counter, ex: getElementByID('<%="txtFileUpdate' + counter + '%>').value but it FAIL.
the error says "too many characters in character literal" pointing to that line.
Please someone help, is there any solution for this problem ?
Here is the script
-----> Error " to many characters in character literal"
<script type="text/javascript" language="javascript">
var counter = 1;
function AddFileUpload() {
if (counter < 5) {
counter++;
var div = document.createElement('DIV');
div.innerHTML = '<input id="FileUpload' + counter + '" name = "file' + counter +
'" type="file" />' +
'<input id="Button' + counter + '" type="button" ' +
'value="Remove" onclick = "RemoveFileUpload(this)" />';
document.getElementById("FileUploadContainers").appendChild(div);
}
else {
alert("Cannot attach more than 5 file");
}
}
function GetFile() {
var temp;
var error = "";
var stringx = "";
var exCounter = 1 ;
for (exCounter; exCounter <= counter; exCounter++) {
-----> stringx = document.getElementById('<%=FileUpload'+exCounter+'.ClientID%>').value;
if (stringx != "")
temp += stringx + "#;";
else
error += exCounter + ", ";
}
if (error != "") {
alert("Field " + error + " Still Empty");
return;
}
document.getElementById('<%=HiddenField1.ClientID%>').value = temp;
}
Try this:
getElementByID('FileUpdate<%=counter%>').value
or
getElementByID('<%=txtFileUpdate + counter.ToString()%>').value

Categories

Resources