Disable Javascript click events in C# WebBrowser - c#

Intro:
I'm working on a C# WinForms + WebBrowser project.
I'd like to do some processing upon a click on a hyperlink.
Here's how I hook a click event to every hyperlink in an HTML document:
void webBrowser_DocumentCompleted( object sender, WebBrowserDocumentCompletedEventArgs e )
{
HtmlElementCollection links = webBrowser.Document.Links;
foreach ( HtmlElement link in links )
{
link.Click += delegate { MessageBox.Show( "C# Click!" ); };
}
}
The Problem:
The above code works well, but the problem is that I get side effects from javascript code which also performs some clicking action.
I learned the hard way that this problem comes in many shapes and forms..
Here's a not so obvious example of a jQuery action that makes life harder:
$(document).ready(function() {
$("a").click(function() {
alert("jQuery Click!");
});
});
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>>
</head>
<body>
Click Me!
</body>
</html>
<html>
<body>
What happens here is that when clicking a hyperlink in the WebBrowser control - the "jQuery Click!" alert will pop up first, and only after dismissing it will the "C# Click!" message be shown.
The Question:
I've searched far and wide, but didn't yet come up with an answer.
How could I C#-programmatically prevent jQuery or any other form of javascript code from being executed in the WebBrowser?
Clarification:
I'd like to say I already tried to alter the document in many ways, e.g. stripping <script> tags from webBrowser.DocumentText, and from the inner html node, and by working with HtmlElement and the underlying IHtmlElement objects...
But no luck..
Changing the webBrowser.DocumentText causes the document to get reloaded from a string, and thus I lose any credentials (e.g. cookie) I had to the original site. And changing IHtmlElement objects doesn't really make a difference 'cause the jQuery script was already loaded so, again, I am unable to prevent the event from occurring.

To my knowledge there is no way to disable JavaScript execution in WebBrowser component.
The only you can do is to suppress the error messages with ScriptErrorsSupressed property set to false.
An idea would be to pre-filter your HTML and eliminate all your "onclick" events from HTML using regular expressions before you render your HTML in the WebBrowser component.

Related

Click on dynamically generated element after body onload using Selenium

I'll do my best to convey my situation as the date I can give you is limited.
There is this button inside a webpage when clicked creates a new tab whose HTML source is somewhat like below.
<HTML><HEAD><META content="IE=5.0000" http-equiv="X-UA-Compatible">
<TITLE>Report Viewer Webpage</TITLE>
<META content="text/html; charset=windows-1252" http-equiv=Content-Type>
<SCRIPT src="javascript1.js"></SCRIPT>
<SCRIPT src="javascript2.js"></SCRIPT>
<SCRIPT src="anotherJavascript.js"></SCRIPT>
</HEAD>
<BODY onload="CallInit('ABC_DEFG_HIJKL_1_',''); window_onload();" onhelp=common_ShowHelp() leftMargin=0 topMargin=0 bgColor=#c6c6c6 currJsHelpVar="help_reports_viewer_dlg">
<OBJECT id=CRViewer codeBase="/viewer/activeXViewer/activexviewer.cab#Version=9,2,0,442" classid=CLSID:1123452WDUIHED:1325726GDUJBEA:12R432VD width="100%" height="99%" VIEWASTEXT>
<PARAM NAME="lastProp" VALUE="500">
<!--Bunch of other params go here-->
<PARAM NAME="_cx" VALUE="26987">
<SCRIPT language=VBScript>
<!--Some Business Logic-->
</SCRIPT>
<OBJECT id=ReportSource codeBase="/viewer/activeXViewer/activexviewer.cab#Version=9,2,0,442" classid=CLSID:1123452WDUIHED:1325726GDUJBEA:12R432VD width="1%" height="1%"></OBJECT>
<OBJECT id=ViewHelp codeBase="/viewer/activeXViewer/activexviewer.cab#Version=9,2,0,442" classid=CLSID:1123452WDUIHED:1325726GDUJBEA:12R432VD width="1%" height="1%"></OBJECT>
</BODY>
</HTML>
And the page content look something like this:
And of course this is a Crystal Report.
All I want to do is click on the neat little Export button sitting right beside Print button above the text preview.
And I am using Selenium to automate all this. But the problem is, selenium only works with HTML elements and I believe the buttons in the page are ActiveX controls or something else. And they are only loaded after the call to <Body> tag's onLoad call.
One of the biggest constraint is that this application only works in IE and the power of IE developer tools is not enabling me to inspect the button element. IE developer tools just doesn't see those buttons as HTML elements. They don't exist to IE developer tools. I am using IE 9 by the way.
What would help me in automating the clicking of that Export button ? Any javascript would help ??
When I inspected this webpage, the first <Object> right after the <Body> is taking all the space of the view. And I think that randomly generated elements are going inside it dynamically.
You can try FluentAutomation. It is written on top of Selenium and has Click on (x, y) coordinate function. I've managed to get it working for Crystal report. Please let me know if you have any problem.
Cheers,
Given the HTML code you're showing, it seems that the content of the page is an ActiveX.
As a result, there is no way for you to do any kind of automation with Selenium as you said it yourself, Selenium only works with HTML.

Deny a user to access Iframe web page using asp.net

In my default web page i have some pop-up Iframe when a user click something (using JS).
How can i prevent users from go directly to the link : WWW.mydomain.com/Iframe.aspx
and see the full page but still give them the access whenever they click the Iframe button from the default page.
default - default.aspx
Iframe - Iframe.aspx.
Thanks.
There is a technique called Frame killer used by web applications to prevent their web pages from being displayed within a frame. In your case, it's a bit opposite, but we can borrow a similar idea.
If you display your Iframe.aspx as a popup when you click a button. You could check for the window.opener in your Iframe.aspx throw error if window.opener is empty. Like this:
<script type="text/javascript">
if(!window.opener) {
throw new Error();
}
</script>
If your Iframe.aspx is embedded in an iframe of the popup. You could check it further using window.parent.opener
<script type="text/javascript">
if(!window.parent.opener) {
throw new Error();
}
</script>
Note that this technique does have limitations as pointed out in the link above.

How do I make Adsense code run after I insert it in an embedded browser?

I need to add Google ads to a page using the DOM API in any language (Delphi, C++, C#). I can add the Adsense code in a Web page using the DOM, but how can I subsequently trigger it to run?
The ad code usually runs in the document.load event. How do I attach my function to that event? (I also can use document download event but this event isn't compatible with DOM.)
I need to attach my function to document.load and I need use DOM functionality for parsing HTML code before running the Adsense Javascript code.
using delphi you can do this:
procedure TForm1.FormCreate(Sender: TObject);
begin
WebBrowser1.Navigate('http://stackoverflow.com');
end;
procedure TForm1.WebBrowser1DocumentComplete(Sender: TObject;
const pDisp: IDispatch; var URL: OleVariant);
var
Script: WideString;
begin
Script := 'document.onload=alert("boo!");';
if (pDisp as IWebBrowser) <> nil then
((pDisp as IWebBrowser).Document as IHTMLDocument2).parentWindow.execScript(Script, 'JScript');
end;
Here is also some additional info about sinking events with TWebBrowser. which may be useful in your case.
note that the:
TEventObject = class(TDebugInterfacedObject, IDispatch)
should be declared as:
TEventObject = class(TInterfacedObject, IDispatch)
It sounds more like a JavaScript question.
All this will be much easier to make if you use some framework like jQuery: it will let you access easily to the DOM from your javascript code.
See for instance http://docs.jquery.com/Tutorials:Getting_Started_with_jQuery for an official tutorial to easily manipulate the DOM of your page.
Here is an extract from this page:
We start with an empty html page:
<html>
<head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
// we will add our javascript code here
</script>
</head>
<body>
<!-- we will add our HTML content here -->
</body>
</html>
This page just loads the jquery.js library (make sure the URL points
to where you stored your copy of jquery! This example assumes that you
store it in the same directory as this example file). Two comments
indicate where we will expand this template with code.
As almost everything we do when using jQuery reads or manipulates the
document object model (DOM), we need to make sure that we start adding
events etc. as soon as the DOM is ready.
To do this, we register a ready event for the document.
$(document).ready(function() {
// do stuff when DOM is ready
});
Putting an alert into that function does not make much sense, as an
alert does not require the DOM to be loaded. So lets try something a
little more sophisticated: Show an alert when clicking a link.
Add the following to the <body>:
Link
Now update the $(document).ready handler:
$(document).ready(function() {
$("a").click(function() {
alert("Hello world!");
});
});
Then you just add this JavaScript in the Delphi, C++ or C# code which generates it, as plain text. You'll have to insert the Google AdSense code to the main page in the $(document).ready handler.
If you need to access the DOM from the outside (not inside like with jQuery) then you could easily do it with Delphi. But you should first install the excellent embedded web browser component TEmbeddedWB from bsalsa which makes it really easy to work with the browser.
Drop the TEmbeddedWB component onto your form and add a handler for e.g. OnDocumentComplete which is raised when the document's DOM is completely accessible:
procedure TForm1.EmbeddedWB1DocumentComplete(ASender: TObject; const pDisp: IDispatch; var URL: OleVariant);
begin
// check that the event is raised for the outermost browser (not frames or iframes)
if (pDisp as IUnknown) = (EmbeddedWB1.ControlInterface as IUnknown) then
begin
// do your work here
// example: show a message
EmbeddedWB1.ExecScript('eval("alert(''Hello'')")', '');
end;
end;
Start a navigation to test this:
EmbeddedWB1.Navigate('http://www.google.com');

lightbox is not working in updatepanel + c#

I have 6 thumbnail images as asp:imagebutton instances. These are treated as triggers for asp:updatepanel control on the page which contains an asp:image control.
When the user clicks on the thumbnail, the image in the asp:updatepanel's image control changes to the clicked thumbnail image.
The users are also allowed to again enlarge the image by clicking on the enlarge button (this runs the lightbox function). This works fine.
Question
The problem is that the enlargement works when the page loads, however when the user select a thumbnail and then tries. The method (lightbox) does not work.
I have had similar problems with javascript functions and the asp:updatepanel. Has anyone else faced similar issues? If so, how do I solve this issue?
A $ function (which is a DOM ready function) will be only be executed when the page loads for the first time.
Any further AJAX call (which is a partial loading/rendering) will not fire DOM ready function. Which is the reason, you were not able to get it working.
In you case, this function binds your anchor link (button) with the lighbox behavior the first time the page loads. so, it works. The next time when you refresh the update panel (which is a partial render) the button is not bound to lightbox again. Unless this binding is achieved it will not show up.
Normally a script control is used in such cases to fire the event every time the control is loaded.
If you are not bothered here about segregating related objects, the solution like pageLoad is still fine.
Following javascript was defalut one, it work fine without asp:UpdatePanel
<script type="text/javascript">
$(function()
{
$('#gallery a').lightBox();
});
</script>
but it is not working with asp:UpdatePanel so there is the need to call function on page load and it works fine.
<script type="text/javascript">
function pageLoad(sender, args)
{
$('#gallery a').lightBox();
}
</script>
Thanks guys for helping.
Solved:
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<script src="../slimbox-2.05/slimbox2.min.js" type="text/javascript"></script>
<script type="text/javascript">
function pageLoad() {
jQuery(function ($) {
$("a[rel^='lightbox']").slimbox({/* Put custom options here */
}, null, function (el) {
return (this == el) || ((this.rel.length > 8) && (this.rel == el.rel));
});
});
}
</script>

Element-Enhancing Javascript in ASP.NET Master Pages

I have run in to a bit of a problem and I have done a bit of digging, but struggling to come up with a conclusive answer/fix.
Basically, I have some javascript (created by a 3rd party) that does some whizzbang stuff to page elements to make them look pretty. The code works great on single pages (i.e. no master), however, when I try and apply the effects to a content page within a master, it does not work.
In short I have a master page which contains the main script reference. All pages will use the script, but the parameters passed to it will differ for the content pages.
Master Page Script Reference
<script src="scripts.js" language="javascript" type="text/javascript" />
Single Page
<script>
MakePretty("elementID");
</script>
As you can see, I need the reference in each page (hence it being in the master) but the actual elements I want to "MakePretty" will change dependant on content.
Content Pages
Now, due to the content page not having a <head> element, I have been using the following code to add it to the master pages <head> element:
HtmlGenericControl ctl = new HtmlGenericControl("script");
ctl.Attributes.Add("language", "javascript");
ctl.InnerHtml = #"MakePretty(""elementID"")";
Master.Page.Header.Controls.Add(ctl);
Now, this fails to work. However, if I replace with something simple like alert("HI!"), all works fine. So the code is being added OK, it just doesn't seem to always execute depending on what it is doing..
Now, having done some digging, I have learned that th content page's Load event is raised before the master pages, which may be having an effect, however, I thought the javascript on the page was all loaded/run at once?
Forgive me if this is a stupid question, but I am still relatively new to using javascript, especially in the master pages scenario.
How can I get content pages to call javascript code which is referenced in the Master page?
Thanks for any/all help on this guys, you will really be helping me out with this work problem.
NOTES:
RegisterStartupScript and the like does not seem to work at any level..
The control ID's are being set fine, even in the MasterPage environment and are rendering as expected.
Apologies if any of this is unclear, I am real tired so if need be please comment if a re-word/clarification is required.
Put a ContentPlaceHolder in the head section of the master page, then add a asp:Content control on the content page referring to the placeholder and put your script in that control. You can customize it for each page this way.
Also, the reference by ID may not be working because when you use Master Pages, the control IDs on the page are automatically created based on the container structure. So instead of "elementID" as expected, it may be outputting "ctl00_MainContentPlaceHolder_elementID" View your source or use firebug to inspect your form elements to see what the IDs outputted are.
Isn't it possible to do with clean javascript ?-)
-- just add something similar to this inside the body-tag:
<script type="text/javascript">
window.onload = function(){
MakePretty("elementID");
}
</script>
By the way the script-tag has to have an end-tag:
<script type="text/javascript" src="myScript.js"></script>
Why not use jQuery to find all the controls? Something like this:
$(document).ready(function(){
$("input[type='text'], input[type='radio'], input[type='checkbox'], select, textarea").each(function(){
MakePretty(this);
});
});
This way you'll get all elements on the page, you can wait until the page is ready (so you don't modify the DOM illigally). The jQuery selector can get the elements in a bit more of a specific format if you need (ie, add a root element, like the ID of the body div).
It'd also be best to modify the MakePretty method so it takes the element not the ID as the parameter to reduce processing overhead.
Once you use Master Pages, the ids of controls on the client side aren't what you think they are. You should use Control.ClientID when you generate the script.
When using master pages, you need to be careful with the html attribute ID, since .NET will modify this value as it needs to keep ids unique.
I would assume your javascript is applying css styles via ID, and when you are using master pages the ID is different than what is in your aspx. If you verify your javascript is always being added, your answer needs to take into account the following:
ALWAYS set your master page id in page load (this.ID = "myPrefix";)
Any HTML element in your master page will be prefixed by the master page id (i.e.: on the rendered page will be "myPrefix_myDiv")
Any HTML element in your content place holder id will be prefixed with an additional prefix (i.e. myPrefix_ContentPlaceHolderId1_myDiv)
Please let me know if I can clarify anything. Hope this helps!

Categories