How to override the crowd-html submit button to include additional data - javascript

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

Related

Listening on Apache Tapestry form events

I'm a Back-end dev, and recently inherited a couple of legacy Apache Tapestry systems. My skills with Tapestry are null my knowledge on javascript medium.
I want to disable a submit button right before the submit is made to avoid multiple submits.
A very simple
$(document).ready(function () {
$("#form").submit(function () {
$("#submitbutton").attr("disabled", true);
return true;
});
});
approach wont do because the submit event is propagated before Tapestry does the client-side validation, so I could be disabling the button on a submint attempt that will fail validation.
On this question I learned that Tapestry also propagetes its own events, and if I could listen on tapestry:formprocesssubmit That would probably solve my problem.
I have my CreateContract.tml file with the form, fields and buttons that already work, I have my CreateContract.java file with
#Import(library = {
"context:js/jquery.mask.min.js",
"context:js/maintain-contracts.js",
"context:js/zone-overlay.js"},
stylesheet = "context:layout/zone-overlay.css")
And my maintain-contracts.js file with
$(document).ready(function () {
$("#form").on('tapestry:formprepareforsubmit', function () {
console.log("I want to arrive here!");
});
});
But it doesn't work.
On this mailing list thread I see people discussing very similar matters, but they go about listening on events on a different fashion, that I don't quite grasp.
Should I create the listener inside the initializer?
I'm reffering to the event as 'tapestry:formprepareforsubmit' instead of Tapestry.FORM_PREPARE_FOR_SUBMIT_EVENT because on both my maintain-contracts.js and my console the Tapestry variable is empty - why is that?
What about the .on versus .bind versus .observe trichotomy?
the first links's question was solved using ProptypeJS Class.create, but I think i dont have access to that.
I'm I going about that wrong?
Thank you, any help is appreciated.
Not an analysis of why your approach doesn't work, but a useful referral nonetheless:
Geoff Callender, creator of Tapestry JumpStart, has an excellent description of how duplicate form submissions can be avoided using a mixin.
See http://jumpstart.doublenegative.com.au/jumpstart/examples/javascript/creatingmixins1
After reading Tapestry's source code, i found out that the event is not called tapestry:formprepareforsubmit, but t5:form:prepare-for-submit, even though I found no documentation of that anywhere.
So
$(document).ready(function () {
$("#form").on('t5:form:prepare-for-submit', function () {
console.log("I want to arrive here!");
});
});
Works perfectly.

Is it fine to use submit and ajax at the same time?

I am doing CRUD for our website. Our implementation is to use submit but in some cases I need to pass data from JS file to my controller (BTW I am using Codeigniter) so I am now thinking if it is standard to use it at the same time. So far it works for me.
In my experience, pass it all through JS and basically do below. Note it's about as pseudo code as possible. You will need to make changes for it to even compile.
$("#submit").on('click', function(e) {
e.preventDefault();
if(normal_stuff()){
$(this).sumbit();
} else {
fancy_stuff();
}
});

CasperJS - using fill() vs evaluate() vs sendKeys()

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)

Detect console event with javascript

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);

ASP.NET MVC. Check if user is authorized from JavaScript

I'm using ASP.NET MVC Framework 3 and Forms Authentication. I know, how to check on servers side, if the user is authorized for some action (with [Authorize]) and I know, how to check this within an action or a view (with User.Identity.IsAuthenticated or other members of 'User').
What I'm trying to do - is to define some JavaScript code, that will be executed differently, depending if the user is authorized.
Consider such script on the page:
<script>
function Foo(){
if(userAuthorized)
alert("You\'re in the system");
} else {
alert("You\'re not authorized");
}
<script>
Function Foo() is triggered by some event, say click. And I'd like to have an ability to check, if user is authorized, on clients side.
The best solution I've came up with is to actually render global variables initialization in view. Like this:
#if(User.Identity.IsAuthenticated)
{
<script>
var userAuthorized = true;
</script>
}
else
{
<script>
var userAuthorized = false;
</script>
}
But it doesn't seems to me as a good approach. Are there any other ways?
Thanks in advance.
PS: This is a usability issue, of course I'm doing necessary checks on server.
I like the idea in #Gaby's comment, though I am not sure whether that's doable since I don't have the whole picture on your project.
At the very least you can simplify your code by doing...
<script>
var userAuthorized = #User.Identity.IsAuthenticated.ToString().ToLower();
</script>
Another couple of options would be to use a custom HTML data- attribute or create a simple ajax request that asks the server if the user is authenticated.

Categories