How to create an elapsed time calendar in JavaScript - javascript

I have the original code, which only allows the user to choose from future dates. However, I would like to change this so that the user can pick a previous date, and it will show the time since then. The if-statement is where it decides if the date is in the past or future. However, even when I remove the entire statement, it allows me to pick a past date but won't print it to the screen.
This is the rest of the code if you are interested/able to help. I understand the snippet doesn't show everything but I don't know what other pieces of code to include. The entirety of the code is simply copied into a Google Doc: cal.js
code snippet:
// select date
function selectDate(event) {
if (event === undefined) { // get caller element in IE8
event = window.event;
}
var callerElement = event.target || event.srcElement;
dateObject.setDate(callerElement.innerHTML);
var fullDateToday = new Date();
var dateToday = Date.UTC(fullDateToday.getFullYear(),
fullDateToday.getMonth(), fullDateToday.getDate());
var selectedDate = Date.UTC(dateObject.getFullYear(),
dateObject.getMonth(), dateObject.getDate());
** if (selectedDate <= dateToday) {
document.getElementById("cal").style.display ="block";
return false;
} **
document.getElementById("tripDate").value =
dateObject.toLocaleDateString();
hideCalendar();
countdown = setInterval(updateCountdown, 1000);
document.getElementById("countdownSection").style.display = "block";
}

Related

Full Calendar If no events for a particular month the calendar will automatically load on next month

Is there any way I can make full calendar to automatically proceed to next month if there is no event coming in a particular month.
Say there is no Event in June or the event is already finished, the calendar will proceed to July without click the next month button.
I never used full calendar (or it was years ago) so I may be a bit wrong, but I flew through their docs and this is what I found (btw: their api is rather a weak part of this plugin, speed and efficiency as well but it's your choice).
There is an event in docs that triggers every time the view change, so although the view will be rendered, skipping will be probably not visible. First of all you will have to implement your own methods to move across calendar, because you have to know if you are going forward or backward (example). So according to this you can try it as such: https://codepen.io/prowseed/pen/bKQEov?editors=0010
var lastOperationFlag;
$('#calendar').fullCalendar({
events: [...],
header: false, // don't display the default header
viewRender: function (view, element) {
var start = view.start._i; // timestamp of the beginning of current view
var end = view.end._i; // timestamp of the end of current view
var events = view.options.events; // all events
if( checkBoundariesAndCurrentRange(start, end, events) ){
(lastOperationFlag === 'next') ? $('#calendar').fullCalendar('next') : $('#calendar').fullCalendar('prev');
}
}
});
$('#prev').on('click', function() {
lastOperationFlag = 'prev';
$('#calendar').fullCalendar('prev'); // request previous view
});
$('#next').on('click', function() {
lastOperationFlag = 'next';
$('#calendar').fullCalendar('next'); // request next view
});
function checkBoundariesAndCurrentRange (start, end, events) {
if (events.length === 0) return false;
var smallestDate = null;
var biggestDate = null;
var eventsInRange = false;
events.forEach(e => {
var ev_start = (new Date(e.start)).getTime(); // !!!!! MORE SAFE to transform it with a momentjs
// here you can eventually also handle event.end if exists with additional logic
if (smallestDate == null || ev_start < smallestDate) smallestDate = ev_start;
if (biggestDate == null || ev_start > biggestDate) biggestDate = ev_start;
if (start <= ev_start && end >= ev_start) eventsInRange = true; // set the flag if there is at least one event in given start-end range
});
console.log((!eventsInRange && smallestDate < start && biggestDate > end) )
return (!eventsInRange && smallestDate < start && biggestDate > end)
}

Automatically locking a range (column) as each date passes?

I have a sheet that employees will update daily with information about tasks done that day. Each column has a date in the header row (row 3 in this case), and after the end of the following day I want that column to lock so it cannot be edited further except by myself and one other. This is to prevent people from covering up mistakes or accidentally changing or deleting data.
I am looking for a script or something that will accomplish this. This sheet has about 45 tabs and I need the same thing applied to all of them.
My idea is possibly a script that triggers at a certain time based off the date in the header row, so if the date is May 5th 2017, the respective column would lock itself at midnight on the 6th.
A link to a copy of my sheet, minus data is here.
Alternatively, if there is a way to simply lock any cell 24 hours after the most recent data is entered into it, and prevent further editing by everyone except select people, that could work too if the ideal method isn't doable.
Yes, there is a way to do this.
I will briefly describe the solution:
Let's say that the first row has 1:1 contains consecutive dates.
Create function lockColumns which would create new protected range.
Add function lockColumns to time trigger, which triggers every day between 0:01 and 1:00 am.
And now some code:
function lockColumns() {
var ss = SpreadsheetApp.getActive().getSheetByName('Sheet 1')
var range = ss.getRange('1:1').getValues()[0];
var today = new Date();
var todayCol = null;
for (var i=0; i<range.length; i++) {
if (today.isSameDateAs(range[i])) {
todayCol = i;
break;
}
}
var rangeToProtect = ss.getRange(1, todayCol +1, ss.getMaxRows(), 1)
var protection = rangeToProtect.protect().setDescription('Protected range');
// Ensure the current user is an editor before removing others. Otherwise, if the user's edit
// permission comes from a group, the script will throw an exception upon removing the group.
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
protection.addEditor('email#gmail.com'); // second person with edit permissions
}
/*
http://stackoverflow.com/a/4428396/2351523
*/
Date.prototype.isSameDateAs = function(pDate) {
return (
this.getFullYear() === pDate.getFullYear() &&
this.getMonth() === pDate.getMonth() &&
this.getDate() === pDate.getDate()
);
}

How to improve performance when rendering <table> in IE 8?

I have a jquery function which adds tag to first row of table.
I tried using append, however its not working, so i got a solution which is very slow and it somehow gives error "Script on this page is causing internet explorer run slow..."
Function is as
jQuery.fn.fixGridView = function () {
"use strict";
// var start = +new Date(); // log start timestamp
if (jQuery(this).is('table') && this.find('thead').length === 0) {
var theadv = "<thead><tr>" + this.find('tbody tr:first').html(); +"</tr></thead>";
this.find('tbody tr:first').remove();
var htmlv = this.html();
this.html(theadv + htmlv);
}
//var end = +new Date(); // log end timestamp
// var diff = end - start;
// alert(diff);
return this;
};
Can anybody help me to make this code run faster?
EDIT: I have to use IE..that is the requirement (ie8).
Edit2: I have created js fiddle: http://jsfiddle.net/4xLzL/
To increase rendering performance you must understand that DOM manipulation (including reflows & repaints) are expensive operations. Your code currently re-creates the entire table with the <thead> added the majority of the <tbody> content remains the same. This massive "redraw" of the table is highly inefficient. Especially when in IE 8, where rendering tables is extra slow, you have to modify the DOM as little as possible.
I've refactored your logic to minimize the number of lookups performed to find elements by saving them to a variable to be re-used. Also, removed the .html('...') call that re-renders the table, but instead used the .prepend() function to add the <thead> into the <table> as the first child.
jQuery.fn.fixGridView = function () {
"use strict";
var start = +new Date(); // log start timestamp
if (this.is('table') && this.children('thead').length === 0) {
var firstRow = this.children('tbody').children('tr:first');
var thead = "<thead><tr>" + firstRow.html() + "</tr></thead>";
firstRow.remove();
this.prepend(thead);
}
var end = +new Date(); // log end timestamp
var diff = end - start;
alert(diff);
return this;
};
$(document).ready(function () {
$('table[id*="gvCategories"]').fixGridView();
});
Go ahead and test it in IE8: http://jsfiddle.net/amyamy86/4xLzL/7/
The problem is not with the plugin, but with your selector. You only want tables, so modify your selector to be as follows.
$('table [id*="gvCategories"]').fixGridView();
I also updated the fiddle.

JavaScript Timer countdown to logout

I'm trying to make a countdown timer in JS that will change the value of a field every one minute (in the begining there is 20, and then change it to 19,18,17 etc), but it's not working correctly. It's changing value not every 60sec but I have a feel that it works random (sometimes it change value first time after 15 sec, another time it's 53). Any idea what I'm doing wrong? Here is the code:
function getTimeNow(){
var Time = new Date;
return Time.getHours()*60*60+Time.getMinutes()*60 + Time.getSeconds();
}
var start = getTimeNow();
var start_point = start%60;
var target = start+60*20;
function TimeOut(){
if((getTimeNow()-start)%60 == start_point && target>getTimeNow()){
var temp = jQuery('.Timer').html();
temp-=1;
jQuery('.Timer').html(temp);
}
setTimeout(TimeOut,1000);
}
You cannot count on the exact moment a timer function will be called. You need to change your logic to something more resilient to time shifts...
setInterval(function(){count.innerText = count.innerText - 1;},
60*1000);
this is also a lot shorter...

jQuery Plugin with setTimeout or setInterval

I'm working on my first jQuery plugin which is a simple countdown timer with an option to set the target date. The goal is to get a plain text clock counting down to the provided target date & time. For the life of me I can't figure out how to use setTimeout or setInverval within the plugin so it actually counts down. Spent all day digging through stackoverflow and other sources but couldn't find a solution, so apologies if I'm just not getting it.
Here's what I've got:
(function( $ ){
$.fn.clock = function( options ) {
// ESTABLISH DEFAULTS
var settings = $.extend( {
'target' : '07/21/2013 09:00:00', // mm/dd/yyyy hh:mm:ss
}, options);
return this.each(function() {
// calculate milliseconds to target
tarDate = new Date(settings.target);
dateNow = new Date();
amount = tarDate.getTime() - dateNow.getTime();
delete dateNow;
// set label
label = settings.title;
// generate output
if(amount <= 0) {
out = '000:00:00:00';
} else {
td = 0; th = 0; tm = 0; ts = 0; out = ''; // reset everything
amount = Math.floor(amount/1000); // kill the milliseconds
td = Math.floor(amount/86400); // calculate days to target
amount = amount%86400; // convert amount to days
th = Math.floor(amount/3600); // calculate hours to target
amount = amount%3600; // convert amount to hours
tm = Math.floor(amount/60); // calculate minutes to target
amount = amount%60; // convert amount to minutes
ts = Math.floor(amount)+1; // calculate seconds to target
out += (td<=99?'0':'') + (td<=9?'0':'') + td + ':';
out += (th<=9?'0':'') + th + ':';
out += (tm<=9?'0':'') + tm + ':';
out += (ts<=9?'0':'') + ts;
}
// assemble and pump out to dom
$(this).html(out);
// set refresh rate
??????
});
};
})( jQuery );
Check out this link for an interesting pattern for plugin authoring. Basically what you need to do is provide a "method" for updating your clock:
(function( $ ){
function updateClock(element) {
var settings = element.data("settings");
// Your update logic goes here
}
$.fn.clock = function( options ) {
if ( options === 'update' )
return updateClock(this);
// Other methods, if any
else if ( typeof options !== 'object' )
throw 'Unknown method';
// ESTABLISH DEFAULTS
var settings = $.extend( {
'target' : '07/21/2013 09:00:00', // mm/dd/yyyy hh:mm:ss
}, options);
// Save your settings for later access
this.data("settings",settings);
Then, every time you want to update an element, you call it this way:
$(yourselector).clock("update");
(from outside; if updateClock is accessible from your scope, you can call it directly for efficiency. Just remember to wrap the element in $() if necessary)
Lastly, you have to configure setTimeout or setInterval. I would prefer setTimeout, because that will allow you to stop or restart your clock if necessary. Add this to the end of your updateClock, maybe preceeded by a check:
setTimeout(function() { updateClock(element); }, settings.refreshRate);
i believe you have to have setTimeout inside the function that needs to be called and have setTimeout call the function its in. then have a condition setup so once it reaches zero clearTimeout will go off http://jsfiddle.net/qUYQN/

Categories