Where's XmlHttpRequest defined in Internet Explorer? - javascript

I'm trying to write an IE BHO (ported from Chrome) where I need to use XSS with jQuery. I am hoping that I can enable XSS for my own addon/JavaScript by replacing the jQuery function, $.ajaxSettings.xhr with,
$.ajaxSettings.xhr = function() { return window.myExtension.Xhr() }
Where myExtension.Xhr is a COM function defined in my extension (and myExtension is added via ((IExpando)window).addProperty).
I tried defining my Xhr() function as (C# implementing COM),
public object Xhr()
{
return new MSXML.XMLHTTPRequest();
}
But this fails when jQuery tries to set the onload property of the XHR (at jquery-2.1.3.js:8617). So it looks like I'm using the wrong COM XmlHttpRequest (MSXML2.XMLHttp also has a missing onload). So where is the "real" XmlHttpRequest defined?
// Listen to events
xhr.onload = callback();
xhr.onerror = callback("error");
// Create the abort callback
callback = xhrCallbacks[ id ] = callback("abort");
I can of course just use one of the several methods of submitting GET/POST requests in .NET, but then I'd have to dirty my code with workarounds for IE when doing XSS ajax calls (since Firefox and Chrome extensions can do XSS with appropriate permissions).

I did not find a real solution to my question, but a sort of workaround for what I ultimately want to do is to use jQuery 1.x instead, which is able to (and does, for IE6-8) work with the old MSXML.XMLHTTPRequest.
I am posting this for anyone would like to run cross-domain Ajax requests in scripts they inject via a BHO.
First, define this interface:
[ComVisible(true)]
[Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IExtension
{
[DispId(1)]
object Xhr();
[DispId(2)]
string OptionalFooBar();
}
And implement it somewhere, e.g. in this case my BHO itself:
//Exposed to JS
public object Xhr()
{
return new MSXML2.XMLHTTP();
}
And once your document completes, say in an OnDocumentComplete handler, add a property to the window through IDispatchEx to expose your methods:
void OnDocumentComplete(object pDisp, ref object URL)
{
dynamic window = null;
IExpando windowEx = null;
try
{
if (pDisp != this.site)
return;
var document2 = browser.Document as IHTMLDocument2;
var document3 = browser.Document as IHTMLDocument3;
window = document2.parentWindow;
windowEx = window as IExpando;
windowEx.AddProperty("myExtension")
window.myExtension = this;
}
And then in your JS, after jQuery has been loaded:
jQuery.ajaxSettings.xhr = function () { return window.myExtension.Xhr(); }

Related

WKScriptMessageHandler won't Listen to 'onclick' or 'click' event on a button element on a webpage. The web page is developed using Reactjs

I am using a WKWebView inside a UIViewController's view to display a webpage hosted on a server using a url endpoint. The webpage uses Reactjs. That is all the information I have about the webpage. The code creates a webview and inserts the webview as subview of the controllers view.
let requestObj = URL(string:urlString)!
let preferences = WKPreferences()
preferences.javaScriptEnabled = true
let configuration = WKWebViewConfiguration()
configuration.preferences = preferences
webViewWK = WKWebView(frame: .zero, configuration: configuration)
webViewWK.navigationDelegate = self
_ = webViewWK.load(requestObj)
webViewwrapper = WKWebViewWrapper(forWebView: webViewWK)
The webpage loads fine and also the controller acts as the delegate of the webview and receives the messages for the same. Now I also implement a WKWebViewWrapper class which conforms to WKScriptMessageHandler. This class can then receive messages from webkit object which is created by the WKWebView behing the scenes. The implementation for the same is as below
class WKWebViewWrapper : NSObject, WKScriptMessageHandler{
var wkWebView : WKWebView
let eventNames = ["buttonClick"]
var eventFunctions: Dictionary<String, (String) -> Void> = [:]
let controller: WKUserContentController
init(forWebView webView : WKWebView){
wkWebView = webView
controller = WKUserContentController()
super.init()
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if let contentBody = message.body as? String {
if let eventFunction = eventFunctions[message.name]{
print("Detected javascript event")
}
}
}
func setUpPlayerAndEventDelegation(){
wkWebView.configuration.userContentController = controller
for eventname in eventNames {
controller.add(self, name: eventname)
eventFunctions[eventname] = { _ in }
wkWebView.evaluateJavaScript("var elements = document.getElementsByClassName('btn button_btn button_primary button_md button_block'); for (var i = 0 ; i < elements.length; i++) { elements[i].addEventListener('onClick', function(){ window.webkit.messageHandlers.\(eventname).postMessage(JSON.stringify(isSuccess)) }); }") { any, error in
if let error = error {
print("EvaluateJavaScript Error:",error)
}
if let any = any {
print("EvaluateJavaScript anything:", any)
}
}
}
}
}
The setUpPlayerAndEventDelegation() method is the most important part. Here for the controller object which is of type WKUserContentcontroller adds message handlers using its add(: , name:) method. According to documentation this method adds a messageHandler of the name parameter to the webkit object. Whenver the messsage handler is triggered, the WKScriptMessageHandler's userContentController( userContentController: WKUserContentController, didReceive message: WKScriptMessage) method is called with useful parameters. Then I inject javascript into the webpage using evaluateJavaScript method of webview which is as below
var elements = document.getElementsByClassName('btn button_btn button_primary button_md button_block');
for (var i = 0 ; i < elements.length; i++) {
elements[i].addEventListener('onClick', function(){ window.webkit.messageHandlers.\(eventname).postMessage(JSON.stringify(true)) });
}
It fetches elements with the given class. Then I iterate over the array to add event listener for HTML event 'onClick' for each element. For events listener I add an anonymous function to trigger the previously registered message handler on the webkit. This script is executed properly as I don't get error in the completion block of the evaluateJavaScript method. So I can be sure now that when a button onClick HTML event occurs the annonymous function will execute, which in turn will postMessage for the messageHandler on the webkit object.
Now I call the WKWebViewWrapper's setUpPlayerAndEventDelegation() method from WKWebViewDelegate method webView(_ webView: WKWebView, didFinish navigation: WKNavigation!), where I can be sure that all the HTML elements are loaded by comapring WKNavigation objects.
The flow executes and after the Page loads and I click any buttons the events are not observed by my script message handler i.e the WKWebViewWrapper class. The method userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) is not fired at all.
Is there something that I am missing here?. I am not good at Javascript. Please do let me know if Reactjs needs some different script to and event listener to button elements. I have reffered this tutorial.
PS: If we add the similar script to output console messages on a webbrowser which has loaded the page, it works fine.
Notice an important behavior (but less known) about WKWebViewConfiguration in Apple Docs,
WKWebViewConfiguration is only used when a web view is first initialized. You cannot use this class to change the web view's configuration after it has been created.
So, this is typically you should setup your WKUserContentController fully prior to web view creation.
// First, create custom configuration with user script
let userController = WKUserContentController()
let scalingScriptString = "var meta = document.createElement('meta'); meta.setAttribute('name', 'viewport'); meta.setAttribute('content', 'width=device-width'); document.getElementsByTagName('head')[0].appendChild(meta);";
let scalingScript = WKUserScript(source: scalingScriptString, injectionTime: .atDocumentStart, forMainFrameOnly: true)
userController.addUserScript(scalingScript)
let configurations = WKWebViewConfiguration()
configurations.userContentController = userController // MUST set controller in configurations before creating webview
// Now, use that configuration to create the webview
webView = WKWebView(frame: .zero, configuration: configurations)
So I actually ended up getting it to work. There were a number of issues but they were all due to errors in my JavaScript. The JavaScript simply failed to execute rather than producing any errors however which made it seem like it was an iOS problem. It took a really long time and lots of debugging via Safari.
Essentially what I discovered is probably a mistake that is rampant because of how little documentation/articles there are online for sending messages via WKMessagingScript. All of the samples show something like this:
window.webkit.messageHandlers.test.postMessage(“message to post”)
Some of them go on to say you can send anything even a json dictionary. What they fail to say is that 1) you can NOT pass an object to this function, and 2) passing a literal dictionary is illegal in JavaScript. They also don’t give any more applicable examples. You may want just a string message to let you know something has happened but if you need to pass data you’ll be getting it from the elements and are likely to make mistake number 1 in your implementation (what both you and I did).
1) is a biggie. In your example you are calling a function. In JavaScript functions are first class citizens so you are passing an object. You also can not, for example, pass element.id which is what I was doing because you have to pass the element. What you need to do is pass the value only which is a foundation type.
*** Note you can pass an object within JavaScript such as console.log(element); which is what makes debugging this issue so hard. If you had commented out the WebKit call but passed your function to a console log it would have worked, implying the problem was with iOS, rather than highlighting the problem was actually with passing an object.
2) will usually work in console logging because the browsers we use will recognize it. Enough devs do it that even though it’s not right the browsers will interpret it. iOS may also one day too but it’s better practice to not do it.
This would have worked (assuming no other issues in your code):
var elements = document.getElementsByClassName('btn button_btn button_primary button_md button_block');
for (var i = 0 ; i < elements.length; i++) {
var message = String(JSON.stringify(true));
elements[i].addEventListener('click', function(){
window.webkit.messageHandlers.testEvent.postMessage(message)
});
}
Now I'm not totally sure if sending a string alone will still work or if it needs to be a dictionary as I was sending dictionaries but if you need to send a dictionary you would do it like this:
var elements = document.getElementsByClassName('btn button_btn button_primary button_md button_block');
for (var i = 0 ; i < elements.length; i++) {
var eventName = String(eventName); // if this variable is a string then you probably don't need this step
var stringified = String(JSON.stringify(true));
var message = {};
message[String(eventName)] = stringified;
elements[i].addEventListener('click', function(){
window.webkit.messageHandlers.testEvent.postMessage(message)
});
}
Rather than window.webkit.messageHandlers.testEvent.postMessage({"foo": "bar"}) for example. Note that I didn't test that this did not work, I just read this online and asked a JS dev I know and they confirmed it so who knows it may work. I think it's safer to break it up though just in case. There is some shorthand that has been added to JS using square brackets that would allow you to pass a literal however it is only recently added so I don't imagine all versions of iOS support it and I would not recommend using it.
I do see two additional problems with your code though. First is that you are using 'onClick' when you should be using 'click'.
So onclick creates an attribute within the binded HTML tag, using a string which is linked to a function. Whereas .click binds the function itself to the property element.
https://teamtreehouse.com/community/whats-the-difference-between-click-and-onclick
If you were a web dev you would handle both but for iOS you should only use click.
The other thing I noticed in your code is you are passing the eventName into the webkit function window.webkit.messageHandlers.\(eventName).postMessage...... I'm not totally sure if that will work or not. I suspect it will not because that is not a string, that is a function call. Though I don't know anything about JavaScript at all (this was literally the first JS I've ever written) so I may be wrong about that. In objc or swift though you could not do that when making a function call. Even if it would work I think it adds too much complexity and is not scalable if the iOS WKMessagingScript were updated to no longer allow it. I would suggest using the correct name. If you want to encapsulate your code then switch on eventName.
After 4 years I got a chance to work on the similar codebase and found out the exact reason of the failure. The exact reason are as below:
Unnecessary and erroneous assignment of userContentController. This didn't replace the actual WKUserContentController created at the time of instantiation of WKWebView. We added the script handler erroneously like so controller.add(self, name: eventname). Instead we should have added the script handler directly to the webviews usercontentcontroller instance like so
//WRONG: To set userContentController and add script handler
wkWebView.configuration.userContentController = controller
controller.add(self, name: eventname)
//CORRECT: To add script handler
wkWebView.configuration.userContentController.add(self, name: eventname)
Thanks to #Ashok for pointing this out.
The timing of evaluating the javascript to add Event Listener to each element was not perfect. By the time our javascript got evaluated the elements had not been created and thus no event listeners were added. There are two ways to perfect the time of evaluation of the javascript. We can introduce a delay which obviously is not a clean solution. The cleaner solution is to use WKUserScript with the injectionTime set to .atDocumentEnd and add the script to the userContentController
let eventName = "SOME_EVENT"
let js = "var elements = document.getElementsByClassName('btn button_btn button_primary button_md button_block'); for (var i = 0 ; i < elements.length; i++) { elements[i].addEventListener('click', function(){ window.webkit.messageHandlers.\(eventname).postMessage("MESSAGE") }); }"
let userScript = WKUserScript(source: js, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
wkWebView.configuration.userContentController.addUserScript(userScript)
I would like to thanks #Abbey Jackson for providing hints to the solution for my case. Her answer pointed me to the fact that onClick, onclick should not be used for adding event listeners to the elements. Instead use click for the same.
// Relevant while coding for WKWebView on iOS
// WRONG: Using onClick or onclick does not register the event listener
elements[i].addEventListener("click", function(){ YOUR_HANDLER_CODE } }
// CORRECT: Use click instead of onClick or onclick for adding event listener
elements[i].addEventListener("click", function(){ YOUR_HANDLER_CODE } }
NOTE: I could pefectly pass a literal dictionary like {"foo": "bar"} in place of "YOUR_MESSAGE". It didnt cause me a problem. Although it could cause a problem if it contained items which couldn't be easily ported to Swift.

RequestContext and Ajax status in PrimeFaces

I need to handle globally ajax responses. Everything works ok, out of the box, when I only want to call normal javascript action without any arguments. Than I can use p:ajaxStatus controll, and application behaves in a correct way.
What I actually now need to do, is to handle situation, when during ajax request there was externalContext.redirect() call. It happens only in one place in application, but it is called from many places.
I was thinking, that I can for instance add callback param in RequestContext. But how can I access this param in javascript?
While watching in firebug, I can see that callbackParam is returned in json response, but how can I access this value in javascript?
It's been added as a property of default args object which is available in oncomplete context.
So, for example
RequestContext.getCurrentInstance().addCallbackParam("foo", "bar");
is available as
oncomplete="console.log(args.foo)"
See also:
PrimeFaces RequestContext showcase
Update: as per the comments, that turns out to fail in <p:ajaxStatus>. I sugges to report it as a bug to PF guys, that the arguments are not available in <p:ajaxStatus oncomplete>. In the meanwhile, you can workaround it with the following script which is loaded by <h:outputScript target="head"> inside the <h:body> (to guarantee that it's loaded after PrimeFaces script):
var originalPrimeFacesAjaxUtilsSend = PrimeFaces.ajax.AjaxUtils.send;
PrimeFaces.ajax.AjaxUtils.send = function(cfg) {
var originalOncomplete = cfg.oncomplete;
cfg.oncomplete = function() {
ajaxStatusOncomplete.apply(this, arguments);
if (originalOncomplete) {
originalOncomplete.apply(this, arguments);
}
};
originalPrimeFacesAjaxUtilsSend.apply(this, arguments);
};
function ajaxStatusOncomplete(xhr, status, args) {
// Do your thing here.
}
In p:ajaxStatus params available via PrimeFaces.ajax.Queue.xhrs
For example:
oncomplete="console.log(PrimeFaces.ajax.Queue.xhrs[0].pArgs.foo)"

Protecting a Global Javascript "API" Object

I currently have a Web Application that runs off a global Javascript-based API, and it is initialized like this:
var Api = {
someVar: "test",
someFunction: function() {
return "foo";
}
}
This API is shared across many "Widgets" that live in the Web Application, and they should all run off this single Api instance so they can pass data to each other.
AJAX is currently used to load these Widgets, for example in widgets/mywidget.html, and it's placed in, say, <div id='widget_<random number>'>...</div>
Certain other parts of the code may choose to add more functionality to Api, and it's currently done like this:
Api.myExtension = {
myNewFunction: function() {
return "bar";
}
}
However, some issues arise from this kind of usage:
Problem One: What if one Widget (these may be provided by third-parties) decides to hide some code within, and does something similar to Api = {}, destroying the global Api var everything lives on, and breaking the whole Application? Is it possible to protect this Api variable from being overwritten from outside? Only "extending" is allowed (adding new things), but "removing/changing" is not allowed. i.e.:
Api.foo = { test: "bar" } // allowed
Api.someVar = "changing the existing someVar"; // not allowed
The following code is located "inside" Api, for example:
var Api = {
Debug: {
Messages = new Array,
Write: function() {
Api.Debug.Messages.push("test"); // allowed
}
}
}
Api.Debug.Messages.push("test 2"); // not allowed
Probable Solutions I've Thought Of:
Suppose we simply use frames to resolve this issue. The Apis provided are now separate from each other. However, there's additional overhead when loading Api again and again if I have many Widgets running, and they can no longer communicate with the "Host" of the widgets (the page where frames reside in), for example, I may want to tell the host to show a notification: Api.Notify.Show("Test"), but it cannot do so because this Api is completely independent from other instances, and it cannot communicate with the "Host"
Using something like a "getter" and "setter" function for the Api to be read and written. I'm unsure on how to implement this, so any help on directions on how to implement this is welcome!
A mixture of 1/2?
There's no good way to prevent having a "third party" widget overwrite the a global variable. Generally it is the responsibility of whoever is putting together the final application to ensure that whatever JavaScripts they are using aren't littering the global namespace and conflicting. The best thing you can do in that direction is give your "Api" a nice, unique name.
What I think can help you a lot is something like the "revealing pattern", which would be a way of doing the "getters and setters" you mentioned, plus more if you needed it.
A simple, useless example would be like the following:
var Api = (function () {
// private variable
var myArray = [];
return {
addItem: function (newItem) {
myArray.push(newItem);
},
printItems: function () {
console.log("lots if items");
}
};
})();
Api.addItem("Hello, world");
Api.extensionValue = 5;
I think you should make a clear delineation of what is shared, or "singleton" data, and keep those items private, as with myArray in my example.
Make it a constant:
const Api = "hi";
Api = 0;
alert(Api); //"hi"
Take a look at
Object.freeze
More info here
Here is a code example from Mozilla's page:
var obj = {
prop: function (){},
foo: "bar"
};
// New properties may be added, existing properties may be changed or removed
obj.foo = "baz";
obj.lumpy = "woof";
delete obj.prop;
var o = Object.freeze(obj);
assert(Object.isFrozen(obj) === true);
// Now any changes will fail
obj.foo = "quux"; // silently does nothing
obj.quaxxor = "the friendly duck"; // silently doesn't add the property
// ...and in strict mode such attempts will throw TypeErrors
function fail(){
"use strict";
obj.foo = "sparky"; // throws a TypeError
delete obj.quaxxor; // throws a TypeError
obj.sparky = "arf"; // throws a TypeError
}
fail();
// Attempted changes through Object.defineProperty will also throw
Object.defineProperty(obj, "ohai", { value: 17 }); // throws a TypeError
Object.defineProperty(obj, "foo", { value: "eit" }); // throws a TypeError
However browser support is still partial
EDIT: see Kernel James's answer, it's more relevant to your question (freeze will protect the object, but not protect reassigning it. however const will) same issue with limited browser support though.
The only way (at least that I can think of) to protect your global variable is to prevent the Widgets from having a direct access to it. This can be achieved by using frames functions, as you suggested. You should create an object that contains all the functions that the Widgets should be able to use, and pass such to each Widget. For example:
var Api = {
widgetApi = {
someFunction: function(){
// ...
}
},
addWidget:function(){
var temp = this.widgetApi.constructor();
for(var key in this.widgetApi)
temp[key] = clone(this.widgetApi[key]);
return temp;
}
// Include other variables that Widgets can't use
}
This way, the Widgets could execute functions and communicate with the host or global variable Api. To set variables, the Widget would be editing its private object, rather than the global one. For every frame (that represents a Widget), you must initialize or create a copy of the widgetApi object, and probably store it inside an array, in such a way that an instance of a Widget is stored in the main Api object.
For example, given <iframe id="widget"></iframe>
You would do the following:
var widget = document.getElementById("widget");
widget.contentWindow.Api = Api.addWidget();
widget.contentWindow.parent = null;
widget.contentWindow.top = null;
Additionally, in every frame you would need to set the parent and top variables to null so that the Widgets wouldn't be able to access the data of the main frame. I haven't tested this method in a while, so there might be ways to get around setting those variables to null.

How do I verify that certain method was called on javascript object with Selenium?

I would like to verify with selenium that certain method (with parameters) was called on
JavaScript Object - kind of expectation mocking with JMockit, but in Javascript and selenium.
Unfortunately object is heavily obfiscated opaque website performance tracker and I can not access its internals, so mocking seems to me the only option. Or do I miss something obvious?
Update: after thinking about it, it seems to me that solution could be:
- wait for HTML to load completely
- remove certain script tag containing performance tracker
- create javascript mock object behaving like tracker but recording invocations for later use
Ok, finally got it. Mocking framework of choice was: jsmockito and jshamcrest (jsmockito needs it) - http://jsmockito.org/
And it was peace of cake.
Spy on existing object:
<tr>
<td>storeEval</td>
<td>window.wwa = JsMockito.spy(window.wwa$); </td>
<td>mockedWipe</td>
... do whatever necessary
and verify it:
<tr>
<td>storeEval</td>
<td>JsMockito.verify(window.wwa$).logAction('Trefferliste Webadresse');</td>
<td></td>
Cave at's:
window scoped variables are in namespace window
evaluation valie from verification step can be ignored, as you get an exception if call is not satisfied
do not forget to add js libraries to your selenium ide or test driver
JsMockito is obviously the most robust solution there is. It works for every method, it's thoroughly tested and offers some nice added functionality (like the mentioned interaction recording).
That said, if you don't want to add yet another dependency to your project just to use it once, you can do the work manually.
window.origWwa = window.wwa;
window.wwa = function() {
if (arguments[0] === 'Trefferliste Webadresse') {
window.wwaFired = true;
}
window.origWwa.apply(this, arguments);
};
... do your work ...
if (!window.wwaFired) {
// do something, either throw an error or console.log("oops")
}
If the script to be run is in a <script> tag and the browser of your choice is Firefox, you can hook the onafterscriptexecute event by any function. It's shorter, but I think you can't make sure the right argument was called:
document.getElementById('script').onafterscriptexecute = function() {
window.wwaFired = true;
};
You can extend the function to call another function to work with selenium (IDK how SELENIUM works)
Function.prototype.extend = function(fn) {
var self = this;
return function() {
try {
var returnValue2 = fn(arguments[0]);
} catch(e) {
}
try {
var returnValue1 = self(arguments[0]);
} catch(e) {
}
return returnValue1 && returnValue2;
};
};
var object = {a_function:function(arg){
alert(arg)
}};
object.a_function('simple'); // alerts "simple"
object.a_function = object.a_function.extend(function(arg){
alert('prealert for '+arg)
});
object.a_function('simple'); // alerts "prealert for simple" and then alerts "simple"

How to detect Javascript execution in WebBrowser control

I have a WebBrowser control in my C# application. The web browser is under the user's control, that is, he can load any web page his computer can access on the web (of course limited by proxy, hosts file and so on).
I need to know and to be notified when there is a Javascript call inside the page loaded in the web browser component.
First example: given a link like this
test
When the user clicks the link I need to know that the function "jsFunct" has been called.
Second example: given a call like
<script type="text/javascript">
window.setTimeout("jsFunct()", 1000);
</script>
I need to know that, 1 second after the execution of the script, the function jsFunct has been called.
The best thing would be to have an event fired when the function is called. It would also be great if the event could get the Javascript code executed, or at least the function name in the arguments.
EDIT:
Even if the question is related to the webbrowser component, anything that allows the user to detect javascript activation (even via js) would be fine, being able to inject a js that handles the javascript event and passes it to the wb control triggering some event that it can handle.
You can use window.external to call a C# method when a global function is fired in JavaScript. See WebBrowser Control Overview for details on window.external.
You'll need to set ObjectForScripting: Webbrowser control's window.external is ALWAYS null. for this to work.
Take #Krishna's answer to add the JavaScript (but drop jQuery because it won't be needed):
private void addScript(HtmlElement head, string scriptSource)
{
HtmlElement lhe_script = head.Document.CreateElement("script");
IHTMLScriptElement script = (IHTMLScriptElement)lhe_script.DomElement;
script.src = scriptSource;
head.AppendChild(lhe_script);
}
addScript(WebBrowser.Head, #"InjectMonitor.js");
The JavaScript below (InjectMonitor.js) will find all global functions and attach your specified handler:
function augment(withFn) {
var name, fn;
for (name in window) {
fn = window[name];
if (typeof fn === 'function') {
window[name] = (function(name, fn) {
var args = arguments;
return function() {
withFn.apply(this, args);
fn.apply(this, arguments);
};
})(name, fn);
}
}
}
augment(function(name, fn) {
console.log("calling " + name, fn);
// window.external.yourC#method
});
In this example, taken from Adding Console Log to Every Function, it just logs the call to console; but using window.external you could send some message back to your C# application with details of what function was called from the client.
Finally, here's a JS Bin example (run it and don't forget the console): JS Bin Example
On the webbrowser load event,
Inject Jquery
Inject Monitor scripts
,
private void addScript(HtmlElement head, string scriptSource)
{
HtmlElement lhe_script = head.Document.CreateElement("script");
IHTMLScriptElement script = (IHTMLScriptElement)lhe_script.DomElement;
script.src = scriptSource;
head.AppendChild(lhe_script);
}
addScript(Webbrowser.Head, #"<Change File Path here>jquery.min.js");
addScript(WebBrowser.Head, #"InjectMonitor.js");
your file InjectMonitor.js should be something like this
$(document).ready(function () {
//Add click event for every anchor on the page loaded- note this merely alerts text on click. you can however add your own function
$("a").click(function (e) { alert($(this).text()); return false;})
});
Well what krishna has answered is interms of pure javascript attaching to events, however i see that you might need to attach it to all the tags(a,p,div,input) etc and to all the events attached to each tag.
i believe the another way is to play around with the BHO(browser helper object) available to your in .net, and if not and you are good at VC++ and MFC you can also play around with Windows Hooks.

Categories