I have just succeeded in creating oAuth authentication for my twitter application using PHP.
I then saw this site and I am surprised how they open a new window, close that window and then continue the request in the initial window?! Can Someone explain with some Javascript (I am guessing they are using this) how they did this?!
I notice when the second window closes they make two GET requests.
I want to be able to do something like this since my users can write content on my site and I do not want that to get deleted. Is there a better way that isn't so obtrusive? (window popping open). If not, I will use their method as I can not think of anything else.
Thanks all
Here's the part of the JavaScript code that is related to that:
TG.util.oauth = {
win: null,
timer: null,
loginUpdate: function() {
$.getJSON('/-login/check?format=json', TG.util.oauth.loginCallback);
},
loginCallback: function(data) {
if (data && data.loggedin) {
TG.util.login.update(data);
}
},
winCheck: function() {
if (!TG.util.oauth.win || TG.util.oauth.win.closed) {
window.clearInterval(TG.util.oauth.timer);
return TG.util.oauth.loginUpdate();
}
},
loginClick: function() {
TG.util.oauth.win = window.open('/-oauth-twitter/request?gotoafter=1&gotor=oauthtwitter&gotop=action%3Dwindowend',
'OAuthTwitterRequest',
'menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes,width=800,height=400');
if (!TG.util.oauth.win) return true;
TG.util.oauth.timer = window.setInterval(TG.util.oauth.winCheck, 300);
return false;
}
};
TG.util.oauth.win = window.open('/-oauth-twitter/request?gotoafter=1&gotor=oauthtwitter&gotop=action%3Dwindowend','OAuthTwitterRequest','menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes,width=800,height=400'); opens the oAuth window, that handles the login
if (!TG.util.oauth.win) return true; returns true if the window isn't open (I guess).
TG.util.oauth.timer = window.setInterval(TG.util.oauth.winCheck, 300); spawns a timer that checks if the login has been done every 300 miliseconds.
Related
There is an ajax function, which displays a notification on the home page, however, every time I enter thehome page, or refresh the F5 page, the notification is displayed again.
How to fix this?
Is there any way to do this, using js jquery or PHP?
Below the code I have:
Controller
public function get_message()
{
$notification= array();
$notification['message'] = 'message test';
$notification['type'] = 1;
echo json_encode($notification);
}
Javascript
/*** variable ***/
var enum_toastr_type = {
success: 1,
info: 2,
warning: 3,
error: 4
}
/*** PageLoad start ***/
$(document).ready(function() {
toastr.options = {
closeButton: true,
positionClass: 'toast-bottom-right',
timeOut: '20000'
}
get_message_ajax();
});
/*** PageLoad end ***/
function show_message_toastr(mensagens) {
$(mensagens).each(function() {
switch (this.tipo) {
case enum_toastr_type.info:
toastr.info(this.message);
break;
case enum_toastr_type.success:
toastr.success(this.message);
break;
case enum_toastr_type.warning:
toastr.warning(this.message);
break;
case enum_toastr_type.error:
toastr.error(this.message);
break;
}
});
}
/*** Ajax start ***/
function get_message_ajax() {
$.ajax({
type: 'GET',
async: false,
contentType: 'application/json; charset=utf-8',
url: "helper/get_message",
success: (function(data) {
//console.log(data);
_obj = JSON.parse(data);
show_message_toastr(_obj);
}),
error: (function(erro) {
handle_ajax_error(erro);
})
});
}
/*** Ajax end ***/
For doing this you will need to set cookies in the browser to track if user has visited this page already. This would also prevent this on page reloads. You can use local storage to store any data in the browser.
// on page load check if user has not already visited this page
var visited = localStorage.getItem('visited');
if(!visited) {
// call your ajax function which displays message
get_message_ajax();
// lets set visited to true so when user loads page next time then get_message_ajax() does not gets called
localStorage.setItem('visited', true);
}
If you need something like; what if user logs out of the system, then you can clear the local storage on logout. Maybe you can add click listner on logout button and can clear local storage.
localStorage.clear(); // this will clear all website data in localStorage
// or you can update visited key;
localStorage.setItem('visited', false);
Or if you want something more advance like even user does not logs out and still you want to show message lets say if user visits after 1 day. Then you can store timestamp with key and parse it back when checking if user visited.
var object = {value: "value", timestamp: new Date().getTime()}
localStorage.setItem("key", JSON.stringify(object));
When accessing the key you can do something like this;
var object = JSON.parse(localStorage.getItem("key")),
dateString = object.timestamp,
now = new Date().getTime().toString();
// here you can compare two time strings and decide to show message.
For different implementation and ideas on how to manipulate time here is some help;
https://developer.mozilla.org/en-US/docs/Web/API/Storage
When do items in HTML5 local storage expire?
I have implemented custom search functionality for my angular js application.
For that I called an Ajax request to fetch the data.
This call happens on change event and that is why it calls my Ajax multiple times.
Please suggest as I am new in angular js.
You can use delay(idle time) into consideration. Like suppose I am typing in search text box If I am idle for 200ms, 400ms or whatever time you want, You can call an AJAX request.
If I type salman it will call api for 6 times. but suppose we will have idle time. we will call when user idle for that specific time.
To implement it in angular, you can use. $watch or bootstrap directives
So your best bet is to give yourself a bit of delay. As noted by Akash, you have to choose the delay time you find acceptable. You also need to make sure that the request is only made after the delay.
Here is one way to do it:
//In your controller
var _timeout;
$scope.fetchSearchResults = function(){
//We will clear the previous timeout because a key has been pressed
clearTimeout(_timeout);
//Set the timeout - if no key is pressed, it will execute. Else the line above will clear it.
_timeout = setTimeout(function(){
var keyword = $scope.searchKeyword.name;
//Do your AJAX request here
//We have delayed the request by 400ms - but you can change it as you please.
}, 400);
}
Your HTML:
<!-- Then in your HTML something similar to: -->
<input ng-model="searchKeyword.name" ng-keyup="fetchSearchResults()" />
Edit:
If you want to go the 'pure' angular way, you'd do it like this:
//In your controller
//NOTE: make sure you've injected $timeout into your controller
var _timeout;
$scope.fetchSearchResults = function(){
//We will clear the previous timeout because a key has been pressed
$timeout.cancel(_timeout);
//Set the timeout - if no key is pressed, it will execute. Else the line above will clear it.
_timeout = $timeout(function(){
var keyword = $scope.searchKeyword.name;
//Do your AJAX request here
//We have delayed the request by 400ms - but you can change it as you please.
}, 400);
}
I definitely recommend #jeanpaul's answer for "debouncing".
In addition to that, when you have potential for multiple concurrent AJAX requests and you want to handle the most recent one, it can be necessary to verify which request it is in your response handler. This is especially important when the responses don't always come in the same order they were requested (ie. an earlier request takes longer to respond than a later one)
A way to solve this is something like:
var activeRequest;
function doRequest(params){
// reqId is the id for the request being made in this function call
var reqId = angular.toJson(params); // I usually md5 hash this
// activeRequest will always be the last reqId sent out
activeRequest = reqId;
$http.get('/api/something', {data: params})
.then(function(res){
if(activeRequest == reqId){
// this is the response for last request
}
else {
// response from previous request (typically gets ignored)
}
});
}
You already accepted the answer but I want to share some code with you.
myapp.factory('formService', ['$http', '$filter', '$q', '$timeout', function ($http, $filter, $q, $timeout) {
var service = {};
service.delayPromise = null;
service.canceler = null;
service.processForm = function (url, formData, delay) {
if (service.delayPromise)
$timeout.cancel(service.delayPromise);
if (service.canceler)
service.canceler.resolve();
service.canceler = $q.defer();
service.delayPromise = $timeout(function (service) {
return service;
}, delay, true, service);
return service.delayPromise.then(function (service) {
service.delayPromise = null;
return $http({
method : 'POST',
url : url,
timeout : service.canceler.promise,
data : formData
});
})
}
return service;
]);
What does this do. It provides formService having processForm function, with accepts url, formData and delay.
processForm function delays submitting with $timeout service. If there are already exist delayed or pending submission it just cancels it.
And in your controller.
myapp.controller('myCtrl', ['formService', function (formService) {
$scope.formData = {};
$scope.pageData = {};
$scope.$watchCollection('formData', function (formData, oldData, scope) {
if (!angular.equals(formData, oldData)) {
var event;
formService.processForm(formData, event, 500).then(function (response) {
if (response.data instanceof Object)
angular.copy(response.data, scope.pageData);
});
}
});
}]);
For the backend of my site, visible only to a few people, I have a system whereby I communicate with a php via ajax like so:
function ajax(url, opts) {
var progress = false, all_responses = [], previousResponseLength = "";
var ajaxOptions = {
dataType: "json",
type: "POST",
url: url,
xhrFields: {
onprogress: function(e) {
if (!e.target.responseText.endsWith("\n")) return;
var response = e.target.responseText.substring(previousResponseLength).trim();
previousResponseLength = e.target.responseText.length;
var responses = response.split(/[\r\n]+/g);
var last_response;
for (var k in responses) {
if (responses[k] === "---START PROGRESS---") {
progress = true;
if (opts.onProgressInit) opts.onProgressInit();
} else if (responses[k] === "---END PROGRESS---") progress = false;
else all_responses.push(last_response = responses[k]);
}
if (progress && last_response !== undefined) opts.onProgress(JSON.parse(all_responses[all_responses.length-1]));
}
},
dataFilter: function(data){
return all_responses[all_responses.length-1];
}
}
$.extend(ajaxOptions, {
onProgress: function(data){
console.log(data);
}
});
return $.ajax(ajaxOptions);
}
And an example of a never-ending php script (until the user closes the connection):
const AJAX_START_PROGRESS = "---START PROGRESS---";
const AJAX_END_PROGRESS = "---END PROGRESS---";
session_write_close(); //fixes problem of stalling entire php environment while script runs
set_time_limit(0); //allows to the script to run indefinitely
output(AJAX_START_PROGRESS);
while(true) {
output(json_encode(["asdasd" => "asasdas"]));
sleep(1);
}
function output($msg) {
echo preg_replace("`[\r\n]+`", "", $msg).PHP_EOL;
ob_flush(); flush();
}
This allows me through 1 ajax request to 'poll' (am I using that term correctly?)
So if I want to execute a very long php script I can now check its progress, and the last response is delivered via jqhxr.done(callback).
Or, as in the example php script, I can open a connection and leave it open. Using sleep(1); It issues an update to the $.ajax object every 1 second.
Every response has to be json encoded, and if the response is 1 very long json that comes over multiple 'onprogress' calls, it waits until the end of the message (if responseText.endsWith("\n")) we're ready!)
My remote shared server didn't allow websockets so I made this. If the user closes the connection, so does the php script.
It's only got to work for a few admins with special privileges, and I don't need to worry about old browsers.
Can anyone see anything wrong with this script? Through googling I haven't found anybody else with this kind of method, so I expect something is wrong with it.
Extensive testing tells me it works just fine.
You invented long polling request, actually it's wide used as fallback to websockets, so nothing wrong with it.
About your code it's hard to say without testing, but when using such methods as long-polling, you need to double check memory leaks on browser side and on server side.
The application I am working on is built in CodeIgniter, and the content is always loaded via ajax into the main content div.
This works without fail normally, apart from after the user has been inactive for a short while.
We haven't completely narrowed down the inactivity time required for the request to fail, but it's around 40 minutes or more of inactivity.
I've tried logging details to the console in the error callback of the AJAX request, but nothing is logged.
I'm thinking that it's related to a session expiry but I can't be sure. I know when using CodeIgniter, there are two sessions which are created automatically (PHPSESSID, and ci_session) so my instinct is that it has something to do with these, or one of them, expiring?
When the request fails the headers, preview, response and cookies tab on chrome's developer tools show nothing.
If anyone has experienced this before, or has any ideas what may be causing the problem, I'd appreciate the input.
Edit:
Below is the AJAX request which is experiencing the above problem.
All links within my application use this loadPage function instead of a standard redirect.
function loadPage(href, type, clickElem, changeHash) {
if(ajax_loading == true) { return false; }
ajax_loading = true;
$('#recording_area').slideUp('slow');
if(typeof queue_countdown !== 'undefined') { clearInterval(queue_countdown); }
if(type == 'sidenav') {
$('#sidenav_accordion .accordion-heading a').removeClass('on');
$('#sidenav_accordion .accordion-inner a').removeClass('on');
$(clickElem).parents('.accordion-group').find('.accordion-heading a').addClass('on');
$(clickElem).addClass('on');
} else {
page_requested = href.replace(/^\/([^\/]*).*$/, '$1');
if(!page_requested) { page_requested = 'dashboard'; }
nav_elem = $('.sidenav a[href="/' + page_requested + '"]');
if(nav_elem.html() != null) {
nav_elem_group = nav_elem.parents().eq(2).children().first().find('a');
if(!nav_elem_group.hasClass('on')) {
if(!nav_elem.parents().eq(2).children().first().next().hasClass('in')) { nav_elem_group.click(); }
$('.sidenav .on').removeClass('on');
nav_elem.addClass('on');
nav_elem_group.addClass('on');
}
}
}
current_ajax_request = $.ajax({
type: 'GET',
url: href,
dataType: 'html',
cache: true,
beforeSend: function() {
},
success: function(data){
$('#map-canvas').remove();
$('.content_wrapper script').each(function(){
$(this).remove();
});
$('#gbox_Customers').remove();
if ($.browser.msie && parseInt($.browser.version, 10) === 7) {
$('.content_wrapper').hide().html(data).show();
$('#content_overlay').hide();
} else {
$('.content_wrapper').fadeOut().html(data).hide().fadeIn();
$('#content_overlay').fadeOut();
}
$('.queue_loading').hide();
console.log('success ended');
},
error: function(xhr,status,error) {
/*
* The below console logs do not fire when the problem is occuring.
*/
console.log('ERROR');
console.log('xhr: ' + xhr);
console.log('status: ' + status);
console.log('error: ' + error);
$('#map-canvas').remove();
$.get('inc.404.php', function(data) {
if($.browser.msie && parseInt($.browser.version, 10) === 7) {
$('.content_wrapper').hide().html(data).show();
} else {
$('.content_wrapper').fadeOut().html(data).hide().fadeIn();
}
});
if ($.browser.msie && parseInt($.browser.version, 10) === 7) {
$('#content_overlay').hide();
} else {
$('#content_overlay').fadeOut();
}
$('.queue_loading').hide();
},
complete: function(data) {
console.log(data);
ajax_loading = false;
set_tooltips();
}
});
if(changeHash != false) {
window.location.hash = "!" + href;
}
}
Edit 2:
After putting several console log's through the function, to see at which point it breaks. The problem decided to disappear. For what reason would adding console logs to the function prevent this issue from occurring?
I'm currently waiting an hour or so to re-test it without the console logs to make sure it isn't a red herring.
Edit 3:
After putting in console logs in the error callback of the AJAX request, it seems that the error callback is not firing. Not quite sure where to look now - as if it was a success, it would surely return the content.
Unsure what's causing your problem. But just in case this helps, here is a solution to a ajax and CI session problem I had.
Ajax requests would fail occasionally because the user would get logged out when the ajax request was made. (Not really sure why)
To fix the issue avoid a session update on ajax requests. To do this create a custom session class that overrides the sess_update method.
application/libraries/MY_Session.php
class MY_Session extends CI_Session
{
public function sess_update()
{
if (!IS_AJAX) {
parent::sess_update();
}
}
}
IS_AJAX is defined in application/config/constants.php
define('IS_AJAX', isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
Hello I am working with an ajax post function, where I send data and my callback from PHP returns some data back. Based on the data returned I make the decision, either to go forward or allow the user to stay on the page and make changes.
if (validateStep(step))
{
if(step==1)
{
var data = document.getElementById('hiddenContact').value;
$.post('/app/controller/action', {'data':data}, function(returndata){if(returndata.match('not Unique'))alert('Contact source already exists'); else if(returndata.match('not posted')){alert("Not posted to the database");return false;}});
}
step = step + 1;
form[0].action = '/app/controller/index/step:'+step;
document.getElementById('step').value = step;
form[0].submit();
}
Here I am trying to stop the application going ahead when the return data is matched to "not posted", and I am throwing an alert and then a return false to stop the operation. I am unable to stop the application from going to next step though. Though it is returned false, the operation continues to the next step, but when I comment the last 4 lines which increment the step, set the action and submit, it stays on the page and the alert is thrown.
Does anybody know what I should do in order halt my process from submission??
AJAX calls are asynchronous. The "false" you are returning is on the success callback, not on the handler you have shown there. So the last four steps always execute, before the AJAX call even reaches the server. You can fix this by changing ajax response callback to deal with this, like so:
if (validateStep(step))
{
var next_step = function() {
step = step + 1;
form[0].action = '/app/controller/index/step:'+step;
document.getElementById('step').value = step;
form[0].submit();
}
if(step==1)
{
var data = document.getElementById('hiddenContact').value;
$.post('/app/controller/action', { 'data':data }, function(returndata) {
if (returndata.match('not Unique')) alert('Contact source already exists');
else if (returndata.match('not posted')) alert("Not posted to the database");
else next_step();
});
}
else next_step();
}
your process to continue to the next step is outside of your IF statement and will always run.
can you not do this:
if (validateStep(step))
{
if(step==1)
{
var data = document.getElementById('hiddenContact').value;
$.post('/app/controller/action', {'data':data}, function(returndata){
if(returndata.match('not Unique')) {
alert('Contact source already exists');
step = step + 1;
form[0].action = '/app/controller/index/step:'+step;
document.getElementById('step').value = step;
form[0].submit();
} else if (returndata.match('not posted')){
alert("Not posted to the database");
return false;
}
});
}
}