How do I use the onBeforeUnload event with Script#? - javascript

I'm using the Script# library with ASP.NET. I want to listen and respond to the onBeforeUnload browser event.
I am currently intercepting the event like this:
Window.AttachEvent( "onbeforeunload", OnNavigateAway );
...
private void OnNavigateAway()
{
Script.Alert("You're leaving.");
}
But the second parameter to Window.AttachEvent is a DOMEventHandler, which has a return type of void. To use the onBeforeUnload event, I need to be able to return a string value, which the browser uses as the confirmation message.
Is there any way to do this without emitting a script literal or hand coding JavaScript? I would really prefer to stay in the compiled C# -> JavaScript as much as possible.
In case it matters, I'm using version 0.5.5 of the Script# library, which isn't the latest version, but I am restricted to this for now.
UPDATE: DuckMaestro answered my question perfectly, but it still didn't work for me. It is the correct answer to my question in that the compiled JavaScript is exactly what I was expecting and wanting. But it doesn't have the desired effect of causing the browser to issue a warning prompt.
I do have a work-around, though, in case someone else stumbles across this answer and wants to know how I initially hacked it into working. Instead of this:
public delegate string BeforeUnloadDelegate();
...
Window.AttachEvent( "onbeforeunload", (DOMEventHandler) (Object)
new BeforeUnloadDelegate(OnNavigateAway) );
I did this:
Script.Literal( "window.onbeforeunload = this._onNavigateAway" );
This is bad form for a number of reasons. This will only work on the .debug.js class that Script# generates; Script# changes the names in the release version, so the script emitted by the Script.Literal statement won't match up. Also, it negates a lot of the benefits of using Script# in the first place. (For example, using Visual Studio's refactoring tools to rename OnNavigateAway to something else will leave an orphaned reference in the string.) Also, the C# code declares the method as OnNavigateAway, whereas the Script.Literal has to refer to this._onNavigateAway.
Still, if, like me, you're on a deadline and looking for a hack, this is a place to start. If I make any more progress on a more correct version, I'll update this question with the details.
Thanks again to DuckMaestro for answering the question I asked.

I would declare a new delegate type
public delegate string BeforeUnloadCallback();
and then change your attachEvent code to
Window.AttachEvent( "onbeforeunload", (DOMEventHandler)(Object) new BeforeUnloadCallback(OnNavigateAway) );
I'm not positive that will work on 0.5.5, but it's the kind of trick I use from time to time in 0.6.x.

Related

Angular Universal and browser feature checks

When developing a web app with jQuery or normal JavaScript, it is commonplace to check for feature availability first. So for example, if I want to use the document.oncopy event, I should first have something like this to ensure my code doesn't break for lesser browsers:
if ("oncopy" in document) {
// Feature is available
}
I'm a bit puzzled about how this would work in Angular2. I could still use the same if I expect to only run in the browser, but I'm specifically told to leave the DOM alone if I want to use Angular Universal and depend on templates or the DomRenderer instead. This allows the page to be pre-rendered on the server and provides a truly impressive performance gain.
But suppose I want a specific div to be invisible if the document.oncopy is unavailable. My understanding is that this is not recommended:
<div *ngIf="hasFeature()">...</div>
and
hasFeature() {
return 'oncopy' in document;
}
because then I'm still manipulating the DOM. Note that my example is about the document.oncopy but I could choose any feature whatsoever that doesn't have universal support.
I tested this using Chris Nwamba's tutorial on Scotch and added the following to the end of his Home template:
<div *ngIf="hasFeature()">Feature is supported</div>
<div *ngIf="!hasFeature()">Feature is NOT supported</div>
Update: Interestingly, it gave different results on different browsers. On Chrome 55, it executed as it would normally and showed the "Feature is supported" message. On IE11, I received the "not supported" message. In both instances the server log shows a EXCEPTION: document is not defined message, but the page still seems perfectly okay.
So what is the correct way to check for browser features if I want to use Angular Universal?
Update:
I also toyed around with using a field in the template and assigning that field from one of the life cycle hooks. ngAfterContentInit seemed like a fine candidate, but also causes an error on the server. It still runs fine in the browser with no weird effects (that I have noticed so far).
There are two ways to approach this:
Do the check only once the server is done rendering and the client is completely initialised (including the replay of user events done by preboot.js).
Return a reasonable default when the page is running on the server and perform the actual check only in the browser.
I started looking at the first option, but none of the Angular2 life cycle events will help with this. In fact, you can clearly see them all executing on the server and only then on the client.
I then started looking for something usable in preboot.js but quickly realised it was more complex than it needed to be.
So onto option 2 I went. It turns out checking for the browser is as easy as importing and checking isBrowser.
import { isBrowser } from "angular2-universal";
#Component({
// All the usual stuff
})
export class MyComponent {
// ...
hasFeature(): boolean {
return isBrowser && 'oncopy' in document;
}
// ...
}
And then use the template as I showed in the question.
To check if you're running on the server, import and use isNode in exactly the same way. There doesn't seem to be an obvious way to distinguish between Node and ASP.NET Core, but perhaps it's best not to write too much code that specific to platform.

ActiveXObject javascript Events

I want to utilize events from the IE activex object and can't seem to get it to work.
Please see code below and lemme know if any idea's come to mind:
<html>
<head>
<title>Automate IE</title>
<script type="text/javascript" language="javascript">
var ie = new ActiveXObject( "InternetExplorer.Application" );
[...some calls to ie functions...]
</script>
</head>
<body>
This is a test for IE automation.
</body>
Now I want to be able to use events for the 'ie' object as listed here:MSDN IE Events
But can't seem to get it to work...I tried the following solutions (none worked):
Approach 1:
1. eval( "function ie::EventName(){return MyCustomEvent()}" ); - no joy )-:
Approach 2:
2. <script for="ie" event="EventName">some code here</script> - still no joy )-:
This file is saved with the 'HTA' extension - and runs with the MSHTA scripting host
Any advise \ help on how to do this would be much appreciated...thanks!
I've had success with your first method (see here).
From my experience, the parameters of the function definition must exactly match those of the event definition, e.g. for the BeforeNavigate2 event:
function ie::BeforeNavigate2(pDisp, URL, Flags, TargetFrameName, PostData, Headers, Cancel) {
/* do stuff here */
}
Virtually all the Internet Explorer Application events take some parameters, and therefore your eval doesn't work.
(It's probably self-evident, but you have to fill in the actual event name; you cannot call the function whatever you want.)
I would have answered your question sooner but I had two kids in the last three years ;)
I don't think it is possible in an HTA anymore. ActiveXObjects have never supported events in JScript. Before IE11 you could have used VBScript and CreateObject(object, event_prefix) to register event hooks - https://msdn.microsoft.com/en-us/library/xzysf6hc(v=vs.84).aspx (And you only need to register the events in VBScript because the VBScript variables can be accessed in JavaScript.)
If IE<11 is not an option you'll need to use WScript/CScript. Here is a gist for example: https://gist.github.com/subzey/4374329
Executing WScript from an HTA is feasible with the WScript.Shell activex object, but don't get your hopes up because there is no analogous WScript.CreateObject ActiveX object (or anyway to access CreateObject() from JavaScript/JScript.)
To achieve what you want, you'd need to wrap your IE logic up in a WScript/CScript host script that monitors (or polls) a file on your hard drive. Then your HTA application can write commands to that file. If you need a feedback loop your HTA could monitor a command-result file that gets updated when the JScript logic finishes.
I've been a proponent of HTA's since the 90's, and I still use them for personal quick and dirty projects, but the writing is on the wall about their longevity. There are already a bunch of bugs related to the host window since IE10 and Microsoft has confirmed they won't be fixed.
Given that, you might want to investigate Electron as an alternative if you were not relying on IE-specific functionality: http://electron.atom.io/docs/v0.27.0/api/browser-window/

Calling a function in a JavaScript file with Selenium IDE

So, I'm running these Selenium IDE tests against a site I'm working on. Everything about the tests themselves is running fine, except I would like to do a bit of clean-up once I'm done. In my MVC3 Razor based site, I have a JavaScript file with a function that gets a JsonResult from a Controller of mine. That Controller handles the database clean-up that Selenium IDE otherwise couldn't handle.
However, I'm having a hard time finding any sort of documentation on how to do this. I know I can do JavaScript{ myJavascriptGoesHere } as one of the Values for a line in the test, but I can't seem to find a way to tell it to go find my clean-up function.
Is it even possible for Selenium IDE to do this sort of thing?
If it comes down to it, I can just make a separate View to handle the clean-up, but I'd really like to avoid that if possible.
Thanks!
If you want to execute your own JavaScript function that exists in your test page from Selenium IDE, you need to make sure you access it via the window object. If you look at the reference for storeEval for instance, it says:
Note that, by default, the snippet will run in the context of the
"selenium" object itself, so this will refer to the Selenium object.
Use window to refer to the window of your application, e.g.
window.document.getElementById('foo')
So if you have your own function e.g. myFunc(). You need to refer to it as window.myFunc().
This can be very handy for exercising client-side validation without actually submitting the form, e.g. if you want to test a variety of invalid and valid form field values.
If you use runScript, that should already run in the window's context.
This works for me.
IJavaScriptExecutor js = driver as IJavaScriptExecutor;
string title = (string)js.ExecuteScript("myJavascriptGoesHere");
Make sure your javascript works first before using it here!
Actually to access your page javascript space, you need to get the real window of your page : this.browserbot.getUserWindow()
See this statement to get the jQuery entry point in your page (if it has jQuery of course ^^ )
https://stackoverflow.com/a/54887281/2143734

Send Javascript code to browser

Is there a way to send javascript commands to an open web running in a browser from the shell?
Let's say I have stackoverflow.com open with Chrome. Well, I'd like to send something like
alert('hi!');
from the shell, with something similar to the following:
$ send -t Chrome -w "stackoverflow.com" -c "alert('hi!')"
I was wondering this, because if I can write alert('hi!') on the javascript console of Chrome, I should be able to do the same with a call somewhere, right?
I've seen node.js but I think is not possible with that, please, let me know if I'm wrong.
I know the question could seem weird but I'm curious, thanks in advance :)
You can send JavaScript to Firefox through the jssh extension.
http://www.croczilla.com/bits_and_pieces/jssh/
This is what the Watir testing framework uses to automate Firefox.
I don't know of an equivalent for Chrome.
For IE seems like you can use good old VBScript: http://www.autohotkey.com/forum/topic7642.html
Worked for me just fine now with IE8. :)
Edit: to open this very question and alert JS value have this code as .vbs file and run it:
Dim oIE
Set oIE = CreateObject("InternetExplorer.Application")
oIE.Visible = 1
oIE.Navigate "http://stackoverflow.com/questions/4992552/send-javascript-code-to-browser/4992812"
Do While (oIE.Busy)
Wscript.Sleep 10
Loop
oIE.Navigate "javascript:alert(fkey);"
I think it is possible if you write and install some browser addon that would receive your signal, and do the job. Interesting question, ill be tracking it.
It is entirely up to the browser to provide this sort of functionality. In fact, the form of your problem isn't specific even to browsers:
I was wondering this, because if I can [provide some sort of input] to [a program] to make it [do something], I should be able to do the same with a call somewhere, right?
Some programs do indeed provide hooks for scripting, but if they don't, you're out of luck. There is certainly no guarantee that if you can do something via the GUI, then you can trigger the same action from a command line call.
Now the fact that most browsers provide some sort of plugin architecture, makes it much more likely that such a plugin exists that will listen for external input in this way, if this functionality is missing in the base product.
However, this is still going to be very specific to the particular model and even version of the browser you want to control - so if it's something you wanted to release into the wild, you'll need to be very specific with your requirements.
You can send arbitrary code to browser through the address bar! For example in AutoHotKey style,
send F6 //focus the address bar
send ctrl+v //given that your code is in clipboard
send enter
Now there is another question. Can we get the return value of the inject code? The answer is YES!
Assign your return value to document.title, and retrieve the window title from your application.
If the return value is too long (eg. a JSON format string), do the trick that
document.title='calculating...';
document.title=returnValue.subString(0,20);
sleep(10);
document.title=returnValue.subString(20,40);
sleep(10);
document.title=returnValue.subString(40,60);
...
document.title='finished';
Hope it works.

any method to change title of inputbox i.e prompt in javascript

i want to know if there is any way to change title of inputbox i.e prompt in javascript?
nope, you cannot change the title in the native javascript prompt. you could easily write a function of your own, though, which mimics the behavior of the prompt, but the flow won't be exactly the same (i.e. you'll have to use callbacks, rather than a return value, for the user input)
Something like:
function myPrompt(title, message, value, callback) {
// create form, that displays the title, message, and an input box with the value
// append the form to the dom, probably in some elevated (modal) manner
// if the user invoking myPrmopt didn't specify a callback, don't register listeners
if(typeof callback != 'function') return;
// register listeners:
// if there's a close button, equivalent to escaping out of a prompt:
closeBtn.click(function() { callback() }); // not passing any params
okBtn.click(function() { callback(input.value); });
}
If you are talking about changing the title of the window itself, then what i know it is not possible because this method has only two parameters which do not affect the title of the window. See this for more information.
Syntax:
prompt(msg,defaultText)
But you can not change the title which says"
"page at whatever address says...."
Note: The title varies in different browsers.
No, and not only that: you can't really use prompt any more, at all.
IE7 has removed it(*), ostensibly on security grounds. (I find Microsoft's reasoning somewhat spurious on this, especially compared to a lot of the questionable stuff IE has come up with in the past. But it's too late to complain about now.)
So today, for compatibility, you must use an in-document pop-up that runs asynchronously, with a callback function run on completion, similar to David's example. There are many pre-packaged scripts that will do this for you, but it does require that you re-write your calling code to deal with the response in an inline callback function instead of executing directly after the function call.
In any case, alert/confirm/prompt aren't great for usability (as they make the rest of the browser UI unresponsive), aren't very pretty, and have some sneaky concurrency issues in some browsers. If you can get rid of them for all but the most trivial cases (or debugging purposes), that's all for the better.
(*): actually it's still there, but hidden by a security warning infobar which silently prevents it working for at least the first time. This effectively makes the feature as good as useless.
inputbox.title="insert your text here ?";

Categories

Resources