I am currently working with a javascript that is supposed to remove some unwanted cookies, but for some reason aren't they removed when told to?..
only after certain amount of times trying to remove them, they seem to be removed.. some sort of delayed effect?
here is the code:
const name = 'test_u';
const name1 = 'test_te_s';
function eraseCookie(name) {
document.cookie = name+'=; Max-Age=-99999999;';
}
function removeCookies(cookieA, cookieB) {
setInterval(function() {
if (document.cookie.includes(cookieA) || document.cookie.includes(cookieB))
{
eraseCookie(cookieA);
eraseCookie(cookieB);
var date = new Date();
var timestamp = date.getTime();
console.log(timestamp)
}
},10000);
}
removeCookies(name, name1);
example from console log output:
1555420706478
1555420716477
1555420726487
1555420736487
1555420746497
1555420756487
It runs 6 times before its removed? but why though?
why aren't they removed immediately?
Because you have setInterval which means that that code will be run after some time that you provide, and keep repeating it by that interval. So just remove that setInterval:
function removeCookies(cookieA, cookieB) {
if (document.cookie.includes(cookieA) || document.cookie.includes(cookieB)) {
eraseCookie(cookieA);
eraseCookie(cookieB);
var date = new Date();
var timestamp = date.getTime();
console.log(timestamp)
}
}
And if you want to keep repeating it try this one:
removeCookies(name, name1);
setInterval(() => {
removeCookies(name, name1);
}, 10000);
or
function removeCookies(cookieA, cookieB) {
if (document.cookie.includes(cookieA) || document.cookie.includes(cookieB)) {
eraseCookie(cookieA);
eraseCookie(cookieB);
var date = new Date();
var timestamp = date.getTime();
console.log(timestamp)
}
setInterval(() => {
removeCookies()
}, 10000);
}
removeCookies(name, name1);
so it will first call removeCookies, and then it will keep repeating.
Related
I have a model named 'Deal' which has start_at and end_at attributes. I have implemented a countdown timer using hotwire/stimulus JS.
When the deal starts (start date is in the past, end date is in the future), the countdown timer displaying time left to deal will be shown. e.g Time left to deal: 2 hours, 4 minutes, 30 seconds and so on. It will decrement by 1 second.
If the deal has not yet started (start date is in the future), the page will show "Deal is going to start on #{datetime}".
However, the user needs to refresh the page they are currently on to see a timer if the deal has started in the meantime (i.e. transitioning from "Deal is going to start on #{datetime}" to a countdown timer). I am wondering what's the best way to start the timer without refreshing the page. Thanks.
The way to manage a 'timer' that runs some function every X milliseconds is via the browser's setInterval function.
This function can be used like this - const intervalID = setInterval(myCallback, 500); - where myCallback is the function that will attempt to run every 500ms.
The timer can be 'cancelled' by calling clearInterval and giving it the interval ID that is created as the result of setInterval.
Example HTML
Here we have a basic HTMl structure where we set our controller timer and set the from/to times along with targets that hold the messages based on three states.
These three states are 'before', 'during' (when the current time is between the two times) and 'after'.
<section class="prose m-5">
<div
data-controller="timer"
data-timer-from-value="2022-03-08T10:41:32.111Z"
data-timer-to-value="2022-03-09T11:10:32.111Z"
>
<div style="display: none" data-timer-target="before">
Deal will start on <time data-timer-target="fromTime"></time>
</div>
<div style="display: none" data-timer-target="during">
Deal is active <time data-timer-target="toTimeRelative"></time>
</div>
<div style="display: none" data-timer-target="after">
Deal ended on <time data-timer-target="toTime"></time>
</div>
</div>
</section>
Example Stimulus Controller
This timerController accepts the to and from times as strings (ISO strings are best to use, and remember the nuances of time-zones can be complex).
When the controller connects we do three things; 1. set up a timer to run this.update every X milliseconds and put the timer ID on the class for clearing later as this._timer. 2. Set the time values (the inner time labels for messaging). 3. Run the this.update method the initial time.
this.getTimeData parses the from/to datetime strings and does some basic validation, it also returns these date objects along with a status string which will be one of BEFORE/DURING/AFTER.
this.update - this shows/hides the relevant message parts based on the resolved status.
import { Controller } from '#hotwired/stimulus';
const BEFORE = 'BEFORE';
const DURING = 'DURING';
const AFTER = 'AFTER';
export default class extends Controller {
static values = {
interval: { default: 500, type: Number },
locale: { default: 'en-GB', type: String },
from: String,
to: String,
};
static targets = [
'before',
'during',
'after',
'fromTime',
'toTime',
'toTimeRelative',
];
connect() {
this._timer = setInterval(() => {
this.update();
}, this.intervalValue);
this.setTimeValues();
this.update();
}
getTimeData() {
const from = this.hasFromValue && new Date(this.fromValue);
const to = this.hasToValue && new Date(this.toValue);
if (!from || !to) return;
if (from > to) {
throw new Error('From time must be after to time.');
}
const now = new Date();
const status = (() => {
if (now < from) return BEFORE;
if (now >= from && now <= to) return DURING;
return AFTER;
})();
return { from, to, now, status };
}
setTimeValues() {
const { from, to, now } = this.getTimeData();
const locale = this.localeValue;
const formatter = new Intl.DateTimeFormat(locale, {
dateStyle: 'short',
timeStyle: 'short',
});
this.fromTimeTargets.forEach((element) => {
element.setAttribute('datetime', from);
element.innerText = formatter.format(from);
});
this.toTimeTargets.forEach((element) => {
element.setAttribute('datetime', to);
element.innerText = formatter.format(to);
});
const relativeFormatter = new Intl.RelativeTimeFormat(locale, {
numeric: 'auto',
});
this.toTimeRelativeTargets.forEach((element) => {
element.setAttribute('datetime', to);
element.innerText = relativeFormatter.format(
Math.round((to - now) / 1000),
'seconds'
);
});
}
update() {
const { status } = this.getTimeData();
[
[BEFORE, this.beforeTarget],
[DURING, this.duringTarget],
[AFTER, this.afterTarget],
].forEach(([key, element]) => {
if (key === status) {
element.style.removeProperty('display');
} else {
element.style.setProperty('display', 'none');
}
});
this.setTimeValues();
if (status === AFTER) {
this.stopTimer();
}
}
stopTimer() {
const timer = this._timer;
if (!timer) return;
clearInterval(timer);
}
disconnect() {
// ensure we clean up so the timer is not running if the element gets removed
this.stopTimer();
}
}
Why is my pastPres function not working? It is supposed to change the color for a time block in a calendar depending on whether that block is in the past present or future.
$(document).ready(function () {
$(".saveBtn").on("click", function () {
var description = $(this).siblings(".description").val();
var time = $(this).parent().attr("id")
localStorage.setItem(time, description)
})
function pastPres() {
var blockTime = moment().hour()
$(".time-block").each(function () {
var time = $(this).attr("id")
if (time < blockTime) {
$(this).addClass("past")
} else if(time > blockTime) {
$(this).removeClass("past")
$(this).addClass("future")
} else {
$(this).removeClass("future")
$(this).addClass("present")
}
})
}
pastPres()
var interval = setInterval(pastPres, 15000)
$("#9am .description").val(localStorage.getItem("9am"))
$("#10am .description").val(localStorage.getItem("10am"))
$("#11am .description").val(localStorage.getItem("11am"))
$("#12pm .description").val(localStorage.getItem("12pm"))
$("#1pm .description").val(localStorage.getItem("1pm"))
$("#2pm .description").val(localStorage.getItem("2pm"))
$("#3pm .description").val(localStorage.getItem("3pm"))
$("#4pm .description").val(localStorage.getItem("4pm"))
$("#5pm .description").val(localStorage.getItem("5pm"))
$("#currentDay").text(moment().format("MMMM DD, YYYY"))
})
You are comparing strings. You need to compare time values instead. Since you are using moment you can invoke a new moment instance for the time and let it handle parsing to military time:
function pastPres() {
var blockTime = moment().hour();
$(".time-block").each(function () {
var time = moment($(this).attr("id"), ["hA"]).hour()
if (time < blockTime) {
$(this).addClass("past")
} else if(time > blockTime) {
$(this).removeClass("past")
$(this).addClass("future")
} else {
$(this).removeClass("future")
$(this).addClass("present")
}
})
}
Assuming your .time-block elements are the same as #9am, #10am, etc, it appears you're trying to compare a string to a number like
'9am' < 10
which as far as JavaScript is concerned, is false.
I suggest you add some better data to your elements like
<div id="9pm" data-hour="21" class="time-block">
and use
const time = $(this).data('hour')
Is there any default way in JavaScript to check user activity. If not how to address this issue.
There is no default way of doing this in java script. One way to address this issue is using JavaScript events.
this.lastActiveTime = new Date();
window.onclick = function () {
this.lastActiveTime= new Date();
};
window.onmousemove = function () {
this.lastActiveTime= new Date();
};
window.onkeypress = function () {
this.lastActiveTime= new Date();
};
window.onscroll = function () {
this.lastActiveTime= new Date();
};
let idleTimer_k = window.setInterval(CheckIdleTime, 10000);
function CheckIdleTime() {
//returns idle time every 10 seconds
let dateNowTime = new Date().getTime();
let lastActiveTime = new Date(this.lastActiveTime).getTime();
let remTime = Math.floor((dateNowTime-lastActiveTime)/ 1000);
// converting from milliseconds to seconds
console.log("Idle since "+remTime+" Seconds Last active at "+this.lastActiveTime)
}
<div> APP Here <br/><br/><br/><br/><br/><br/>make activity here<br/><br/><br/><br/><br/>Till here </div>
Here is the short example of the functionality where something will happen if user was inactive for around 10 minutes.
Upon init of the app:
window.lastActivity = Date.now();
document.addEventListener('click', function(){
window.lastActivity = Date.now();
})
Somewhere in particular service:
var TIMEOUT = 600000 //10 mins
var activityChecker = setInterval(check, 3000);
function check() {
var currentTime = Date.now();
if (currentTime - window.lastActivity > TIMEOUT) {
// do something useful, for example logout or whatever
}
}
This approach is nice because it doesn't depend on some timers which are working incorrectly if user minimize browser or switch to another tab, etc.
We just check current timestamp with the lastActivity timestamp every few seconds.
You can change 'click' event in my code with any other type of event you need or with any other condition which is suitable for you to consider user as active.
It's actually a follow up to this question I want to display elements from json based on their time and duration and interval is interupted by settimeout - I accepted the answer there made by #Daniel Flint - his code is quite clear and can be found here http://jsfiddle.net/nauzilus/rqctam5r/
However, there's one more thing that I wanted to add - a simple div <div id="time"></div> that would contain a new date time object initialized during opening the page and then it being incremented every second just to show the current time constantly. I thought about writing there a javascript:
var actualTime = new Date(substractedDate); // taken from the server
function updateTimeBasedOnServer(timestamp) {
var calculatedTime = moment(timestamp);
var dateString = calculatedTime.format('h:mm:ss A');
$('#time').html(dateString + ", ");
};
var timestamp = actualTime.getTime();
updateTimeBasedOnServer(timestamp);
setInterval(function () {
timestamp += 1000; // Increment the timestamp at every call.
updateTimeBasedOnServer(timestamp);
}, 1000);
(I provide the time of the server as a timestamp there).
I just noticed that there is a slight mismatch between displaying the time in my div and between the text appearing on the screen, possibly because I increment both of the values in two different places.
So my question is - how can I "merge" #Daniel Flint's code with mine and increment both values only in one place?
One thing that jumps out here:
timestamp += 1000;
setTimeout/setInterval aren't guaranteed to run at precisely the delay you've entered. Run this in your browsers console:
var last = Date.now(),
time = function() {
var now = Date.now();
console.log(now - last);
last = now;
},
id = setInterval(time, 1000);
On my Mac at home (Chrome/FireFox) it was anywhere from 990 to 1015. Windows machine at work is a bit better (995-1002), but IE was getting up to 1020. It's not a huge difference, but it's not nothing.
So code needs to be able to handle not running exactly every 1000ms. That's why I was running the timer at 500ms intervals, and checking if the start time was less-than-equal to the current time.
I've rejigged the demo to show the time and message in sync:
(function() {
var messages = [];
var time = document.getElementById("current-time");
var display = document.getElementById("message");
function check() {
showMessage(currentMessage());
showTime();
}
function currentMessage() {
var message = null;
if (messages.length) {
var now = toTheSecond(new Date());
var start = toTheSecond(new Date(messages[0].start_time));
var end = toTheSecond(new Date(start.getTime() + ( messages[0].text_duration * 1000 )));
if (start <= now) {
if (end <= now) {
// done with the current message...
messages = messages.slice(1);
// ...but check if there's another one ready to go right now
message = currentMessage();
}
else {
message = messages[0];
}
}
}
return message;
}
function toTheSecond(date) {
date.setMilliseconds(0);
return date;
}
function showMessage(message) {
if (message) {
display.textContent = message.text_content;
}
else {
display.textContent = "no messages";
}
}
function showTime() {
time.textContent = new Date().toLocaleString()
}
function getMessages() {
setTimeout(function() {
var now = new Date();
messages.push(
{"text_content":"aaaaa","text_duration":5,"start_time": new Date(now.getTime() + 3000).toISOString()},
{"text_content":"aawwaaaaa","text_duration":5,"start_time": new Date(now.getTime() + 10000).toISOString()},
{"text_content":"bbaawwaaaaa","text_duration":5,"start_time": new Date(now.getTime() + 15000).toISOString()}
);
}, 1000);
}
setInterval(check, 500);
getMessages();
})();
<span id="current-time"></span> <span id="message">Hello there!</span>
(Putting the code here as well because I recall SO want code in the answers so it's controlled, but there's a demo here: http://jsfiddle.net/nauzilus/ymp0615g/).
This probably isn't as efficient as it could be; the message text is being set every iteration which might cause repaints/reflow. But then again setting the time stamp is going to do that anyway, so meh :)
I want to start a timer when the user clicks on a object, and stop it when the user releases the click. All using javascript/jquery.
The following should get you started
var start_time;
function start() {
start_time = new Date();
}
function end() {
var now = new Date();
alert(now-start_time);
}
$('#element_id').mousedown(start);
$('#element_id').mouseup(end);
the mousedown event will run the start function which sets the start time. the mouseup event will substract the start time from the current time. The result is in milliseconds
$("#element").mousedown(); will let you record when the user clicks, and similarly $("#element").mouseup();will let you record when the button is released.
var start = 0;
$("#element").mousedown(function() { start = new Date(); });
$("#element").mouseup(function() {
var cur = new Date();
alert(cur-start);
}
function myTimer() {
doSomething();
}
$('#thing').mousedown(function() {
$(this).data('timerHandle', setTimeout(myTimer));
});
$('#thing').mouseup(function() {
clearTimeout($(this).data('timerHandle'));
}