I'm trying to store my script that counts numbers starting from 23,000 to always continue to appear it's "live" and always counting using Web Storage. I've tried implementing this and so far, I can't seem to get it to work. What would be the best solution to get this to work and function to always count even when refreshing, etc? I've included my JS Fiddle and code below. Any help is kindly appreciated!!
EDIT: To clarify.. I'm trying to have a "live" counter always going no matter what when you go to the page, refresh it, whatever. It's just always going and getting bigger no matter what just like my script does.. However, everytime I refresh it starts back at 23,000.
HTML
<span id="liveNumbers">23,000</span>
JS
if(typeof(Storage)!=="undefined")
{
setInterval(function(){
random = (Math.floor((Math.random()*2)+1));
var plus = Math.random() < 0.5 ? 1 : 1;
random = random * plus;
currentnumber = document.getElementById('liveNumbers');
var curnum = parseInt(currentnumber.innerHTML.replace(",",""));
document.getElementById('liveNumbers').innerHTML =
commaSeparateNumber(curnum + random);
}, 3000);
function commaSeparateNumber(val){
while (/(\d+)(\d{3})/.test(val.toString())){
val = val.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
}
return val;
}
}
else
{
// Sorry! No Web Storage support..
}
Here's my attempt: fiddle
The logic:
On first visit (no localStorage data) the counter is reset to 23000.
Counter runs while page is open.
When closing the page, the current counter value is stored together with the current timestamp (lastSessionEnd).
When user loads the page again, the time that has passed since he closed the page is translated into interval cycles which are passed to the randomRange function and added to the stored counter from the last session.
Here's the code:
if(window.localStorage) {
//configs
var updateInterval = 3000; //ms
function randomRange() {
return Math.floor(Math.random()*3)+1; // [1..3] range
}
var counter = +localStorage.getItem('counter');
if (!counter) { //first load
counter = 23000;
} else { //simulate randomness that would have happened while the user was away from the page
var lastSessionEnd = +localStorage.getItem('lastSessionEnd');
for(var l = Math.floor((getUnixTimeStamp() - lastSessionEnd)*1000/updateInterval); l--;) {
counter += randomRange();
}
}
var liveNumbers = document.getElementById('liveNumbers'); //cache DOM query
function refreshDisplay() {
liveNumbers.innerHTML = commaSeparateNumber(counter);
}
refreshDisplay();
setInterval(function() {
counter += randomRange();
refreshDisplay();
}, updateInterval);
function commaSeparateNumber(val) {
while (/(\d+)(\d{3})/.test(val.toString())){
val = val.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");
}
return val;
}
function getUnixTimeStamp() {
return Math.floor(Date.now()/1000);
}
window.addEventListener('beforeunload', function() {
localStorage.setItem('counter', counter);
localStorage.setItem('lastSessionEnd', getUnixTimeStamp());
});
} else {
// Sorry! No Web Storage support..
}
NOTE: this is not perfect, here are the caveats:
As it is done purely in the front-end, it is easily hackable by manipulating the localStorage. Don't use this for important stuff.
As it uses the localStorage API, if the user opens the page in more than one browser (or more than one computer/device), each one will have a different counter. Also, cleaning all personal data will reset the counter.
Finally, there's an interval cycle rounding error, it doesn't account for interrupted interval cycles. E.g. the user closes the page midway through an interval cycle, the next time he opens the page that half-cycle will be discarded and a new one starts. I believe this is a small detail which would take more effort to fix than it's worth, but I'll leave that decision and effort to you.
Related
I'm writing a news display for the company I work at and I'm trying to get the page to refresh after it's looped through the entire length of a JSON array. Currently everything works, but I'm not entirely sure where the refresh command would go. Where it is at the moment is not executing. Here's my relevant code:
var i = 0,
d = null,
x = null,
interval = 3000;
console.log('welcome');
$(document).ready(function(){
fetch();
console.log('fetching');
});
function fetch(){
// get the data *once* when the page loads
$.getJSON('info.json?ver=' + Math.floor(Math.random() * 100), function(data){
// store the data in a global variable 'd'
d = data[0];
console.log('results');
console.log(data);
// create a recurring call to update()
x = setInterval(function(){
update()
}, interval);
});
}
function update(){
console.log('update starting');
// if there isn't an array element, reset to the first once
if (d && !d[i]){
console.log('got the D');
clearInterval(x);
i = 0;
fetch();
return;
if(d[i] >= d.length){
// refresh the window if the variable is longer than the array
console.log('refreshing');
window.location.reload();
}
}
// remove the previous items from the page
$('ul').empty();
// add the next item to the page
$('ul').append(
'<li>' + d[i]['news']
+ '</li>'
);
// increment for the next iteration
i++;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='news'>
<ul></ul>
</div>
$.getJSON('info.json?ver=' + Math.floor(Math.random() * 100), function(data){
//your code
}).done(function( data ) {
window.location.reload();
});
Function written in done section will be executed after complete all code from main function
I have figured this out going in a direction I wasn't originally planning to. I realized that once I included an RNG for version control to my .json file I actually didn't need to refresh the page. I am using an iterative loop, so once the loop completes it goes back to the top, and re-opens the info.json. My RNG looks like this:
$.getJSON('info.json?ver=' + Math.floor(Math.random() * 100) + '.' + Math.floor(Math.random() * 100), function(data){
//code here
}
This means that every time $.getJSON is caled, it's looking at a different version number than it was before, which forces a server check and download, which keeps things in the file updating to the screen on their own. Network sources looked like this:
info.json?ver=1.23
info.json?ver=2.42
info.json?ver=1.15
Definitely not the solution I was looking for, but it is actually a better solution than my question could have asked.
If I understood you question, you just need to know where your reload function is correct?
Well it's window.location.reload();
I'm busy with a webdoc that I'm partially creating on hype, the video are hosted on vimeo (so I need to use the vimeo api for some tasks like seekto) but my difficulties should be limited to js.
the objective is to display a given image at a given time interval of the video.
With my code below, I do get the string "test", "success" and "confirmed success" at the right time in my div id=popimgbox, and I can seek back and forth in the video and still get the right "answear", if I may say so.
Now, I have images that are all stored in the same folder, and all named popimgX.jpg, with X being a number.
I want
to store the URLs of my images in a variable let's say "popimgurl"
that my variable is updated (by a function???) in order to contain the URL of a given immage for a given interval of time of the video
to still be able seekto back and forth in the video and get the right URL at the right time
To do so I created a function increment, and a pair of variable. With the code below, my popimgurl variable is indeed updated once the video reach 3 seconds, but it do not increment only once... untill the video reach 6 seconds, when I want to update my popimgurl variable once again.
I tried to use for with js break and js closure but did not manage for some understandable reasons after thought;
I did quite some try with switch, but I'm stuck with the fact that the case must be string or single numerical value, not numerical interval or comparaison.
thank's in advance for your help :-)
var iframe = $('#vplayer_1')[0];
var player = $f(iframe);
var status = $('.status');
fired = 0;
//my try to sync increment
var dia = (function () {
var n = 0;
return function increment() {return n += 1;}
})();
function dian(){
popimgurl = '${resourcesFolderName}/popimg'+ dia() +'.jpg';
popimgloader = '<img src ="' + popimgurl + '">';
}
// When the player is ready, add listeners for pause, finish, and playProgress
player.addEvent('ready', function() {
status.text('ready');
player.addEvent('pause', onPause);
player.addEvent('finish', onFinish);
player.addEvent('playProgress', onPlayProgress);
});
// Call the API when a button is pressed
$('button').bind('click', function() {
player.api($(this).text().toLowerCase());
});
function onPause(id) {
status.text('paused');
}
function onFinish(id) {
status.text('finished');
}
function onPlayProgress(data, id) {
status.text(data.seconds + 's played');
//my chapters, when I want the img to change within popimgbox
if (data.seconds >= 1) {
popimgbox.innerHTML = "test";
}
if (data.seconds >= 3) {
// popimgbox.style.display = "success"
dian();
popimgbox.innerHTML = popimgurl;
}
if (data.seconds >= 6) {
// popimgbox.style.display = "confirmed success"
dian();
popimgbox.innerHTML = popimgurl;
}
}
PS1: disclamer, I'm a beginer coder, i do my best so excuse my french if my question isn't well formulated or if the answer is somewhere but I was unable to see/understand it
PS2 : i did quite a try with popcornjs, but not way to make it work with vimeoapi and within hype, quite frustrated ;-)
PS3: as this is my first post I would like to thank's you all for the great support available here; I owe you most ;-)
Finally I'll answer myself.
It's a solution that only stand for vimeo, as this is what I use to host my videos, but very little changes have to be done to work with the html5 <video> tag as well.
First you need to define your variables and your intervals:
var intervals =[11.56, 44.08, 115, 125, 127.92, 177.72];
var index;
Then you need to add an event listener timeupdate that return the elapsed time , filter intrevals according to the elapsed time data.seconds or seconds and define the value of index as the indexOf the last entry of your filtered array intervals
player.on('timeupdate', function(data) {
seconds = data.seconds;
index = intervals.indexOf(intervals.filter(function(nb) {
return seconds < nb;
})[0]);
if (diaIndex == -1) {
// do something if seconds > the higher value of your last interval
}
And that's it !
Now for
seconds = [0, 11.56[ --> index = 0
seconds = [11.56, 44.08[ --> index = 1
seconds = [44.08, 115[ --> index = 2
and so on
Now we can use index as a variable for instance to display a given image :
var imgNum = 0;
function diaplayImg(index) {
if(index === imgNum) {
return;
// this will avoid that the same image is releaded on every timeupdate events
}
else {
imgNum =+ index
document.getElementById('myImageWraper').innerHTML = "<img src='img" + imgNum+ ".png'>"
};
}
Don't forget, you need to call the function displayImage() in your timeupdate event listener, it will then be fired every ±250ms but the image won't be reloaded each time
PS : vimeo has realeased its new api between my question and my answer so the question use the old api while the answer use the new one
I have a small program, when you click on an "entry", the editing mode is opened, and the entry is to edit locked for others. There is every 10 seconds sends an ajax request to update the timestamp in the table.
$(".entry-edit").click(function() {
// code
loopLockingVar = setInterval(function() { loopLockingFunction(id) }, 10000);
// code
});
Then I have a cancel button to updating the timestamp in the table to 0 and to clear the interval.
$(".entry-cancel").click(function() {
// code
clearInterval(loopLockingVar);
// code
});
It all works when editing only one entry, but if two or more processed simultaneously, and then click cancel, the interval for the first entry still further...
I have this tried:
var loopLockingVar;
$(".entry-edit").click(function() {
// code
if( ! loopLockingVar) {
loopLockingVar = setInterval(function() { loopLockingFunction(id) }, 10000);
}
// code
});
However, this does not work more if you cancel and again clicks on edit...
You're assigning multiple interval IDs to the same variable which will only hold the interval ID that was assigned to it last. When you clear the interval, only the interval corresponding to that ID will be cleared.
A straightforward solution would be to maintain an array of interval IDs, and then clear all intervals represented in the array. The code could look something like this:
var intervalIds = [];
$(".entry-edit").click(function() {
intervalIds.push(setInterval(function() { loopLockingFunction(id) }, 10000));
});
$(".entry-cancel").click(function() {
for (var i=0; i < intervalIds.length; i++) {
clearInterval(intervalIds[i]);
}
});
maybe you can try like this.
var loopLockingVar;
$(".entry-edit").click(loopLockingVar,function() {
// code
loopLockingVar = setInterval(function() { loopLockingFunction(id) }, 10000);
// code
});
Is it possible to detect situation when page is entered and when the same page is refreshed
if (entered) alert("hi");
if (refreshed) alert("you've refreshed");
Somehow there are some little differences between page rendering when entered and when refreshed and it would be much easier to detect the case than to debug it for me (if its even possible - maybe some browser optimization stuff is causing it).
This isn't an ideal solution, but if your page can load in under 5 seconds than this will work, and assuming you are not navigation to another page, then returning within 5 seconds.
window.onbeforeunload = function(){
window.sessionStorage.setItem('lastvisit', new Date().getTime());
}
var lastVisit = +window.sessionStorage.getItem('lastvisit');
var isRefresh = (new Date().getTime() - lastVisit) < 5000;
console.log(isRefresh);
There is no perfect way of tracking reloads verses new page loads but this solution works in most situations. Use sessionStorage in combination with an unload event:
(function (win) {
'use strict';
var reloaded = false,
ss = win.sessionStorage,
offset = 1000, // 1 second, may need tweaking if
// your page takes a long time to load/where
// this code is located in your page
now = function () {
return (new Date()).getTime();
},
lastUnload = ss.getItem('lastunload'),
loadStatus = document.getElementById('status');
// sessionStorage returns null if nothing was stored
if (lastUnload !== null) {
// sessionStorage returns a string, +lastUnload
// coerces the string held in lastUnload into an integer
// see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/Arithmetic_Operators#-_.28Unary_Negation.29
if (+lastUnload + offset > now()) {
reloaded = true;
}
}
win.addEventListener('unload', function () {
ss.setItem('lastunload', now());
}, false);
if (lastUnload === null) {
loadStatus.innerHTML = 'First visit of session.';
} else if (reloaded) {
loadStatus.innerHTML = 'Page was reloaded.';
} else {
loadStatus.innerHTML = 'Navigated back to page after leaving';
}
}(window));
This code defines a page reload as returning to the page within 1 second of leaving it, so there could be false positives if someone leaves the page and immediately hits the back button but with normal browsing behavior that really shouldn't happen. You can modify the offset variable if you want to give more or less leeway, but 1 second seems to be a good default.
After developing this code I also found this similar answer.
If sessionStorage is available, you can use that.
if (!window.sessionStorage.getItem('visited')) {
//entered
window.sessionStorage.setItem('visited', true);
}
else {
//refreshed
}
More on sessionStorage
I've built a simple JavaScript-based timer for a mobile webapp; for the sake of example:
var a = 0;
setInterval(function() {
console.log('a', a);
a++;
}, 1000);
This runs just fine in both Mobile Safari and Android Browser. It will log to console every second and increment the value of a accordingly. (Okay, Android Browser doesn't have console.log support, but let's assume it does.)
The issue: if the screen times out (i.e. user stopped interacting with the page), the setInterval function pauses. It resumes when the user turns on their screen again. This won't work for me as I need timer to keep running.
The questions: Is there a way to prevent the setInterval function from pausing when the screen times out? If not, is it possible to prevent the screen from timing out? Any other alternatives?
Thanks in advance!
Basically, no. The phone enters a sleep state to save battery when the screen times out. Since you can't see anything anyway, a large number of processing tasks are stopped. Similar things will occur when you change tabs/windows (the page is unloaded from memory). Right now there is no way to request that the device stays on from a web application. Future support in Android for accessing hardware may provide this functionality, but personally I doubt it.
If you need always running support, you'll need to write native applications for both systems (plus on Android it can always run).
You can use the Page Visibility API to detect when the page is hidden or visible. For example, if the user navigates away from the browser and back again or the screen turns off and on.
I used this answer to help create by solution.
You will need to store the time you set your interval. Then when the visibilityChange event listener indicates the document is visible again, you can calculate the amount of time that has passed since you first started the interval and update your data as needed.
In my case I was creating a count down timer in my Angular2 project. My page was running on an iPad and the timer was pausing whenever the screen turned off. So I added the event listener in my ngOnInit(). Then when the screen turned back on I could update my timer to show the correct time left since it was started.
I am using the moment npm package to handle my date time.
The timerInfo object is a class variable that gets updated by the interval callback. self.zone.run() is used to propagate the changes to the DOM so that the updated time gets displayed.
Written in typescript:
private timerInfo:{
days?:number,
hours?:number,
minutes:number,
seconds:number
};
private startTime:Moment = moment();
private timerDuration:number = 20; // in minutes
private timerHandle:any;
ngOnInit() {
this.setVisibilityListener();
}
private setVisibilityListener():void {
var self = this;
var hidden, visibilityState, visibilityChange;
if (typeof document.hidden !== "undefined") {
hidden = "hidden";
visibilityChange = "visibilitychange";
visibilityState = "visibilityState";
}
var document_hidden = document[hidden];
document.addEventListener(visibilityChange, function () {
if (document_hidden != document[hidden]) {
if (document[hidden]) {
// Document hidden
console.log("document hidden");
} else {
// Document shown
console.log("document shown; setCountDownTimer()");
self.setCountDownTimer();
}
document_hidden = document[hidden];
}
});
}
private setCountDownTimer():void {
var self = this;
if (self.startTime) {
var startMoment = moment(self.startTime);
var endMoment = startMoment.add(self.timerDuration, "minutes");
console.log("endMoment: ", endMoment.toISOString());
self.clearTimer();
var eventTime = endMoment.unix();
var currentTime = moment().unix();
var diffTime = eventTime - currentTime;
var duration = moment.duration(diffTime * 1000, 'milliseconds');
var interval = 1000;
// if time to countdown
if (diffTime > 0) {
self.timerHandle = setInterval(() => {
self.zone.run(() => {
var diff = duration.asMilliseconds() - interval;
if (diff < 0) {
self.clearTimer();
self.timerComplete();
} else {
duration = moment.duration(duration.asMilliseconds() - interval, 'milliseconds');
self.timerInfo = {
days: moment.duration(duration).days(),
hours: moment.duration(duration).hours(),
minutes: moment.duration(duration).minutes(),
seconds: moment.duration(duration).seconds()
};
// console.log("timerInfo: ", JSON.stringify(self.timerInfo));
}
});
}, 1000);
} else {
self.timerComplete();
}
}
}
private clearTimer():void {
if (this.timerHandle) {
clearInterval(this.timerHandle);
this.timerHandle = null;
}
}