Store information in localStorage - javascript

I am trying to store information with the webstorage API. I created a class but the console returns the message "undefined". I was expecting the console to return 20 and 60. Can you help me identify my mistake? Thank you :)
class Timer {
constructor(minutes, secondes){
this.minutes = minutes;
this.secondes = secondes;
this.minutesEltHtml = document.getElementById("minutes");
this.secondesEltHtml = document.getElementById("secondes");
}
setMinutesSecondes(){
sessionStorage.setItem("minutes", this.minutes);
sessionStorage.setItem("secondes", this.secondes);
}
getMinutesSecondes(){
return sessionStorage.getItem("minutes");
return sessionStorage.getItem("secondes");
}
display(){
console.log(timer.getMinutesSecondes());
//console.log(timer.this.minutes);
}
}
let timer = new Timer(20, 60);
timer.display();
Line 20: undefined

1: You don't set the storage as you are not calling the method that does it. either call timer.setMinutesSecondes() before calling display or do so in the constructor as per my example below.
2: It's seconds not secondes (sorry for the pedantry).
3: Your getMinutesSecondes function has 2 return calls. Execution will stop after the first call. see my example below.
4: Some of the mistakes here indicate you would benefit from some introduction to JavaScript courses. Have a quick google, there is a wealth of free content online.
class Timer {
constructor(minutes, secondes){
this.minutes = minutes;
this.secondes = secondes;
this.minutesEltHtml = document.getElementById("minutes");
this.secondesEltHtml = document.getElementById("secondes");
this.setMinutesSecondes();
}
setMinutesSecondes(){
sessionStorage.setItem("minutes", this.minutes);
sessionStorage.setItem("secondes", this.secondes);
}
getMinutesSecondes(){
return { // you were calling return twice... only the first line would have returned
mintues: sessionStorage.getItem("minutes"),
secondes: sessionStorage.getItem("secondes")
};
}
display(){
console.log(this.getMinutesSecondes());
}
}
let timer = new Timer(20, 60);
timer.display(); // output {minutes:20, secondes:60}

The reason you are getting undefined as the return value of sessionStorage.getItem is because the value you are trying to retrieve from the storage has not be set on that storage. You defined a method to store the data to the storage without calling that method ( setMinutesSecondes ).
Do this instead ( Assuming the code you presented is your complete code )
class Timer {
constructor(minutes, secondes){
this.minutes = minutes;
this.secondes = secondes;
this.minutesEltHtml = document.getElementById("minutes");
this.secondesEltHtml = document.getElementById("secondes");
}
setMinutesSecondes(){
sessionStorage.setItem("minutes", this.minutes);
sessionStorage.setItem("secondes", this.secondes);
}
getMinutesSecondes(){
return {
minutes: sessionStorage.getItem("minutes"),
secondes: sessionStorage.getItem("secondes");
};
}
display(){
console.log(timer.getMinutesSecondes());
//console.log(timer.this.minutes);
}
}
let timer = new Timer(20, 60);
timer.setMinutesSecondes(); // if you don't wish to call this method here, you can still call this method in the constructor function
timer.display();

Related

Firebase Cloud Function Cron Update

i have function i am using to do updates to my databased based on Cron Job. It looks like this ( worth saying i had a lot of help here )
exports.minute_job =
functions.pubsub.topic('minute-tick').onPublish((event) => {
var ref = admin.database().ref("comments")
ref.once("value").then((snapshot) => {
var updates = {};
snapshot.forEach(commentSnapshot => {
var comment = commentSnapshot.val();
var currentRating = comment.rating - comment.lastRating;
var newScore = ((Math.abs(comment.internalScore) * 0.95) + currentRating) * -1;
if(newScore < 0.000001) { newScore = 0.000001}
updates[commentSnapshot.key + "/lastRating"] = comment.rating;
updates[commentSnapshot.key + "/internalScore"] = newScore;
});
ref.update(updates);
})
});
Its all working perfectly, except i am getting this warning from Firebase logs:
"Function returned undefined, expected Promise or value"
Thanks for any help
Since your Cloud Function doesn't return a value, the Google Cloud Functions engine contain doesn't know when the code is finished. In many cases this means that GCF will simply terminate the contain of your function right after the closing }) has executed. But at that point, your code is likely still loading data from the database, and it definitely hasn't update the database yet.
The solution is to return a promise, which is just an object that will signal when you're done with the database. The good news is that both once() and update() already return promises, so you can just return those:
exports.minute_job =
functions.pubsub.topic('minute-tick').onPublish((event) => {
var ref = admin.database().ref("comments")
return ref.once("value").then((snapshot) => {
var updates = {};
snapshot.forEach(commentSnapshot => {
var comment = commentSnapshot.val();
var currentRating = comment.rating - comment.lastRating;
var newScore = ((Math.abs(comment.internalScore) * 0.95) + currentRating) * -1;
if(newScore < 0.000001) { newScore = 0.000001}
updates[commentSnapshot.key + "/lastRating"] = comment.rating;
updates[commentSnapshot.key + "/internalScore"] = newScore;
});
return ref.update(updates);
})
});
Now Google Cloud Functions know that your code is still working after the }), because you returned a promise. And then when your update() is done, it resolves the promise it return and Google Cloud Functions can close the container (or at the very least: stop charging you for its usage).

ASP.net MVC session timeout duration

Perhaps I am over-thinking this but what I need to do is see what the time difference it is from the start session time (1 minute) subtracting the current time.
<script type="text/javascript">
var mySessionTimer;
#functions {
public int PopupShowDelay
{
get {
DateTime currentSetTimeout = DateTime.Now.AddMinutes(HttpContext.Current.Session.Timeout);
DateTime currentServerTime = DateTime.Now;
TimeSpan duration = (currentServerTime.Subtract(currentSetTimeout));
return 60000 * (int)duration.TotalMinutes;
}
}
}
function callJSSessionTimer() {
var sessionTimeoutWarning = #PopupShowDelay;
var sTimeout = parseInt(sessionTimeoutWarning);
mySessionTimer = setTimeout('SessionEnd()', sTimeout);
}
function SessionEnd() {
clearTimeout(mySessionTimer);
window.location = "/Account/sessionover";
}
#if (userInfo != null)
{
if (userInfo.chosenAMT == "True")
{
#:callJSSessionTimer();
} else
{
#:clearTimeout(mySessionTimer);
}
} else {
#:clearTimeout(mySessionTimer);
}
</script>
So for the value for duration is -00:01:00 which technically is correct since currentSetTimeout is 1 minute and it gets todays date/time which is a minute away since its subtracting it fromcurrentSetTimeout.
So the point of all of this is to keep track of the remaining session time when the user jumps from page to page. Currently when the user goes to another page, it resets the time and its not accurate.
How can I go about doing this the way I need it?
You may use html5 session storage to maintain the value when a user goes to another page during the session:
if (sessionStorage.popupShowDelay) {
sessionStorage.popupShowDelay = Number(sessionStorage.clickcount);
} else {
DateTime currentSetTimeout = DateTime.Now.AddMinutes(HttpContext.Current.Session.Timeout);
DateTime currentServerTime = DateTime.Now;
TimeSpan duration = (currentServerTime.Subtract(currentSetTimeout));
sessionStorage.popupShowDelay = 60000 * (int)duration.TotalMinutes;
}
You can see more in formation here :
https://www.w3schools.com/html/html5_webstorage.asp
Conceptually your problem is the counter would reset as you go from page to page. So you have to keep start time of the session server side. If you are using ASP.NET, you'd use a session variable to do this. Other platforms have similar things. They all work by using cookies. Good luck!
Got it!
#functions {
public int PopupShowDelay
{
get {
if (Session["currentSetTimeout"] != null)
{
DateTime dt1 = DateTime.Parse(Session["currentSetTimeout"].ToString());
DateTime dt2 = DateTime.Parse(DateTime.Now.ToString());
TimeSpan span = dt1 - dt2;
return (int)span.TotalMilliseconds;
}
return 0;
}
}
}

Intermittent failure in nodeJS timer function

I am not familiar with this function, however I am seeing intermittent failures, sometimes the timer function will execute and the newState variable switches, sometimes it doesn't. Please can you check my understanding of what this is doing?
function motionHandler() {
console.log('im in motionhandler func')
var newState = true;
changeAction(newState);
if(this.timer !== undefined) clearTimeout(this.timer);
this.timer = setTimeout(function(){changeAction(!newState);}, this.window_seconds * 1000);
};
From what I understand, when this function executes I set the newState variable to true. I then execute changeAction which sets my motion detector to "true" (motion detected).
I then create a timer. If this.timer has something in it, then clear. I then create a timeout which will countdown from window_seconds * 1000 (ie. 5x1000 milliseconds = 5 seconds). Once that timeout is reached, I will execute the changeAction function and set newState to the opposite of what it currently is?
Assuming all of that is correct, sometimes newState gets reset, other times it doesn't.
I am executing the motionHandler function every time I receive a particular RF code from a transmitter. The timeout is there to reset the motion detector back to false when no codes are received.
The full code is actually a plugin for home bridge, and can be seen here:
https://github.com/mattnewham/homebridge-RFReceiver/blob/master/index.js
This is my first real foray into Javascript/NodeJS so I don't really know how to troubleshoot this (other than my console.logs!)
Full code:
var Service;
var Characteristic;
var rpi433 = require("rpi-433"),
rfSniffer = rpi433.sniffer({
pin: 2, //Snif on GPIO 2 (or Physical PIN 13)
debounceDelay: 1000 //Wait 500ms before reading another code
}),
rfEmitter = rpi433.emitter({
pin: 0, //Send through GPIO 0 (or Physical PIN 11)
pulseLength: 350 //Send the code with a 350 pulse length
});
var debug = require("debug")("RFReceiverAccessory");
var crypto = require("crypto");
module.exports = function(homebridge) {
Service = homebridge.hap.Service;
Characteristic = homebridge.hap.Characteristic;
homebridge.registerAccessory("homebridge-RFReceiver", "RFReceiver", RFReceiverAccessory);
}
function RFReceiverAccessory(log, config) {
this.log = log;
// url info
this.name = config["name"];
this.rfcode = config["rfcode"] || 4;
this.window_seconds = config["window_seconds"] || 5;
this.sensor_type = config["sensor_type"] || "m";
this.inverse = config["inverse"] || false;
}
RFReceiverAccessory.prototype = {
getServices: function() {
// you can OPTIONALLY create an information service if you wish to override
// the default values for things like serial number, model, etc.
var informationService = new Service.AccessoryInformation();
informationService
.setCharacteristic(Characteristic.Name, this.name)
.setCharacteristic(Characteristic.Manufacturer, "Homebridge")
.setCharacteristic(Characteristic.Model, "RF Receiver")
.setCharacteristic(Characteristic.SerialNumber, "12345");
var service, changeAction;
if(this.sensor_type === "c"){
service = new Service.ContactSensor();
changeAction = function(newState){
service.getCharacteristic(Characteristic.ContactSensorState)
.setValue(newState ? Characteristic.ContactSensorState.CONTACT_DETECTED : Characteristic.ContactSensorState.CONTACT_NOT_DETECTED);
};
} else {
service = new Service.MotionSensor();
changeAction = function(newState){
console.log('changing state');
service.getCharacteristic(Characteristic.MotionDetected)
.setValue(newState);
};
}
function motionHandler() {
console.log('im in motionhandler func')
var newState = true;
changeAction(newState);
if(this.timer !== undefined) clearTimeout(this.timer);
this.timer = setTimeout(function(){changeAction(!newState);}, this.window_seconds * 1000);
};
var code = this.rfcode
var name = this.name
rfSniffer.on('data', function (data) {
console.log('Code received: '+data.code+' pulse length : '+data.pulseLength);
console.log(code);
if(data.code == code){
console.log("Motion Detected In" +name);
motionHandler()};
});
return [informationService, service];
}
};

Meteor : How to clearInterval() onDestroyed() created in onRendered()

I have a countdown function to run every sec, So i proffered setInterval(). After I moved to another template, the interval function keep on running. How to destroy it onDestroyed(). Below code will help you to understand well.
<template name="Home">
<h4>{{timeremaining}}</h4>
</template>
Template.Home.helpers({
timeremaining : function(){
return Session.get('timeremaining');
}
});
Template.Home.onRendered(function () {
// time functions begin
var end_date = new Date(1476337380000); // I am getting timestamp from the db.
var run_every_sec = setInterval(function () {
var current_date = new Date();
var remaining = end_date.getTime() - current_date.getTime();
var oneDay = 24*60*60*1000;
var diffDays = Math.round(Math.abs(remaining/oneDay));
console.log(remaining); // am getting this log in every template.
if (remaining > 0) {
//set remaining timeLeft
Session.set('timeremaining',diffDays + ' Days ' + (Math.abs(end_date.getHours()-current_date.getHours())).toString() + ' Hrs ' + (Math.abs(end_date.getMinutes()-current_date.getMinutes())).toString() + ' Min ' + (60 - end_date.getSeconds()-current_date.getSeconds()).toString() + ' Sec ')
} else {
clearInterval(run_every_sec);
}
}, 1000);
//time functions end
}.bind(this));
Template.Home.onDestroyed(function () {
clearInterval(run_every_sec); // Here I cant remove this time interval
});
We can declare run_every_sec as global function. If so How to pass end_date. I dont think its wise idea to declare end_date inside the run_every_sec because its coming from db.
If you store the interval in file scope like Repo suggested, you'll have problems if there's ever more than one instance of the template at a time: both instances will use the same run_every_sec variable. In this case, you'll need to store the interval on the template instance, which can be accessed as this inside onRendered and onDestroyed:
Template.Home.onRendered(function () {
this.run_every_sec = setInterval(/* ... */);
});
Template.Home.onDestroyed(function () {
clearInterval(this.run_every_sec);
});
That way, each instance of the template will have its own run_every_sec property.
You should declare "run_every_sec" outside "onRendered".
So instead of this:
Template.Home.onRendered(function () {
// time functions begin
var end_date = new Date(1476337380000); // I am getting timestamp from the db.
var run_every_sec = setInterval(function () {
..do this:
var run_every_sec;
Template.Home.onRendered(function () {
// time functions begin
var end_date = new Date(1476337380000); // I am getting timestamp from the db.
run_every_sec = setInterval(function () {
then it will be available in "onDestroyed"
You should use Meteor's setInterval and clearInterval to make sure they run within a fiber. You can find more info here https://docs.meteor.com/api/timers.html.
var intervalID
Template.myTemplate.onRendered(function() {
intervalID = Meteor.setInterval(function() {
//do something
}, 1000)
})
Template.myTemplate.onDestroyed(function() {
Meteor.clearInterval(intervalID)
})

Google Apps Script, fastest way to retrieve data from external spreadsheets

I'm trying to load data from multiple spreadsheets(~100) into a single spreadsheet, however when I try to do this my script times out. It appears that opening each spreadsheet takes a long time. Is there any way I can speed this up or a work around?
Here's what I use to open each spreadsheet
// We set the current spreadsheet to master and get the current date.
var master = SpreadsheetApp.getActive();
var masterSheet = master.getSheetByName('Master');
var users = master.getEditors();
var today = new Date();
// Adds the menu to the spreadsheet
function onOpen() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Update Data",
functionName : "retrievePartnerData"
}];
spreadsheet.addMenu("Submissions Menu", entries);
};
// First we get all data from the partner sheets
function retrievePartnerData() {
masterSheet.getRange(2, 1, masterSheet.getLastRow(), masterSheet.getLastColumn()).clear(); //Clear our master sheet aka Sheet All
masterSheet.hideSheet();
//Get's Promo Outline from the internal sheet and store it's values in the promoRange array
var promoRange = master.getSheetByName("Promotional Outline").getRange("A1:Z100").getValues();
var sheetPartnerArray = [];
// Row is an array that contaings the url's to the external spreadsheets
var row = master.getSheetByName('Partner Sheet Collection').getRange("B:B").getValues();
row.map(function(e){
if(e[0] != "" && e[0] != "Url"){
var ss = SpreadsheetApp.openByUrl(e[0]);
var studioName = ss.getSheets()[0].getRange("A1").getValue();
//Updates the Promotional Outline sheet in the partner sheet
var promoSheet = ss.getSheetByName("Promotional Outline");
promoSheet.getRange("A1:Z100").setValues(promoRange);
//Hide columns K to Z
promoSheet.hideColumns(11,4);
var sheet = ss.getSheets();
sheet.map(function(f){
var sheetName = f.getSheetName(); // Retrieves the sheetname of each sheet
var lastRow = 0;
if(f.getLastRow() == 1) {
lastRow = 1;
} else {
lastRow = f.getLastRow() - 1;
}
var dataRange = f.getRange(2, 1, lastRow, f.getLastColumn());
var data = dataRange.getValues();
for (var j = 0; j < data.length; j++) {
if (data[j][0].length != 0 && (data[j][5] > today || data[j][5] == "[Please Enter]")) { // We check if the promo end date is after the current day
var sheetRow = data[j];
sheetRow[1] = studioName;
sheetRow.unshift(sheetName); //Adds the Country to the beginning of the row using the sheet name from spreadsheets
sheetPartnerArray.push(sheetRow);
}
}
})
}
})
masterSheet.getRange(2, 1, sheetPartnerArray.length , sheetPartnerArray[0].length ).setValues(sheetPartnerArray);
};
Thanks!
One common approach is to set a trigger to restart your Big Job at some time in the future (just beyond the maximum execution time). Then your Big Job does as much as it can (or stops nicely at some logical point), and either gets killed or quietly exits. Either way, it gets restarted shortly after, and resumes its work.
Patt0 has taken this idea to an elegant end, providing a library that you can add to your script. With a few adaptations, you should be able to turn your retrievePartnerData() into a batch job.
Since you have a menu already, and retrievePartnerData() involves iterating over many spreadsheets, you have the opportunity to break the barrier another way, by completing each iteration (or better, a set of iterations) in a separate server script instance.
This technique appears in What happens when I "sleep" in GAS ? (execution time limit workaround)
And there is something similar in How to poll a Google Doc from an add-on. In that answer, a UI client uses a timer to repeatedly execute a server function. Here, though, iterations would be work-based, rather than time-based. This client-side function, running in your browser, would keep calling the server until there was no more work to be done:
/**
* Call the server-side 'serverProcess' function until there's no more work.
*/
function dispatchWork(){
if (window.runningProcess) {
}
google.script.run
.withSuccessHandler( //<<<< if last call was good
// After each interval, decide what to do next
function(workis) {
if (!workis.done) { //<<<<< check if we're done
// There's more work to do, keep going.
dispatchWork();
}
else {
// All done. Stop timer
stopTimer();
$('#start-process').hide();
$("#final").html(' <h2>Processing complete!</h2>');
}
})
.withFailureHandler(
function(msg, element) { //<<<<<< do this if error
showError(msg, $('#button-bar'));
element.disabled = false;
})
.serverProcess(); //<<<<< call server function
};
In your case, you first need to refactor retrievePartnerData() so it can be called from a client to process a single spreadsheet (or set of them). No doubt you have put considerable time into making that map loop work cleanly, and taking it apart will be painful, but it will be worth it.
The following spreadsheet-bound script can be adapted to your use. It consists of a menu item, a simple UI, and scripts on the client (Javascript + jQuery) and server (Google Apps Script), which control the work in intervals.
The control data is in a "SourceSheets" tab, and results will be copied to "Master".
Code.gs
var properties = PropertiesService.getScriptProperties();
// Adds the menu to the spreadsheet
function onOpen() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Update Data",
functionName : "updateData"
}];
spreadsheet.addMenu("Big Job", entries);
};
/**
* Presents UI to user.
*/
function updateData () {
var userInterface = HtmlService.createHtmlOutputFromFile("Conductor")
.setHeight(150)
.setWidth(250)
.setTitle("What 5 minute limit?");
var ss = SpreadsheetApp.getActiveSpreadsheet();
ss.show(userInterface)
}
/**
* Called from client, this function performs the server work in
* intervals. It will exit when processing time has exceeded MAX_INTERVAL,
* 3.5 minutes. Every time this function exits, the client is provided
* with the current status object, done=true when the work queue has
* been emptied.
*
* #returns {Object} Status { done: boolean }
*/
function serverProcess() {
var MAX_INTERVAL = (3.5 * 60); // minutes * seconds
var intervalStart = Math.round(new Date() / 1000);
// Get persisted work queue, if there is one
var queueProp = properties.getProperty('work-queue') || '[]';
var queue = JSON.parse(queueProp);
if (queue.length == 0) {
queue = prepareWork();
}
// Do the work for this interval, until we're out of time
while ((Math.round(new Date() / 1000) - intervalStart) < MAX_INTERVAL) {
if (queue.length > 0) {
var ssID = queue.shift();
processSheet(ssID);
properties.setProperty('work-queue', JSON.stringify(queue));
}
else break;
}
// Report result of this interval to client
var result = { done : (queue.length == 0) };
return( result );
}
/**
* Set up work queue & clear Master sheet, ready to import data from source sheets.
*
* #return {String[]} work queue
*/
function prepareWork() {
// No work yet, so set up work
var ss = SpreadsheetApp.getActive();
var masterSheet = ss.getSheetByName('Master');
var rowsToDelete = masterSheet.getMaxRows()-1;
if (rowsToDelete)
masterSheet.deleteRows(2, rowsToDelete); //Clear our master sheet aka Sheet All
// Build work queue
var queue = [];
var data = ss.getSheetByName('SourceSheets') // get all data
.getDataRange().getValues();
var headers = data.splice(0,1)[0]; // take headers off it
var ssIDcol = headers.indexOf('Spreadsheet ID'); // find column with work
for (var i=0; i<data.length; i++) {
queue.push(data[i][ssIDcol]); // queue up the work
}
// Persist the work queue as a scriptProperty
properties.setProperty('work-queue', JSON.stringify(queue));
return queue;
}
/**
* Do whatever work item we need. In this example, we'll import all data from
* the source sheet and append it to our Master.
*
* #param {String} ssID Source spreadsheet ID
*/
function processSheet(ssID) {
var masterSheet = SpreadsheetApp.getActive().getSheetByName('Master');
var sourceSheet = SpreadsheetApp.openById(ssID).getSheetByName('Sheet1');
Utilities.sleep(60000); // You probably don't want to do this... just wasting time.
var masterLastRow = masterSheet.getLastRow();
var sourceRows = sourceSheet.getLastRow();
masterSheet.insertRowsAfter(masterSheet.getLastRow(), sourceSheet.getLastRow());
var sourceData = sourceSheet.getDataRange().getValues().slice(1);
var destRange = masterSheet.getRange(masterLastRow+1, 1, sourceData.length, sourceData[0].length);
destRange.setValues(sourceData);
}
Conductor.html
<link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons.css">
<!-- The CSS package above applies Google styling to buttons and other elements. -->
<div id="form-div" class="sidebar branding-below">
<span id="final"></span>
<form>
<div class="block" id="button-bar">
<button class="blue" id="start-process">Start processing</button>
</div>
</form>
</div>
<div class="bottom">
Elapsed processing time: <span id="elapsed">--:--:--</span>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script>
/**
* On document load, assign click handlers to button(s), add
* elements that should start hidden (avoids "flashing"), and
* start polling for document selections.
*/
$(function() {
// assign click handler(s)
$('#start-process').click(startProcess);
});
/**
* Call the server-side 'serverProcess' function until there's no more work.
*/
function dispatchWork(){
if (window.runningProcess) {
}
google.script.run
.withSuccessHandler(
// After each interval, decide what to do next
function(workis) {
if (!workis.done) {
// There's more work to do, keep going.
dispatchWork();
}
else {
// All done. Stop timer
stopTimer();
$('#start-process').hide();
$("#final").html(' <h2>Processing complete!</h2>');
}
})
.withFailureHandler(
function(msg, element) {
showError(msg, $('#button-bar'));
element.disabled = false;
})
.serverProcess();
};
/**
* Runs a server-side function to retrieve the currently
* selected text.
*/
function startProcess() {
this.disabled = true; // Disable the button
$('#error').remove(); // Clear previous error messages, if any
startTimer(); // Start a work timer, for display to user
window.runningProcess = true;
dispatchWork(); // Start our work on the server
}
// Timer adapted from http://codingforums.com/javascript-programming/159873-displaying-elapsed-time.html
/**
* Kicks off the tick function.
*/
function startTimer( )
{
window.seconds = null;
window.ticker = null;
window.seconds = -1;
window.ticker = setInterval(tick, 1000);
tick( );
}
/**
* Stop ticking
*/
function stopTimer()
{
clearInterval(window.ticker);
}
/*
* Updates the timer display, between sleeps.
*/
function tick( )
{
++window.seconds;
var secs = window.seconds;
var hrs = Math.floor( secs / 3600 );
secs %= 3600;
var mns = Math.floor( secs / 60 );
secs %= 60;
var pretty = ( hrs < 10 ? "0" : "" ) + hrs
+ ":" + ( mns < 10 ? "0" : "" ) + mns
+ ":" + ( secs < 10 ? "0" : "" ) + secs;
$("#elapsed").text(pretty);
}
/**
* Inserts a div that contains an error message after a given element.
*
* #param msg The error message to display.
* #param element The element after which to display the error.
*/
function showError(msg, element) {
var div = $('<div id="error" class="error">' + msg + '</div>');
$(element).after(div);
}
</script>

Categories

Resources