How to refresh page every 2 seconds? - javascript

I wanna to setup a web messenger. So I want to reload my page every 1 or 2 seconds. Actually I want a silent reload to get new chats from my database. Most methods just reload page and clear all inputs. Please help me.
I tried:
function loadlink(){ $('#links').load('test.php',function () { $(this).unwrap(); }); } loadlink(); setInterval(function(){ loadlink() }, 5000);
And:
<meta http-equiv="refresh" content="2">

This tag refreshes the whole page, not ideal:
meta http-equiv="refresh" content="2"
Here I found a complete article about this.
It uses php, MySql (to store chat and authentication) and vanilla js ajax calls to refresh chat.
As others stated executing ajax requests every 2 seconds might slow down your server. Better to try with 3-5 secs.
This example uses 5 seconds.
It is set by setInterval(), using milliseconds. 5000ms = 5 sec.
Here is the ajax part that updates conversations (copied from the example):
setInterval(() => {
// If the current tab is 2
if (currentChatTab == 2) {
// Use AJAX to update the conversations list
fetch('conversations.php', { cache: 'no-store' }).then(response => response.text()).then(html => {
let doc = (new DOMParser()).parseFromString(html, 'text/html');
document.querySelector('.chat-widget-conversations').innerHTML = doc.querySelector('.chat-widget-conversations').innerHTML;
conversationHandler();
});
// If the current tab is 3 and the conversation ID variable is not NUll
} else if (currentChatTab == 3 && conversationId != null) {
// Use AJAX to update the conversation
fetch('conversation.php?id=' + conversationId, { cache: 'no-store' }).then(response => response.text()).then(html => {
// The following variable will prevent the messages container from automatically scrolling to the bottom if the user previously scrolled up in the chat list
let canScroll = true;
if (document.querySelector('.chat-widget-messages').lastElementChild && document.querySelector('.chat-widget-messages').scrollHeight - document.querySelector('.chat-widget-messages').scrollTop != document.querySelector('.chat-widget-messages').clientHeight) {
canScroll = false;
}
let doc = (new DOMParser()).parseFromString(html, 'text/html');
// Update content
document.querySelector('.chat-widget-messages').innerHTML = doc.querySelector('.chat-widget-messages').innerHTML;
if (canScroll && document.querySelector('.chat-widget-messages').lastElementChild) {
// Scroll to the bottom of the container
document.querySelector('.chat-widget-messages').scrollTop = document.querySelector('.chat-widget-messages').lastElementChild.offsetTop;
}
});
// If the current tab is 3 and the status is Waiting
} else if (currentChatTab == 3 && status == 'Waiting') {
// Attempt to find a new conversation between the user and operator (or vice-versa)
fetch('find_conversation.php', { cache: 'no-store' }).then(response => response.text()).then(data => {
if (data != 'error') {
// Success! Two users are now connected! Retrieve the new conversation
getConversation(data);
}
});
}
}, 5000); // 5 seconds (5000ms) - the lower the number, the more demanding it is on your server.
Note: it has many more parts as well, the ajax call is only a small slice of the cake.

Refreshing your whole page every 2 seconds is not an excellent idea.
You should read more on WebSockets or use ajax

Related

Angular - window - EventListener - refresh main tab when other close

I use Angular 7. I deal with documents When I click on "INDEXER" button, a second tab is opened with content of the first document and a form.
When the form is filled, the second document appears on this second tab etc...
When all the documents are ok, this second tab close and and the first main tab must be refreshed.
Code for second tab :
iterate(index) {
this.loadingAction = false;
if (index < this.workflowList.length) {
this.getDetails(this.workflowList[index]);
} else {
localStorage.setItem('actualise', 'true');
window.close();
}
}
Code for the first tab
ngOnInit() {
const that = this;
// COMMUNICATION INTER ONGLETS
window.addEventListener('storage', (event) => {
console.log(event.key)
// console.log('event storage = LocaleStorage : ' + event.storageArea !== localStorage);
if (event.storageArea !== localStorage) {
return;
}
if (event.key === 'actualise') {
// if (event.storageArea.getItem('actualise') === 'true') {
console.log('appel backend')
this.refresh();
} else {
console.log(localStorage.getItem('actualise'));
}
});
}
Problem is that backend is called multiple times and when there are a lot of documents, it's very long.
I updated code in order the backend is called one time, it works but the screen is not refreshed
Original : Backend called multiple time and screen refresh
Update: backend called one time but screen is not refreshed
How can I solve that ?

Reduce the impact of third-party code (zendesk)

<script
id="ze-snippet"
src="https://static.zdassets.com/ekr/snippet.js?key=some_zendesk_key"
/>
I'm trying to optimize my web site performance. I've faced a big impact of third-party code to my performance, I think all my bundle has a lower size than zendesk code. How can I load it without impacting on the main thread? Should I use the async or defer tags? Or which approach is better for this case?
This seems to be an issue that tortures so many people without a clear solution.
What I managed to do it to reduce the block time by adding this configuration.
window.zESettings = {
webWidget: {
chat: {
connectOnPageLoad: false
}
}
};
ref https://developer.zendesk.com/embeddables/docs/widget/settings#connectonpageload
ps
I did a performance test to my zendesk helpdesk "domain.zendesk.com" and the results there were even worse
I came across this issue recently and made this hack using a function for loading the zendesk script only when you reached certain point of the doc. I know is kind of dirty but it works:
<script defer type="text/javascript">
(function($, win) {
$.fn.inViewport = function(cb) {
return this.each(function(i,el){
function visPx(){
var H = $(this).height(),
r = el.getBoundingClientRect(), t=r.top, b=r.bottom;
return cb.call(el, Math.max(0, t>0? H-t : (b<H?b:H)));
} visPx();
$(win).on("resize scroll", visPx);
});
};
}(jQuery, window));
$('#trigger_div').inViewport(function(px){
if(px) {
//zopim code
}
});
Starting from this article https://www.newmediacampaigns.com/blog/maintaining-great-site-performanc-using-zendesk-web-widget I have implemented a solution that significantly reduces the load time by at least 3 seconds (in Google Lighthouse).
I have created a fake button in the HTML that will load the Zendesk script and open the widget when clicked. It will also load a localStorage item that will prevent this from happening on subsequent page loads.
⚠️ Warning:
The code relies heavily on how the widget is currently implemented (for example it expects a #launcher and a #webWidget element to appear on the page), so it can break as soon as the original code changes, but at least we will have an improvement in the loading times until they fix it.
Here is the most important part of the code:
HTML Button
<button class="zendesk-button">
<span class="left-icon">
<!-- here you insert the icon -->
</span>
<span class="text">Chat</span>
</button>
JavaScript code
// select the button
const zendeskButton = document.querySelector('.zendesk-button');
// add the script to the page
const loadZendeskScript = () => {
const zenDeskScript = document.createElement("script");
zenDeskScript.id = "ze-snippet";
zenDeskScript.src = "https://static.zdassets.com/ekr/snippet.js?key=HERE_YOU_INSERT_YOUR_KEY";
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0] || document.getElementsByTagName('script')[0].parentNode).insertBefore(zenDeskScript, null);
};
// a poller that waits for a condition and executes a callback
const poller = (comparison, callback, timerStep = 250, maxTime = 5000) => {
// why setTimeout instead of setInterval
// https://stackoverflow.com/questions/8682622/using-setinterval-to-do-simplistic-continuous-polling
let currTime = 0;
const checkCondition = () => {
// `comparison` is a function so the condition is always up-to-date
if (comparison() === true) {
callback();
} else if (currTime <= maxTime) {
currTime += timerStep;
setTimeout(checkCondition, timerStep);
}
};
checkCondition(); // calling the function
};
// load the script and execute a callback if provided
const loadZendeskChat = callback => {
loadZendeskScript();
if (callback) {
callback();
}
};
// this function opens the chat
const openZendeskChat = () => {
poller(
() => {
// check that zendesk-related functions are available
return typeof zE !== 'undefined';
},
() => {
// open the widget
zE('webWidget', 'open');
poller(
() => {
// check that the elements exist and that the opacity is already set to "1"
const launcher = document.querySelector('#launcher');
const webWidget = document.querySelector('#webWidget');
return launcher !== null && webWidget !== null && webWidget.style.opacity === '1';
},
() => {
// hide the fake button
zendeskButton.style.opacity = '0';
// save in localStorage
localStorage.setItem('zd_hasOpened', 'true');
}
);
}
);
};
// zendesk management
if (localStorage.getItem('zd_hasOpened')) {
// load the zendesk widget if we find that it was opened
loadZendeskChat();
} else {
// show the fake button if it's the first time it shows
zendeskButton.style.opacity = '1';
}
// This will run when the .zendesk-button element is clicked
zendeskButton.addEventListener('click', () => {
// add a 'Loading' text to the button, as the widget will take some time to load (between 1 and 2 seconds on my laptop)
zendeskButton.querySelector('.text').innerHTML = 'Loading';
// load the zendesk widget
// open the widget and hide the fake button
loadZendeskChat(openZendeskChat);
});
Regarding styles, I have pretty much copied the style in the original widget, converting ems to pixels, but one part I'd like to highlight is the focus style, because in my opinion it helps telling the user that something is happening.
.zendesk-button:focus {
outline: none;
box-shadow: inset 0 0 0 0.21429rem rgb(255 255 255 / 40%) !important;
}

Detect content change on refresh

I'm doing a refresh inside the page to update a div, I'm trying to catch when the content in the div is changed, I tried using "DOMSubtreeModified" but it just detected the refresh every time.
I'm grabbing info from a page (donations.php) that just contains a dollar amount etc: $20.00 it refreshes every 5 seconds to look for new content. It updates okay but I want to trigger an alert on change not every 5 seconds.
function loadlink(){
$.get("donations.php", function(data) {
$('#results').html(data);
});
}
loadlink();
setInterval(function(){
loadlink()
}, 5000);
is my current code, I'm trying to detect a complete change on #results
Its a donation tracker for stjudes charity and I want to trigger an alert on the change.
You can store the old value of data and do a check against it.
(function () {
var dollarVal = "";
function loadlink() {
$.get("donations.php", function (data) {
$('#results').html(data);
if (dollarVal !== data) {
// trigger alert
alert("Value has changed!");
}
dollarVal = data;
});
}
loadlink();
setInterval(loadlink, 5000);
}) ();
If you don't want an alert on the first time load, then do:
if (dollarVal !== "" && dollarVal !== data)

Logging user out after some time of inactivity

I want user to be logged out after some time inactivity. I want this php code to run automatically after some time of user inactivity. It must happen without refreshing the page.
<?php
if (isset($_SESSION['user_login_status'])) {
$max_time = 5; // Maximun inactive time(this time is set in seconds )
$current = time(); // Current time on server
if (!isset($_SESSION['Inactive']))
{ // Create session inactive;
Session::set('Inactive', time()); // Create session inactive;
} else {
$session_life = $current - $_SESSION['Inactive'] ;
if ($session_life > $max_time )
{
Session::destroy(); // This is a function that destroys all sessions and logging out the user
header('location: index.php'); // Redirects to some kinda page
} else {
$_SESSION['Inactive'] = time();
}
}
}
?>
This php code is working and user is logged out after 5 seconds when I refresh the page. But I need this code to be runned after those 5 seconds of inactivity and it should redirect to another page. I have tried some ajax code but it didn't worked.
Any suggestions how can I Run that php code after some time?
A lot of misspelled words. Sorry for that.
Modify the code according to your needs. What this code would do is that if the user refreshes the page within 5 second, the timer will reset and start the count again. If user does not refresh/reload the page within 5 seconds, ajax call will be made to your controller action to log the user off. Return a new url to the ajax call to automatically redirect user to a new page. [FYI, I do not like automatic logoffs, specially such short ones. Of course, most Web servers have session timeouts. I would rather go with those timeouts.]
// add these functions at the bottom of the output html page within <script> tags
// YOU SHOULD CALL setLogoutTimer FUNCTION ON MOUSEMOVE OR SOME USER ACTIVITY EVENT.
// otherwise user will be logged out even when the user is doing something on the page
setLogoutTimer();
function setLogoutTimer() {
var myTimeout;
if (window.sessionStorage) {
myTimeout = sessionStorage.timeoutVar;
if (myTimeout) {
clearTimeout(myTimeout);
}
}
myTimeout = setTimeout(function () { logoutNow(); }, 5000); //adjust the time.
if (window.sessionStorage) {
sessionStorage.timeoutVar = myTimeout;
}
}
function logoutNow() {
if (window.sessionStorage) {
sessionStorage.timeoutVar = null;
}
//MAKE AN AJAX CALL HERE THAT WILL CALL YOUR FUNCTION IN
// CONTROLLER AND RETURN A URL TO ANOTHER PAGE
$.ajax({
url: 'YOUR CONTROLLER ACTION URL',
cache: false,
async:false,
type: 'POST',
success: function (msg) {
window.location.href=msg; //msg is the url of another page returned by the controller
}
});
}

Inactive/browser close - change status to 0 and back to 1 when user returns

I am trying to get my website to set online users' status to 0 when they are inactive or close the browser.
If they reopen the website or get back from idling (after timeout), I want the status to get back to 1 (unless they have been fully logged out due to long absence from the site)
Here is what I tried so far:
Inactive.php
include 'db.php';
mysql_query("UPDATE users SET status = 0 WHERE user_id = ".$_SESSION['user_id']."");
Check if browser closed
window.onbeforeunload = function() {
$.ajax({
url: 'inactive.php',
type: 'GET',
async: false,
timeout: 4000
});
};
Check for idle timeout
var IDLE_TIMEOUT = 60; //seconds
var _idleSecondsCounter = 0;
document.onclick = function() {
_idleSecondsCounter = 0;
};
document.onmousemove = function() {
_idleSecondsCounter = 0;
};
document.onkeypress = function() {
_idleSecondsCounter = 0;
};
window.setInterval(CheckIdleTime, 1000);
function CheckIdleTime() {
_idleSecondsCounter++;
var oPanel = document.getElementById("SecondsUntilExpire");
if (oPanel)
oPanel.innerHTML = (IDLE_TIMEOUT - _idleSecondsCounter) + "";
if (_idleSecondsCounter >= IDLE_TIMEOUT) {
alert("Time expired!");
document.location.href = "inactive.php";
}
}
My query doesn't seem to work. How can I tell it which user to check every x seconds?
The window.onbeforeunload is going to produce a race condition and won't be very reliable. Also you would want to use window.addEventListener('beforeunload', function () {...}); instead
The alert in CheckIdleTime will halt execution of the javascript, so the user will have to interact (click OK) to log out. Otherwise that approach seems fine.
Now for when a user leaves the page, generally you would set your cookies to expire on leaving the site, but it seems you want to have a running tally in your website of the active users.
For that you would probably want a two step approach, actively setting flags and timestamp for "last active." And also running a garbage collection script that sets user to "inactive" if you have not seen any activity from them in a bit.
In the event that you needed truely realtime logs of active users, you might be want to look into Node.js in particular Socket.IO which can deal much better with real time client-server IO.
Its likely far easier to run a query that updates the users to say that they are in fact active
<script>
setInterval(function () {
$.post('active.php');
},
15000 // every 15 seconds
);
</script>
in active.php (assuming you add a new last_active DATETIME, and user_id is an int:
mysql_query("UPDATE users SET status = 1, `last_active` = NOW() WHERE user_id = ". (int)$_SESSION['user_id']."");
mysql_query("UPDATE users SET status = 0 WHERE `status` = 1 AND `last_active` < DATE_SUB(NOW(), INTERVAL 15 SECOND)"); // set all in active who have not pinged in the last 15 seconds
Here might be how the schema looks
CREATE TABLE `users`
`id` IN NOT NULL,
`status` INT(1) DEFAULT 0,
`last_active` DATETIME
);
you likely want to play around a bit with that "inactive" interval, and consider creating an index.
Revised code
This code will make reference to the example I wrote available here >> jquery-idle with jquery-ui Dialog
Libraries used :
jQuery-idletimer
Embedded Library Example:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://thorst.github.io/jquery-idletimer/prod//src/idle-timer.js"></script>
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/smoothness/jquery-ui.css" />
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
Without jQuery dialog :
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://thorst.github.io/jquery-idletimer/prod//src/idle-timer.js"></script>
Please keep in mind that you may switch out the dialog code with whatever your prefered dialog method is. I included jquery-ui for dialog to keep things as simple as possible. This also does not handle the beforeunload event, as you have that covered in your code, however I would suggest read further here >> beforeunload stackoverflow article <<
Explanation
HTML
This line of code is for the placeholder where the countdown timer will be stored. To simplify things, I also use this when the timer has expired to display "Session Expired"
<div id="sessionSecondsRemaining" style="font-size: 22px; font-weight: bolder;"></div>
This is a very simple Modal dialog using jQuery UI. You can expand on it or replace it at your leisure.
<div id="dialog-confirm" title="Logout" style="display: none;">
<p><span class="ui-icon ui-icon-alert" style="float:left; margin:0 7px 20px 0;">Your session has expired.</span></p>
</div>
Without jQuery Dialog
<div id="sessionSecondsRemaining" style="display:none;"></div>
CSS
This is just a small hack due to a bug in the grayed background not displaying properly for jQuery UI modal dialogs (why has this not been fixed yet -- facepalm )
/* override jquery ui overlay style */
.ui-widget-overlay {
background-image: none !important; /* FF fix */
background: #000 url(images/new-ui-overlay.png) 50% 50% repeat-x;
}
Without jQuery Dialog
No CSS needed
Javascript
This section is where you can configure the parameters for jquery-idletimer.
var
session = {
//Logout Settings
inactiveTimeout: 10000, //(ms) The time until we display a warning message
warningTimeout: 10000, //(ms) The time until we log them out
minWarning: 5000, //(ms) If they come back to page (on mobile), The minumum amount, before we just log them out
warningStart: null, //Date time the warning was started
warningTimer: null, //Timer running every second to countdown to logout
logout: function () { //Logout function once warningTimeout has expired
//window.location = settings.autologout.logouturl;
},
//Keepalive Settings
keepaliveTimer: null,
keepaliveUrl: "", // set the Keep Alive URL here (aka keepalive.php)
keepaliveInterval: 5000, //(ms) the interval to call said url
keepAlive: function () {
$.ajax({ url: session.keepaliveUrl });
}
}
;
To add 'keepalive.php' support, simply set the full URL for where keepalive.php is located (and any parameters you wish to pass, since you are using sessions, you shouldn't need any).
keepaliveUrl: "http://example.com/keepalive.php", // set the Keep Alive URL here (aka keepalive.php)
This line, initializes and sets the value in the #sessionSecondsRemaining div.
$('#sessionSecondsRemaining').html(Math.round((session.warningTimeout - diff) / 1000));
This section is where you would put the code that controls your dialog warning the user of a session expiration countdown (usually #sessionSecondsRemaining would be in this dialog)
$( "#dialog-confirm" ).dialog({
resizable: false,
height:140,
modal: true,
buttons: {
"Extend": function() {
clearTimeout(session.warningTimer);
$( this ).dialog( "close" );
},
Cancel: function() {
session.logout();
$( this ).dialog( "close" );
}
}
});
Without jQuery Dialog
Remove the last block
If you notice, 'Extend', terminates the warning timer, and Cancel calls the logout function (also configurable above)
Lastly, this block is very important to what happens in the event the timer counts down to zero, and for controlling the display of the countdown inside #sessionSecondsRemaining
if (remaining >= 0) {
$('#sessionSecondsRemaining').html(remaining);
} else {
$( '#dialog-confirm' ).dialog( "close" );
clearInterval(session.warningTimer);
$( '#sessionSecondsRemaining' ).html('Session Expired');
session.logout();
}
Under the else, is probably the only spot you will really need to modify in the above block. In there, I call the session.logout() function (should really be the last line after dialogs are cleaned up, but this is just a demo). This is where you close the dialogs, and/or redirect the user to the session expired page, or display the message. If staying on the same page, make sure to clearInterval(session.warningTimer);. If not, then that line does not matter.
Without jQuery Dialog
if (remaining >= 0) {
$('#sessionSecondsRemaining').html(remaining);
} else {
clearInterval(session.warningTimer);
session.logout();
}
keepalive.php
if (session_status() !== PHP_SESSION_ACTIVE) { session_start(); }
include 'db.php';
$maxtimeout = 15; // Seconds for max timeout before forcing session reset on other users.
mysql_query("UPDATE users SET status = 1 WHERE user_id = ".$_SESSION['user_id']."");
mysql_query("UPDATE users SET status = 0 WHERE user_id <> ".$_SESSION['user_id']." AND (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(`timestamp_field`)) > " . $maxtimeout . "";
This task should be set to run server-side to cleanup the database from any strays (if you have a lot of activity, then you won't need this script)
cron.php
include 'db.php';
// Set this for a longer timeout than in keepalive.php
$maxtimeout = 90; // Seconds for max timeout before forcing session reset on other users.
mysql_query("UPDATE users SET status = 0 WHERE (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(`timestamp_field`)) > " . $maxtimeout . "";
There is a javascript library that may be helpful.
This is Ifvisible.js.
It will allow you to detect when the user is no longer active.
For example you can do something like this:
//Handle tab switch or browser minimize states
ifvisible.on("blur", function(){
//ajax call for inactive.php -> SET status = 0
});
ifvisible.on("focus", function(){
//ajax call for active.php -> SET status = 1
});
//Detection of inactivity for xx seconds
ifvisible.setIdleDuration(120); // Page will become idle after 120 seconds
ifvisible.on("idle", function(){
//ajax call for inactive.php -> SET status = 0
});
ifvisible.on("wakeup", function(){
//ajax call for active.php -> SET status = 1
});
Of course, you can call the same inactive.php program with a different parameter for know if you want to set the status to 1 or 0.
For example, with your ajax call:
// if inactive : SET status = 0
$.ajax({
url: 'inactive.php?status=0',
type: 'GET',
async: false,
timeout: 4000
});
// if active : SET status = 1
$.ajax({
url: 'inactive.php?status=1',
type: 'GET',
async: false,
timeout: 4000
});
In your Inactive.php :
if ($_GET["status"] == "1") // status = 1 -> active
$tatus = "1";
else // status = 0 -> inactive
$tatus = "0";
mysql_query("UPDATE users SET status = " . $tatus . " WHERE user_id = ".$_SESSION['user_id']."");
go to the website for more infos about Ifvisible.js.
I hope it will help you. :)
This is what I am apply at my system to keep track user still online. I make the client site ping back every minute telling the DB he still online.
About the detect browser close you can check out this Close/kill the session when the browser or tab is closed by Daniel Melo
<!DOCTYPE html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
</head>
<body>
<script type="text/javascript">
var timeLeft = Number(60);
setInterval(function(){
timeLeft--;
if(timeLeft<0){
expiredLogout();
}
$("#timer").html(timeLeft);
//If timer less than 30, show message to user will logout soon
if(timeLeft<30){
$("#logoutMsg").show( "slow" );
}else{
$("#logoutMsg").hide( "slow" );
}
$("#logoutMsg").html('You will logout soon, in '+timeLeft+' sec.');
},1000);
//Initial Function
$(function() {
//Mouse move top up the time left value;
$(document).mousemove(function(event) {
timeLeft = Number(60);
});
stillAlive();
//Every 1 minute ping the active.php
setInterval(function(){ stillAlive();},60000);
});
//Redirect to other page if time out
function expiredLogout(){
window.location = "inactive.php";
};
function stillAlive(){
//Update userID 1 still active
var postVal = {userID:1};
$.post("active.php", postVal, null, "json")
.success(function(data) {})
.error(function() {})
.complete(function() {});
};
</script>
<label id="timer"></label>
<div id="logoutMsg"></div>
</body>
</html>
Demo
The first question would be how you define "idle". What terminates an "idle" period? Bringing the focus to the browser window? Scrolling the page? Clicking on the page? Clicking a button? Clicking a link? - The latter seems to be the approach most sites use, and this can be done on the server side alone: If the user did not open another page on your site for, say, 5 minutes, then he is considered idle. After 15 minutes he is logged out by the system.

Categories