I'm working on the front-end part of a project.
And the specified UI contains a set of dialogs which have same appearance on it.
Functionally speaking, two main of the dialogs behaves just like a MessageBox and ConfirmBox, the same with window.alert and window.confirm.
So, I'm trying to hijack the two functions, that when I call window.alert(msg), it shows my custom dialog:
<div id="dialog_alert">
<p class="dialog_content">Message</p>
<a class="btn-confirm">OK</a>
</div>
This behaves enough similar to the native window.alert.
Now comes the problem.
When I'm trying to hijack the window.confirm, I found it seems not possible:
window.confirm = function(message) {
var $dialog = $('#dialog_confirm');
$dialog.find('.dialog_content').text(message);
$dialog.show();
$dialog.find('.btn-yes').click(function() {
return true;
});
$dialog.find('.btn-no').click(function() {
return false;
});
// My GOD, I must return true or false immediately here.
};
As above, when I try to return the confirm result, because of the single thread/event loop/callback property of javascript, I just cannot work it out.
So, is it possible to hijack the confirm function as it was? I'm curious about an opinion, please help.
Related
I'm working on a fairly simple form using crowd-html elements, which makes everything very simple. As part of our study, we want to see how workers interact with the form, so we have a bunch of basic JS logging. That is all prepared as a JSON and the idea is to log it using AWS API Gateway and AWS Lambda. The code all seems to work in unit tests, but not in the real form. I am trying to do this:
document.querySelector('crowd-form').onsubmit = function (e) {
if (!validateForm()) {
window.alert("Please check the form carefully, it isn't filled out completely!");
e.preventDefault();
} else {
let event_data = {
'specific_scroll_auditor': auditor_scrolled_pixels_specific.submit_callable(),
'specific_clicks_auditor': auditor_clicks_specific.submit_callable(),
'mouse_movements_total': auditor_mouse_movement_total.submit_callable(),
'on_focus_time': auditor_on_focus_time.submit_callable(),
'total_task_time': auditor_total_task_time.submit_callable(),
'focus_changes': auditor_focus_changes.submit_callable()
};
log_client_event('auditors', event_data);
post_event_log()
}
}
Note that the validation bit works, but the logging does not. I've tested post_event_log() on it's own, and that works just fine, so it seems like either 1) for some reason I never get to that else clause, or 2) the submission happens more quickly than I can call the logging functions. (but why, since the validation works?)
I also tried this, borrowed from the turkey code (https://github.com/CuriousG102/turkey) which was our inspiration.
$(window).ready(function () {
window.onbeforeunload = function () {
let event_data = {
'specific_scroll_auditor': auditor_scrolled_pixels_specific.submit_callable(),
'specific_clicks_auditor': auditor_clicks_specific.submit_callable(),
'mouse_movements_total': auditor_mouse_movement_total.submit_callable(),
'on_focus_time': auditor_on_focus_time.submit_callable(),
'total_task_time': auditor_total_task_time.submit_callable(),
'focus_changes': auditor_focus_changes.submit_callable()
};
log_client_event('auditors', event_data);
post_event_log()
}
});
That also doesn't work. I would prefer to do this in some simple way like what I have above, rather than completely rewrite the submit function, but maybe I have to?
your custom UI is placed inside a sandboxed iFrame by Ground Truth. It does that only for the real job, and not for previews (you're code might work while previewing the UI from AWS Console). The sandbox attribute on the iFrame goes like this
sandbox="allow-scripts allow-same-origin allow-forms"
Refer https://www.w3schools.com/tags/att_iframe_sandbox.asp for descriptions. Ajax calls are blocked regardless of the presence of allow-same-origin (not that you could change it in any way). See for a thorough explanation IFRAME sandbox attribute is blocking AJAX calls
This example might help.
It updates the onSubmit function to do some pre-submit validations.
https://github.com/aws-samples/amazon-sagemaker-ground-truth-task-uis/blob/master/images/keypoint-additional-answer-validation.liquid.html
Hope this helps. Let us know if not.
Thank you,
Amazon Mechanical Turk
I have created one application. In the application I have used javascript confirm function a lot.
confirm("Do you want to proceed");
I don't like the default UI of confirm. I want to use customized confirm with better UI.
Problem:
I got some options for customized confirm. But if I will use them I need to change all default confirm methods(needs lot of changes).
Is there any way to achieve this in minimal change.
like:
window.confrim = function() {
/*
What logic I should write which will return the
value(true or false) selected by user.
*/
}
I have one JS file which is imported in all HTML files.
So I can place the above function logic in the common JS file.
The biggest issue with customising confirm is that the native confirm is blocking. So you can just write:
if( confirm("Continue?")) {
doStuff();
}
But your own code can't do that. Instead, you would need to create some kind of callback. An example might be:
myConfirm("Continue?",function() {
doStuff();
},function() {
cancelStuff();
});
Exactly how you implement this is up to you - I actually have a more flexible version of this on my projects, where I make a call of the form:
Dialog("Title", "Contents", [array of buttons]);
// [array of buttons] being an array of objects like:
{
"text": "Button text",
"action": function() {doSomething();},
"optional_extras": "more stuff"
}
The cool thing about writing your own stuff is that you can extend it freely to suit your needs as the project grows.
Confirm box is part of the browser not the DOM. So, its not possible to modify that. You can try custom confirm boxes like http://jqueryui.com/dialog/#modal-confirmation OR
http://onehackoranother.com/projects/jquery/boxy/
I'm learning CasperJS and have been able to login to a website using fill() but haven't been able to using this.evaluate() or this.sendKeys()
What am I doing wrong with this.evaluate() & this.sendKeys()?
This works:
casper.then(function() {
this.fill('form[class="login-form"]', {
'session_key': 'username',
'session_password': 'password'
}, true);
});
However, neither of these do:
casper.then(function() {
this.evaluate(function(username, password) {
document.querySelector('input#login-email').value = username;
document.querySelector('input#login-password').value = password;
document.querySelector('input[value="Sign in"]').click();
}, 'username', 'password');
})
or
casper.then(function() {
this.sendKeys('input#login-email', 'username');
this.sendKeys('input#login-password', 'password');
this.click('input[value="Sign in"]')
})
Since your question is more general than specific, I will try to answer in the same vein.
fill and fillSelectors are there to quickly fill simple forms.
If you have javascript heavy websites, with events being triggered on actions, then you have SendKeys, which will try to trigger those events as they go.
Finally, if SendKeys does not do the job, you can always go with evaluate and trigger those events manually. If you open your browser console and inspect elements you want to make action on, you will see the events attached to them. From there, you can see if they are DOM events or JQuery events, so you can use document.querySelector or $ accordingly. Before coding anything, know that if you jump to your browser javascript console, any code that you execute there will be what you will end up having in your evaluate scope ; You can quickly test your code in your browser before applying it to your script.
I did not go in details, I just went through the surface of "fill() vs evaluate() vs sendKeys()" with my personal experience but to answer your question specifically, we do not have the page HTML so it is hard to tell. There would be many reasons why SendKeys would not work but not evaluate. In your evaluate scope, the selectors might be wrong or an event is missing.
Finally, as Artjom mentioned, for clicking it's always best to go with casper.click(selector)
I am trying to detect when an HBO Go movie has completed using javascript. Unfortunately, HBO Go uses Flash, and I have no Flash experience.
I noticed that when the movie ends, the Chrome javascript console shows this:
00:02:30:0596 TimeEvent.COMPLETE
(anonymous function) # VM12786:1
I followed VM12786:1 and found this:
try { __flash__toXML(console.error("00:02:30:0596 TimeEvent.COMPLETE")) ; } catch (e) { "<exception>" + e + "</exception>"; }
I'm not quite sure what either of these mean. Can someone briefly explain it? I have extensively googled, but haven't found anything that I understand.
And, is there any way that I can detect with javascript or jQuery that this has been triggered?
Here's a briefing on those JS bits:
try {
__flash__toXML(console.error("00:02:30:0596 TimeEvent.COMPLETE"));
} catch (e) {
"<exception>" + e + "</exception>";
}
The __flash__toXML function is a mechanism to allow the Flash program to communicate with the webpage via JavaScript (brief explanation here, unrelated article). It seems like that snippet is part of a larger section that handles the video ending event.
The weird stringy thing seems like a useless piece of code that is just there as a placeholder, but I would need to look at the context to understand it better. As it is, it does nothing.
Here's my answer to your question:
Unfortunately, there's no event you can capture for console actions directly. You would need to replace the functions with your own that trigger a custom event, and then handle that event. This article explains the process excellently. You would need to modify the internal intercept function to trigger an event on the main window, which you can handle in the traditional ways:
$(window).trigger("myapp.console.log");
Note: This may not work for content scripts, but that's advanced and depends on implementation. If you are using something injected into the browser, replacing the function will only affect the content script's sandbox.
I learned on StackOverflow that you can hijack the console functions, as in the example, where I've added an alert to the console.error function.
var conerr = console.error;
console.error = function()
{
alert("console error: " + arguments[0]); /* do stuff here */
return conerr.apply(console, arguments);
}
setTimeout(function() {console.error("00:02:30:0596 TimeEvent.COMPLETE");}, 1000);
I want to bind a function to the closing of a specific facebox? According to the limited documentation at facebox(at github) you could do something like this to bind actions.
$(document).bind('close.facebox', function() {
//do stuff...
})
But the problem with this is that it will bind the same action to all faceboxes created on the page.
So how could I bind different functions to different faceboxes? I have tried a few variants without success (probably due to my not yet masterlevelskills of javascript and jQuery):
Bind one general function as proposed by the documentation and in the function figure out what facebox was closed and do the wanted thing.
Get handle to facebox when created and use that to bind the action:
var fb = $.facebox('foo');
fb.bind('close.facebox', function() { ...do stuff ...})
Call bind on the facebox directly like:
$.facebox('foo').bind('close.facebox', function() { ...do stuff ...})
Probably more variants that I do not remember...
Please help me understand how I should do this (or why I should not try to do this).
After a quick look at the source I can think of a hack (!) to make this work:
Override the facebox#close method with you own.
The scope within this method will give you access to the "close" link which has just been clicked
Now you can traverse "sideways" to your content and use e.g. a data attribute or class name to identify which box you're currently showing
Based on that you can then make a decision what to do.
Here's an example:
HTML:
Foo
Bar
<div id="foo">
<div data-close="foo">Foo</div>
</div>
<div id="bar">
<div data-close="bar">Bar</div>
</div>
JS:
$.facebox.close = function(e) {
var type = $(this).prev().find('div:first').data("close");
switch (type) {
case "foo":
alert("FOO");
break;
case "bar":
alert("BAR");
break;
}
$(document).trigger('close.facebox');
return false
};
$('a.facebox').facebox();
Try it here: http://jsfiddle.net/SU3se/ .
I believe that the plugin makes the assumption that you'll not use it on multiple "different" objects and since you can have only one facebox open at times, this "should" not be an issue. But I can see why someone might want to do it nevertheless.
Please remember that my solution is a hack and really not very pretty. Maybe someone else can think of something better.