I am using navigateToURL for file downloading from server. Is there anyway possible to know when navigateToURL has finished, more like when browser download dialog has opened?
Sometimes it takes 5 seconds to complete, user might get confused and start clicking download button like psychopath, which can result in multiple download dialogs opened.
I want to add some "please wait" text or something before it finishes (I already have one, I just need to know when to stop).
Maybe it can be done using javascript and get info from ExternalInterface?
This is kind of crazy, but I can't think of any other way: you could put the request object into a dictionary which is set to weak reference the keys, and then check on intervals whether the key was removed.
However, I'm not sure what will happen first, either the SWF itself will be disposed or the dictionary will be cleaned. It's also possible that given the one-time-ness of the function the reference to the request object isn't deleted because it is assumed to be deleted together with the whole SWF.
One more thing that I know is that uncaught error events will catch events from navigateToURL - not really helpful, but at least may give you the indication if it didn't work.
One more simple thing I can think of - just disable the button for a short time, like 1-2 seconds. If it worked, no one will see the delay, and if it didn't, they won't be able to press it too often.
private var _requestStore:Dictionary = new Dictionary(true);
private var _timer:Timer = new Timer(10);
. . .
_timer.addEventListener(TimerEvent.TIMER, timerHandler);
. . .
public function openURL(url:String):void
{
var request:URLRequest = new URLRequest(url);
_requestStore[request] = true;
_timer.start();
navigateToURL(request);
}
private function timerHandler(event:TimerEvent):void
{
var found:Boolean;
for (var o:Object in _requestStore)
{
found = true;
break;
}
if (!found) // the request got disposed
}
Is there anyway possible to know when navigateToURL has finished, more
like when browser download dialog has opened?
No, there is not. Once you pass a request onto the browser; the Flash Player no longer has any control or access to it.
You mention using ExternalInterface as part of a possible solution, but how would your HTML/JavaScript page know that a download had been finished?
navigateToURL does not fire a complete event. Try using this event from Adobe's help documentation:
public function URLRequestExample() {
loader = new URLLoader();
configureListeners(loader);
var request:URLRequest = new URLRequest("XMLFile.xml");
try {
loader.load(request);
} catch (error:Error) {
trace("Unable to load requested document.");
}
}
private function configureListeners(dispatcher:IEventDispatcher):void {
dispatcher.addEventListener(Event.COMPLETE, completeHandler);
dispatcher.addEventListener(Event.OPEN, openHandler);
dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
}
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/URLRequest.html#includeExamplesSummary
Related
I'm developing an extension on Photoshop and I need to detect the closing of a document to send information to the server.
My research did not lead me to any solution.
Is there not an event like on ID like :
app.addEventListener('beforeClose', detectClose);
The only solution I have is to store the open documents in an array and make a timer that every x seconds checks if the old array is the same as the new one but it's not a great solution.
Thank you in advance !
Indeed, event listeners are not obvious in Photoshop. Probably the best approach for listeners in Photoshop is to make use of the Notifier(s) event-handler object. See the Photoshop Javascript Reference for more information on usage.
Typically, you create Notifiers using File > Scripts > Scripts Event Manager, where you can choose the "Close Document" Photoshop event and choose a script or an action to run when it happens.
But, if you are creating an extension and need to do this via code, it's a little trickier. Your best bet is to create a Notifier for the close event:
var scriptPath = "/c/scripts/server.jsx";
//note the trailing space in "Cls "
var closeEventNotifierRef = app.notifiers.add("Cls ", File(scriptPath));
Add whatever needs to happen with the server in that server.jsx file. Note that the file will only be called after the document is closed, so I am not sure what info will still be accessible.
Also note that, as far as I know, adding notifiers is persistent, meaning that close notifier and the calling of server.jsx will happen every time after. In other words, the close event notifier will not be deleted once your server.jsx script finishes executing.
Because of this, you may want to add logic inside your server.jsx file to take care of removing the close event notifier at the end. However, this is not as simple, since you no longer have access to the notifier reference created (closeEventNotifierRef). The only way I found was to loop through notifiers:
var notifiersAll = app.notifiers;
var notifierRefs = [];
for (var i = 0; i < notifiersAll.length; i++){
if (notifiersAll[i].event == 'Cls ') {
notifierRefs.push(notifiersAll[i]);
}
}
for (var r = 0; r < notifierRefs.length; r++){
notifierRefs[r].remove();
}
Hope this helps.
So lately I have been learning JS and trying to interact with webpages, scraping at first but now also doing interactions on a specific webpage.
For instance, I have a webpage that contains a button, I want to press this button roughly every 30 seconds and then it refreshes (and the countdown starts again). I wrote to following script to do this:
var klikCount = 0;
function getPlayElement() {
var playElement = document.querySelector('.button_red');
return playElement;
}
function doKlik() {
var playElement = getPlayElement();
klikCount++;
console.log('Watched ' + klikCount);
playElement.click();
setTimeout(doKlik, 30000);
}
doKlik()
But now I need to step up my game, and every time I click the button a new window pops up and I need to perform an action in there too, then close it and go back to the 'main' script.
Is this possible through JS? Please keep in mind I am a total javascript noob and not aware of a lot of basic functionality.
Thank you,
Alex
DOM events have an isTrusted property that is true only when the event has been generated by the user, instead of synthetically, as it is for the el.click() case.
The popup is one of the numerous Web mechanism that works only if the click, or similar action, has been performed by the user, not the code itself.
Giving a page the ability to open infinite amount of popups has never been a great idea so that very long time ago they killed the feature in many ways.
You could, in your own tab/window, create iframes and perform actions within these frames through postMessage, but I'm not sure that's good enough for you.
Regardless, the code that would work if the click was generated from the user, is something like the following:
document.body.addEventListener(
'click',
event => {
const outer = open(
'about:blank',
'blanka',
'menubar=no,location=yes,resizable=no,scrollbars=no,status=yes'
);
outer.document.open();
outer.document.write('This is a pretty big popup!');
// post a message to the opener (aka current window)
outer.document.write(
'<script>opener.postMessage("O hi Mark!", "*");</script>'
);
// set a timer to close the popup
outer.document.write(
'<script>setTimeout(close, 1000)</script>'
);
outer.document.close();
// you could also outer.close()
// instead of waiting the timeout
}
);
// will receive the message and log
// "O hi Mark!"
addEventListener('message', event => {
console.log(event.data);
});
Every popup has an opener, and every different window can communicate via postMessage.
You can read more about window.open in MDN.
This is the first time I get my hands on with automation instruments in xcode The script works well for all button taps but the one making server connection. I don't know the reason
Here is the script I tried so far
var target = UIATarget.localTarget();
target.pushTimeout(4);
target.popTimeout();
var window=target.frontMostApp().mainWindow()
var appScroll=window.scrollViews()[0];
appScroll.logElementTree();
UIATarget.localTarget().delay(2);
appScroll.buttons()[1].tap();
The above script works up to showing the UIActivityIndicator instead of moving to next controller after success
I know There must be a very simple point I am missing. So help me out
UIAutomation attempts to make things "easy" for the developer, but in doing so it can make things very confusing. It sounds like you're getting a reference to window, waiting for a button to appear, then executing .tap() on that button.
I see that you've already considered messing with target.pushTimeout(), which is related to your issue. The timeout system lets you do something that would be impossible in any sane system: get a reference to an element before it exists. I suspect that behind-the-scenes, UIAutomation repeatedly attempts to get the reference you want -- as long as the timeout will allow.
So, in the example you've posted, it's possible for this "feature" to actually hurt you.
var window=target.frontMostApp().mainWindow()
var appScroll=window.scrollViews()[0];
UIATarget.localTarget().delay(2);
appScroll.buttons()[1].tap();
What if the view changes during the 2-second delay? Your reference to target.frontMostApp().mainWindow.scrollViews()[0] may be invalid, or it may not point to the object you think you're pointing at.
We got around this in our Illuminator framework by forgetting about the timeout system altogether, and just manually re-evaluating a given reference until it actually returns something. We called it waitForChildExistence, but the functionality is basically as follows:
var myTimeout = 3; // how long we want to wait
// this function selects an element
// relative to a parent element (target) that we will pass in
var selectorFn = function (myTarget) {
var ret = myTarget.frontMostApp().mainWindow.scrollViews()[0];
// assert that ret exists, is visible, etc
return ret;
}
// re-evaluate our selector until we get something
var element = null;
var later = get_current_time() + myTimeout;
while (element === null && get_current_time() < later) {
try {
element = selectorFn(target);
} catch (e) {
// must not have worked
}
}
// check whether element is still null
// do something with element
For cases where there is a temporary progress dialog, this code will simply wait for it to disappear before successfully returning the element you want.
I've got a greasemonkey script that, when it runs, checks to see if an update is available, and prompts the user to download the update if so. This normally works fine, except that if a user opens multiple tabs simultaneously (say, on starting the browser, or using "Open All in Tabs" for a bookmark folder), the greasemonkey script will ping the user in each tab simultaneously, which is a bit of a PITA for a user.
I think the only communication channel I have between the instances of the script is GM_setValue/GM_getValue, which allows the instances access to a key/value store.
What I need to do is come up with a locking scheme (let's call it GM_setLock/GM_releaseLock), so I can do the following:
GM_setLock();
const tried_update = GM_getValue(available_version);
GM_setValue(available_version, true);
GM_releaseLock();
if (!tried_update) { prompt_user() }
Without the locking I could have multiple instances in different tabs all read GM_getValue(available_version) before any of them get to GM_setValue(available_version, true), so the user could be pinged multiple times.
The thing is, I don't know how to implement locking off the top of my head if I only have access to (what I'm willing to pretend are) an atomic read and an atomic write operation (and no atomic write and return previous value). Any ideas?
You can't quite do it with that syntax in Greasemonkey, but something like this should do what you want:
Wrap the upgrade check (or whatever), like so:
function UpgradeCheckFunction ()
{
//--- Put payload code here.
alert ("I just ran an an upgrade check?!");
}
.
Then define PerformOnceAcrossTabs(), like so:
function PerformOnceAcrossTabs (sName, oFunction)
{
var OldValue = GM_getValue (sName);
if (OldValue)
{
//--- Optionally also do a timestamp check and clear any "locks" that are X hours old.
return;
}
GM_setValue (sName, new Date().toString() );
//--- run payload function here.
(oFunction)();
//--- Clear "Lock".
GM_deleteValue (sName);
}
.
Then call it like so:
PerformOnceAcrossTabs ("UpgradeCheckLock", UpgradeCheckFunction);
I'm writing WatiN tests to test an Ajax web application and have come across a timing issue with Ajax requests.
After an Ajax request is triggered by an action on the page, I'd like WatiN to wait until the request is complete before validating that the page was updated correctly.
I have a feeling that the solution will involve eval-ing JavaScript to register handlers for $.ajaxStart and $.ajaxComplete to track whether requests are in progress. I'll dig into that shortly, but wanted to see if anybody else has already solved this. Seems like it would be a common problem with Ajax testing.
I've created a few WatiN Browser extension methods to solve this problem, but am still interested in other solutions.
The InjectAjaxMonitor method creates a javascript global variable that attaches to the ajaxStart and ajaxComplete events to track the number of requests in progress.
Whenever you need to wait for AJAX requests to complete before moving on, you can then call browserInstance.WaitForAjaxRequest();.
public static class BrowserExtensions
{
public static void WaitForAjaxRequest( this Browser browser )
{
int timeWaitedInMilliseconds = 0;
var maxWaitTimeInMilliseconds = Settings.WaitForCompleteTimeOut*1000;
while ( browser.IsAjaxRequestInProgress()
&& timeWaitedInMilliseconds < maxWaitTimeInMilliseconds )
{
Thread.Sleep( Settings.SleepTime );
timeWaitedInMilliseconds += Settings.SleepTime;
}
}
public static bool IsAjaxRequestInProgress( this Browser browser )
{
var evalResult = browser.Eval( "watinAjaxMonitor.isRequestInProgress()" );
return evalResult == "true";
}
public static void InjectAjaxMonitor( this Browser browser )
{
const string monitorScript =
#"function AjaxMonitor(){"
+ "var ajaxRequestCount = 0;"
+ "$(document).ajaxSend(function(){"
+ " ajaxRequestCount++;"
+ "});"
+ "$(document).ajaxComplete(function(){"
+ " ajaxRequestCount--;"
+ "});"
+ "this.isRequestInProgress = function(){"
+ " return (ajaxRequestCount > 0);"
+ "};"
+ "}"
+ "var watinAjaxMonitor = new AjaxMonitor();";
browser.Eval( monitorScript );
}
}
This solution doesn't work very well because .ajaxStart is called only for the first Ajax request, while .ajaxComplete is called each time an ajax request is finished. if you run a this simple code in your console :
$.ajax({url:"/"}); $.ajax({url:"/"})
and add some logging in the .ajaxStart and .ajaxComplete handler methods, you can see that .ajaxStart handler will be called only once and .ajaxComplete handler twice. So ajaxRequestCount will become negative and all your design is screwed.
I suggest that you use .ajaxSend instead of .ajaxStart if you want to keep your design.
Another solution would be to use .ajaxStop instead of .ajaxComplete, but by doing so, you don't need the ajaxRequestCount, you only need a boolean that say if there are ajax requests running behind the scene.
Very useful information can be found : http://api.jquery.com/category/ajax/global-ajax-event-handlers/
Hope this helps.
I just ran into this issue myself while working on some tests using WatiN. I found that in version 1.1.0.4000 of WatiN (released on May 2nd 2007 (latest version being 2.0 RC2 from December 20th 2009)), it is claimed that better support for handling Ajax in tests were added:
To better support testing of AJAX
enabled websites, this release adds
some more options to your toolbox.
A new method is added that will wait
until some attribute has a certain
value. This might be handy in
situations where you need to wait
until a value of an element gets
updated.
Example:
// Wait until some textfield is enabled
textfield.WaitUntil("disable", false.ToSting, 10);
// Wait until some textfield is visible and enabled
textfield.WaitUntil(new Attribute("visibile", new BoolComparer(true)) && new Attribute("disabled", new BoolComparer(false)));
See the link to the release notes for more information.
I haven't looked into it in detail yet, so I cannot tell in which cases it might be useful or not. But thought it could be worth mentioning in case anybody else comes across this question.