PhantomJS/CasperJS -- continue execution after programmatically clicking button that reloads page [duplicate] - authentication

This question already has an answer here:
Cannot get link to be clicked and switch to next page using PhantomJS
(1 answer)
Closed 7 years ago.
I am attempting to automate a website on my remote server using PhantomJS.
For this website I have to log in with my username and password.
Examining the HTML, I see:
<form class="" method="post" action="https://foo.com/login/"
id="foo_login_bar" accept-charset="utf-8">
<input tabindex="1" name="user_name" id="user" value="" type="text">
<input tabindex="2" name="password" id="pass" value="" type="password">
<div class="wrapper_login_button">
<input class="saved_url_for_login" name="login_url"
value="http://foo.com/" type="hidden">
<input tabindex="3" id="login_button" class="btn left login_button"
name="login" value="Login" type="submit">
</div>
</form>
So I try:
var page = require('webpage').create();
page.onConsoleMessage = function(msg) {
console.log('CONSOLE: ' + msg);
};
page.open('http://foo.com', function(status)
{
console.log("Status: " + status);
if(status === "success")
page.evaluate( bot );
page.render('example.png');
phantom.exit();
});
function bot()
{
if( ! Foo.isLoggedIn() ) {
console.log("Not logged in!");
document.getElementById( "user" ).value = "myuser";
document.getElementById( "pass" ).value = "mypass";
document.getElementById( "login_button" ).click();
}
}
Examining the screenshot shows that it has correctly entered text into the user and password fields, but it has failed to refresh the page.
i.e. If I fill out both fields and click the login button on Firefox, it takes me to my account homepage.
I'm guessing that what is happening here is that the code is immediately reaching the screenshot before the page has had a chance to reload.
How can I get execution to continue once the reload has completed?
EDIT: Phantomjs login, redirect and render page after pageLoad finishes

I'm guessing that what is happening here is that the code is immediately reaching the screenshot before the page has had a chance to reload.
You are absolutely right, you need to wait for the page to reload.
In PhantomJS you can register callback functions for when a page is done loading.
var page = require('webpage').create();
var action;
page.onLoadFinished = function(result)
{
page.render('example' + (new Date()).getTime() + '.png');
// Need to check `action` variable because
// this callback will also fire when opening page for the first time
if(action == "loggin in")
{
phantom.exit();
}
}
page.onConsoleMessage = function(msg) {
console.log('CONSOLE: ' + msg);
};
page.open('http://foo.com', function(status)
{
console.log("Status: " + status);
if(status === "success")
{
action = "loggin in";
page.evaluate( bot );
}
});
function bot()
{
if( ! Foo.isLoggedIn() )
{
console.log("Not logged in!");
document.getElementById( "user" ).value = "myuser";
document.getElementById( "pass" ).value = "mypass";
document.getElementById( "login_button" ).click();
}
}

Related

Modal Pop-Up Not Closing Properly After Form Submission

This is a follow-up to the following post:
Modal Pop-Up Displaying Incorrectly When ModelState.IsValid = false Redirect
My Pop-Up validates correctly but after it process the form data it is not getting closed. Once the data gets loaded in the db, I run the following:
TempData["ID"] = status.IssueID;
return RedirectToAction("edit");
Since the Modal doesn't close, the view data gets populated in the modal and not the window.
If I try to use return View("edit"); the underlying page fails because there is no model data on the page.
Here is the current code that I implemented from the post referenced above:
<script>
$('body').on('click', '.modal-link', function () {
var actionUrl = $(this).attr('href');
$.get(actionUrl).done(function (data) {
$('body').find('.modal-content').html(data);
});
$(this).attr('data-target', '#modal-container');
$(this).attr('data-toggle', 'modal');
});
$('body').on('click', '.relative', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var dataToSend = form.serialize();
$.post(actionUrl, dataToSend).done(function (data) {
$('body').find('.modal-content').html(data);
});
})
$('body').on('click', '.close', function () {
$('body').find('#modal-container').modal('hide');
});
$('#CancelModal').on('click', function () {
return false;
});
$("form").submit(function () {
if ($('form').valid()) {
$("input").removeAttr("disabled");
}
});
</script>
Here is the code that I run to open the modal:
<div id="modal-container" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
</div>
</div>
</div>
Add New Status
And here are the actions when I submit data from the modal:
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult CreateEdit(StatusViewModel model)
{
if (ModelState.IsValid)
{
StatusModel status = new StatusModel();
status.IssueID = model.IssueID;
status.StatusDate = DateTime.Today;
status.Status = model.Status;
status.ColorCode = model.ColorCode;
status.NextStep = model.NextStep;
if (model.addedit == "edit")
{
status.UpdatedByNTID = AppHttpContext.Current.Session.GetString("userntid").ToString();
string done = _adoSqlService.UpdateStatus(status);
}
else
{
status.EnteredByNTID = AppHttpContext.Current.Session.GetString("userntid").ToString();
string done = _adoSqlService.InsertStatus(status);
}
TempData["ID"] = status.IssueID;
return RedirectToAction("edit");
}
else
{
return PartialView("_CreateEdit", model);
}
}
Before I implemented the Javascript code as identified in the link, the modal form closed properly but I couldn't validate. After implementation, the modal form validates but the modal receives the redirect instead of closing. What am I doing wrong
the Modal doesn't close, the view data gets populated in the modal and not the window.
It's the expected result, Ajax render the result of redirection to the modal. You should do the redirection in the done function.
Modify the CreateEdit method:
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult CreateEdit(StatusViewModel model)
{
if (ModelState.IsValid)
{
StatusModel status = new StatusModel();
status.IssueID = model.IssueID;
status.StatusDate = DateTime.Today;
status.Status = model.Status;
status.ColorCode = model.ColorCode;
status.NextStep = model.NextStep;
if (model.addedit == "edit")
{
status.UpdatedByNTID = AppHttpContext.Current.Session.GetString("userntid").ToString();
string done = _adoSqlService.UpdateStatus(status);
}
else
{
status.EnteredByNTID = AppHttpContext.Current.Session.GetString("userntid").ToString();
string done = _adoSqlService.InsertStatus(status);
}
TempData["ID"] = status.IssueID;
}
return PartialView("_CreateEdit", model);
}
Add a hidden input in the partial view to mark if the returned model has passed the validation.
<input name="IsValid" type="hidden" value="#ViewData.ModelState.IsValid.ToString()" />
Then determine whether to redirect in the script:
$('body').on('click', '.relative', function (e) {
e.preventDefault();
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr('action');
var dataToSend = form.serialize();
$.post(actionUrl, dataToSend).done(function (data) {
$('body').find('.modal-content').html(data);
var isValid = $('body').find('[name="IsValid"]').val() == 'True';
if (isValid) {
$('body').find('#modal-container').modal('hide');
window.location.href = "/Issue/Edit";
}
});
})
Result:

how to make my android App faster using titanium App

I have noticed when i deployed App in Android device using titanium Alloy, Its working slowly and it seem like android App need time to redirect to next page after touch and click.it goes to next page within 3 or 4 seconds after i clicked on any UI elements(Button,view,label,image)
On other side, its working perfectly with IOS devices (iphone and ipad)
I don't know what should exactly a problem with android.I also reset my factory data in android and tested app again but still issues arrives
Is this android touch/click issue?
Please feedback on my issues and give me your suggestion how to fix it. Thanks in advance
Your problem is not the device, but probably is your login's API. I suggest you insert an indicator to bridge the waiting time like this:
----index.xml----
<Alloy>
<Window class="login_container" height="auto" horizontalWrap="true">
<ActivityIndicator id="activityIndicator" message="Wait please..."/>
----index.js----
function login(e) {
var uname = $.username.value.split(' ').join('');
var pwd = $.password.value.split(' ').join('');
if(uname == ""){
alert("Enter username.");
return false;
}
if(pwd == ""){
alert("Enter password.");
return false;
}
$.activityIndicator.show();
And before change controller add
$.activityIndicator.hide();
Below is my controller,view files for one page in titanium
----index.js---
function login(e) {
var uname = $.username.value.split(' ').join('');
var pwd = $.password.value.split(' ').join('');
if(uname == ""){
alert("Enter username.");
return false;
}
if(pwd == ""){
alert("Enter password.");
return false;
}
//if(results.length == 0){
if (Titanium.Network.networkType === Titanium.Network.NETWORK_NONE) {
alert('There is no internet connection.');
return false;
}
var loginReq = Titanium.Network.createHTTPClient();
var params = {
func : "'"+Ti.Utils.base64encode('check_login')+"'",
username : uname,
password : pwd
};
loginReq.onload = function()
{
var json = this.responseText;
var response = JSON.parse(json);
if(response == 'account_inactive'){
alert('Your account has been inactive. Please contact to your company');
//$.index.close();
var index = Alloy.createController('index').getView();
index.open();
return false;
}
if(response == 'invalid'){
alert('Invalid username or password');
//$.index.close();
var index = Alloy.createController('index').getView();
index.open();
return false;
}
else
{
results = {
iuser_id: response.iuser_id,
signup_ids: response.signup_ids,
staff_id : response.staff_id,
vusername: response.vusername,
vfirst_name: response.vfirst_name,
vlast_name: response.vlast_name,
vemail : response.vemail,
vpwd : response.vpwd
};
Ti.App.Properties.setObject("user_session",results);
results = null;
var flag = '';
if (!Ti.App.Properties.hasProperty('installed'))
{
Ti.App.Properties.setBool('app:isLoggedIn', true);
Ti.App.Properties.hasProperty('installed');
Ti.App.Properties.setBool('installed', true);
var th_sign = Alloy.createController('login').getView();
th_sign.open();
}
else
{
var th_sign = Alloy.createController('account').getView();
th_sign.open();
}
}
json = null;
response = null;
};
if(os_name == 'android'){
loginReq.open("GET", WEB_ROOT+"get_init.php");
}
else{
loginReq.open("POST", WEB_ROOT+"get_init.php");
}
loginReq.send(params);
}
$.index.open();
----index.xml-------
<Alloy>
<Window class="login_container" height="auto" horizontalWrap="true">
<ScrollView id="scrollView_index" showVerticalScrollIndicator="true" height="100%" width="100%" scrollType="vertical">
<View id="index_view">
<ImageView class="logo" image="/images/login/logo.png" top='25' />
<TextField id="username" class="usernameTxt" value="" border="0" top="230" />
<TextField id="password" class="passwordTxt" value="" border="0" top="275" />
<Button id="loginButton" class="login_bg" onClick="login">Login</Button>
</View>
</ScrollView>
</Window>
</Alloy>
I get understood what You said and explained by use of Activity indicator to wait for some time But that will solve problem only for Login Activity. But wherever I used UI utilities like, (Button Onclick, Label onclick, Image Onclick, View Onclick) It takes at least 4 to 5 seconds time to redirect to next page. I also used Loader between switching of two pages But still it takes time(4 to 5 seconds) to effect click event and redirect to next page

Getting data from another page using XMLHttpRequest

Good morning everyone. I tried creating a site that could get information from another page and feed the response into a div tag, but it didnt work. I checked with a very similar one i learnt from. Here is the HTML code.
<html>
<head>
<script>
function checkit(){
var samxml; var username;
if (window.XMLHttpRequest){
samxml = new XMLHttpRequest();}
else {
samxml = new ActiveXObject("Microsoft.XMLHTTP");
}
samxml.onreadystatechange = function() {
if (samxml.readyState == 4 && samxml.status == 200){
document.getElementById("check").innerHTML = samxml.responseText;}
}
username = document.getElementById("username").value;
samxml.open("POST", "check.php",true);
samxml.send( "username" );
}
}
</script>
</head>
<body>
<form>
<label for ="username">User ID:</label>
<input type = "text" name = "username" id = "username"/>
<div id = "check"></div>
<button type = "button" onclick = "checkit()">Check</button>
</form>
</body>
</html>
Here is the PHP page:
//php file
<?php
$user = $_POST["username"];
if ($user == "samuel") {
echo "Hmm. Chosen! Choose another one";}
else {
echo "Nice one";}
?>
Thanks so much.

PHP when countdown runs out

So I have a countdown timer that grabs a .php file when the clock hits 0. Only problem is, the php file is opening in a new window. I would like it to be displayed at the bottom of the page somehow.
I don't know anything about javascript or AJAX. Only php and html. Can anyone show a newbie what to do?
<!--START COUNTDOWN TIMER SCRIPT-->
<br>
<script type="text/javascript">
window.onload = function() {
countDown('my_div1', 'timerunout.php', 4); } function countDown(elID, output, seconds) {
var elem = document.getElementById(elID),
start = new Date().getTime(), end = start+seconds*1000,
timer = setInterval(function() {
var now = new Date().getTime(), timeleft = end-now, timeparts;
if( timeleft < 0) {
document.location.href = output;
clearInterval(timer);
}
else {
timeparts = [Math.floor(timeleft/60000),Math.floor(timeleft/1000)%60];
if( timeparts[1] < 10) timeparts[1] = "0"+timeparts[1];
elem.innerHTML = "When the Clock hits Zero...<br> "+timeparts[0]+":"+timeparts[1];
}
},250); // the lower this number, the more accurate the timer. 250 recommended }
</script>
<center>
<font color="#FF0000"><b><h1>
<div id="my_div1">
</div>
</h1></b></font>
</center>
<!--END COUNTDOWN TIMER SCRIPT-->
Ok so I have a countdown timer on index.php, when it hits 0... it opens another php file into the bottom of the page using AJAX. Let's call this timerunout.php
Problem is this... in that Php file is a link.
At the end of that link needs to be an affiliate ID attached to the end of it.
That affiliate ID is only detected when someone types their username at the end of the address in the index.php. Any suggestions?
Here's the code for index.php
window.onload = function() {
countDown('my_div1', 'timerunout.php', 4);
}
function countDown(elID, output, seconds) {
var elem = document.getElementById(elID);
start = new Date().getTime(), end = start+seconds*1000,
timer = setInterval(function() {
var now = new Date().getTime(), timeleft = end-now, timeparts;
if( timeleft < 0) {
//This code creates the AJAX object, which will then be used to send it.
var xmlhttp;
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
} else {// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
//This code parameterizes the object to point at your page in an asynchronous way.
xmlhttp.open("GET","timerunout.php?s1=username",true);
xmlhttp.send(); //Once all parameters are set, send it on it's way.
//Callback. Once the request is in one of it's stages, this will be called.
xmlhttp.onreadystatechange=function() {
//Request done and fetching the page successful?
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
//Sets the HTML of my_div1 to whatever was in timerunout.php
elem.innerHTML=xmlhttp.responseText;
}
}
clearInterval(timer);
} else {
timeparts = [Math.floor(timeleft/60000),Math.floor(timeleft/1000)%60];
if( timeparts[1] < 10) timeparts[1] = "0"+timeparts[1];
elem.innerHTML = "When the Clock hits Zero...<br> "+timeparts[0]+":"+timeparts[1];
}
} ,250); // the lower this number, the more accurate the timer. 250 recommended } </script> <center>
<div id="my_div1"></div> </center> <!--END COUNTDOWN TIMER SCRIPT-->
and here's the timerunout.php
//
// Maybe check $s1 is indeed valid
//
$newurl = sprintf('/join.php?id=%s', urlencode($_GET['s1']));
$coaching = sprintf('/live/webinar-register.php?id=%s',
urlencode($_GET['s1']));
?>
So basically what I'm saying is that in index.php,
username in this line needs to be coming from what the user types in their address bar.
xmlhttp.open("GET","timerunout.php?s1=username",true);
If you want to use the jQuery-Framework, you might go about the matter like this:
$.ajax({
url: "timerunout.php",
data:{ s1:"whateverparametersuitsyourfancy" }
}).done(function(data) {
$('#my_div1').html(data);
});
If you want to go the traditional way, the AJAX call is a bit more complicated. From the w3schools website:
//This code creates the AJAX object, which will then be used to send it.
var xmlhttp;
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
} else {// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
//This code parameterizes the object to point at your page in an asynchronous way.
xmlhttp.open("GET","timerunout.php?s1=whateverparametersuitsyourfancy",true);
xmlhttp.send(); //Once all parameters are set, send it on it's way.
//Callback. Once the request is in one of it's stages, this will be called.
xmlhttp.onreadystatechange=function() {
//Request done and fetching the page successful?
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
//Sets the HTML of my_div1 to whatever was in timerunout.php
document.getElementById("my_div1").innerHTML=xmlhttp.responseText;
}
}
Both codes will send a GET request to the page in question and write the 'echoed' output of the target page to the html tag identified by 'my_div1'.
In your code (I'll use the plain JS example) this may look like this.
<!--START COUNTDOWN TIMER SCRIPT-->
<br>
<script type="text/javascript">
window.onload = function() {
countDown('my_div1', 'timerunout.php', 4);
}
function countDown(elID, output, seconds) {
var elem = document.getElementById(elID);
start = new Date().getTime(), end = start+seconds*1000,
timer = setInterval(function() {
var now = new Date().getTime(), timeleft = end-now, timeparts;
if( timeleft < 0) {
//This code creates the AJAX object, which will then be used to send it.
var xmlhttp;
if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
} else {// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
//This code parameterizes the object to point at your page in an asynchronous way.
xmlhttp.open("GET","timerunout.php?s1=whateverparametersuitsyourfancy",true);
xmlhttp.send(); //Once all parameters are set, send it on it's way.
//Callback. Once the request is in one of it's stages, this will be called.
xmlhttp.onreadystatechange=function() {
//Request done and fetching the page successful?
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
//Sets the HTML of my_div1 to whatever was in timerunout.php
elem.innerHTML=xmlhttp.responseText;
}
}
clearInterval(timer);
} else {
timeparts = [Math.floor(timeleft/60000),Math.floor(timeleft/1000)%60];
if( timeparts[1] < 10) timeparts[1] = "0"+timeparts[1];
elem.innerHTML = "When the Clock hits Zero...<br> "+timeparts[0]+":"+timeparts[1];
}
} ,250); // the lower this number, the more accurate the timer. 250 recommended
}
</script>
<center>
<font color="#FF0000"><b><h1>
<div id="my_div1"></div>
</h1></b></font>
</center>
<!--END COUNTDOWN TIMER SCRIPT-->
Edit: I added a single GET parameter to the AJAX calls, to be used at your convenience.

Google CSE - multiple search forms on the same page

i'm aiming to put 2 search forms on the same wordpress page. i'm using the iframe form code and have already sorted out how to direct that to a search element.
but the form includes the following script:
www.google.com/cse/brand?form=cse-search-box&lang=en
which starts by defining the search box by ID
var f = document.getElementById('cse-search-box');
but if you use multiple forms then you (incorrectly i know) end up with elements that have the same ID.. and the branding+ focus/blur events don't work across both forms.
the form basically looks like:
<form action="/search.php" class="cse-search-box">
<div>
<input type="hidden" name="cx" value="" />
<input type="hidden" name="cof" value="FORID:10" />
<input type="hidden" name="ie" value="UTF-8" />
<input type="text" name="q" size="32" />
<input type="submit" name="sa" value="Search" />
</div>
</form>
<script type="text/javascript" src="//www.google.com/cse/brand?form=cse-search-box&lang=en"></script>
if this were a jquery script i think it'd be easy to change the ID to a class name and do an .each() iteration. but google's code is pure javascript and i'm not familiar with that, though
i read getElementbyClass isn't super reliable.
so is this fixable or not worth worrying over?
eventually i commented out that script from google.com and replaced it w/ my own custom version:
`
if (window.history.navigationMode) {
window.history.navigationMode = 'compatible';
}
jQuery.noConflict();
jQuery(document).ready(function($) { //tells WP to recognize the $ variable
//from google's original code- gets the URL of the current page
var v = document.location.toString();
var existingSiteurl = /(?:[?&]siteurl=)([^&#]*)/.exec(v);
if (existingSiteurl) {
v = decodeURI(existingSiteurl[1]);
}
var delimIndex = v.indexOf('://');
if (delimIndex >= 0) {
v = v.substring(delimIndex + '://'.length, v.length);
}
$(".cse-search-box").each( function() {
var q = $(this).find("input[name=q]");
var bg = "#fff url(http:\x2F\x2Fwww.google.com\x2Fcse\x2Fintl\x2Fen\x2Fimages\x2Fgoogle_custom_search_watermark.gif) left no-repeat";
var b = "#fff";
if (q.val()==""){
q.css("background",bg);
} else {
q.css("background",b);
}
q.focus(function() {
$(this).css("background", b);
});
q.blur(function() {
if($(this).val()==""){
$(this).css("background", bg);
}
});
//adds hidden input with site url
hidden = '<input name="siteurl" type="hidden" value="'+ v +'">'
$(this).append(hidden);
});
}); //end document ready functions
`
and on the search.php page that you are directing the results to (so this is a 2-page search form, i found a tutorial on that online somewhere) you will need:
`
google.load('search', '1', {language : 'en', style : google.loader.themes.MINIMALIST});
/**
* Extracts the users query from the URL.
*/
function getQuery() {
var url = '' + window.location;
var queryStart = url.indexOf('?') + 1;
if (queryStart > 0) {
var parts = url.substr(queryStart).split('&');
for (var i = 0; i < parts.length; i++) {
if (parts[i].length > 2 && parts[i].substr(0, 2) == 'q=') {
return decodeURIComponent(
parts[i].split('=')[1].replace(/\+/g, ' '));
}
}
}
return '';
}
function onLoad() {
// Create a custom search control that uses a CSE restricted to
// code.google.com
var customSearchControl = new google.search.CustomSearchControl)('google_search_id');
var drawOptions = new google.search.DrawOptions();
drawOptions.setAutoComplete(true);
// Draw the control in content div
customSearchControl.draw('results', drawOptions);
// Run a query
customSearchControl.execute(getQuery());
}
google.setOnLoadCallback(onLoad);
`