Preferred Method to (Accurately) Get Time From User Input (in UiApp - GAS) - javascript

UiApp has DateBox and DateTimeFormat
for that Class. However, there is no such thing as TimePicker or TimeBox, where a user could enter a time in a well-specified manner such as through using Google Forms:
Forms has different behavior for this Widget in Chrome vs Firefox (I much prefer the Chrome behavior). Anyway, currently I am using a TextBox to get time values, where someone would enter a time value in the following manner:
12:00 or 13:50, etc. These times would be in the 24-hour clock so that I could create new Date objects based on someDate + " " + startTime, which would act as the real start time for an event on the Calendar (this is the process I currently use in several of my applications at work). This is obviously unreliable for several reasons.
Ex: If the user entered anything except a valid 24-hour representation in HH:MM:SS, Date creation would fail.
I don't want to force my boss to be overly-precautious about how he inputs times into the UI, and I also want to avoid regexing "valid" formats and having the UI do a lot of back-end work (it would be 18 regex tests total, and if any failed I'd have to handle them individually).
So, the question: is there an efficient/preferred method of getting times in UiApp, either via TextBox or some other interface?

What about something like that ? Test app here (updated with new version, see edit)
code below :
function doGet() {
var app = UiApp.createApplication().setTitle('enter time');
var frame = app.createVerticalPanel().setStyleAttributes({'border':'solid 1px #AA6','background-color':'#FFD','padding':'15px'});
var handler = app.createServerHandler('setTime').addCallbackElement(frame);
var h = app.createListBox().setId('h').setName('h').setStyleAttributes({'margin':'5px'}).addChangeHandler(handler);
for(var n=0;n<12;n++){h.addItem(Utilities.formatString('%02d', n),n)}
var m = app.createListBox().setId('m').setName('m').setStyleAttributes({'margin':'5px'}).addChangeHandler(handler);
for(var n=0;n<60;n++){m.addItem(Utilities.formatString('%02d', n),n)}
var am = app.createListBox().setId('am').setName('am').setStyleAttributes({'margin':'5px'}).addChangeHandler(handler);
am.addItem('AM').addItem('PM');
var date = app.createDateBox().setValue(new Date()).setFormat(UiApp.DateTimeFormat.DATE_LONG).setName('date').addValueChangeHandler(handler);
var label = app.createHTML('<b>StartTime *</b><br>When your reservation starts').setStyleAttributes({'fontSize':'10pt','font-family':"Arial, sans-serif",'padding-bottom':'10px'});
var subFrame = app.createHorizontalPanel().setStyleAttributes({'border':'solid 1px #AA6','background-color':'#FFD','padding':'5px'});
var result = app.createHTML().setId('date').setStyleAttributes({'fontSize':'10pt','font-family':"Arial, sans-serif",'color':'#AA6','padding-top':'20px'})
.setHTML(Utilities.formatDate(new Date(new Date().setHours(0,0,0,0)), Session.getTimeZone(), 'MMM-dd-yyyy HH:mm'));
frame.add(date).add(label).add(subFrame).add(result);
subFrame.add(h).add(m).add(am);
return app.add(frame);
}
function setTime(e){
var app = UiApp.getActiveApplication();
var date = app.getElementById('date')
var date = new Date(e.parameter.date);
var am = e.parameter.am
if(am=='AM'){am=0}else{am=12};
var h = Number(e.parameter.h)+am;
var m = Number(e.parameter.m);
date.setHours(h,m,0,0)
Logger.log(date);
app.getElementById('date').setHTML(Utilities.formatDate(date, Session.getTimeZone(), 'MMM-dd-yyyy HH:mm'));
return app
}
EDIT : here is the wrapped version and a demo with a grid and 10 panels.
function doGet() {
var app = UiApp.createApplication().setTitle('enter time');
var grid = app.createGrid(10,2)
var handler = app.createServerHandler('setTime').addCallbackElement(grid);
var varName = 'date';
var htmlString = '<b>StartTime *</b> When your reservation starts'
for(var idx=0 ; idx<10;idx++){
var frame = pickDate(idx,varName,htmlString,handler);
grid.setText(idx, 0, 'test widget '+idx+' in a grid').setWidget(idx,1,frame);
}
var result = app.createHTML('<h1>Click any widget</h1>').setId('result');
return app.add(grid).add(result);
}
/* wrapped version
** takes a var name + index + label string + handler
** as input parameter
** The same handler will be used for every occurrence , the source being identified in the handler function (see code example below)
** and returns a selfcontained widget that you can add to a panel or assign to a grid
** or a flex Table
*/
function pickDate(idx,varName,htmlString,handler){
var app = UiApp.getActiveApplication();
var frame = app.createVerticalPanel().setStyleAttributes({'border':'solid 1px #AA6','background-color':'#FFD','padding':'1px', 'border-radius':'5px'});
var h = app.createListBox().setId('h'+idx).setName('h'+idx).setStyleAttributes({'margin':'5px'}).addChangeHandler(handler);
for(var n=0;n<12;n++){h.addItem(Utilities.formatString('%02d', n),n)}
var m = app.createListBox().setId('m'+idx).setName('m'+idx).setStyleAttributes({'margin':'5px'}).addChangeHandler(handler);
for(var n=0;n<60;n++){m.addItem(Utilities.formatString('%02d', n),n)}
var am = app.createListBox().setId('am'+idx).setName('am'+idx).setStyleAttributes({'margin':'5px'}).addChangeHandler(handler);
am.addItem('AM').addItem('PM');
var date = app.createDateBox().setValue(new Date()).setFormat(UiApp.DateTimeFormat.DATE_LONG).setId(varName+idx).setName(varName+idx).addValueChangeHandler(handler);
var label = app.createHTML(htmlString).setStyleAttributes({'fontSize':'10pt','font-family':"Arial, sans-serif",'padding-bottom':'3px'}).setId('html'+idx);
var subFrame = app.createHorizontalPanel().setStyleAttributes({'border':'solid 1px #AA6','background-color':'#FFE','padding':'1px', 'border-radius':'4px'});
frame.add(label).add(date).add(subFrame);
subFrame.add(h).add(m).add(am);
return frame;
}
function setTime(e){
// Logger.log(JSON.stringify(e));
var app = UiApp.getActiveApplication();
var idx = Number(e.parameter.source.replace(/\D+/,''));
Logger.log('date'+idx+ ' > '+e.parameter['date'+idx]);
var date = new Date(e.parameter['date'+idx]);
var am = e.parameter['am'+idx];
if(am=='AM'){am=0}else{am=12};
var h = Number(e.parameter['h'+idx])+am;
var m = Number(e.parameter['m'+idx]);
date.setHours(h,m,0,0)
app.getElementById('result').setHTML('<h1>Widget Nr '+idx+' has value '+Utilities.formatDate(date, Session.getTimeZone(), 'MMM-dd-yyyy HH:mm')+'</h1>');
return app
}

Related

Date doesnt work - tag value in setFullYear

var d = new Date();
var gunler= ["Pazar","Pazartesi","Salı","Çarşamba","Perşembe","Cuma","Cumartesi"];
document.getElementById("gun").innerHTML = gunler[d.getDay()];
var ic = document.getElementsByClassName("i");
var dis = document.getElementsByClassName("d");
var ll = document.getElementById("seciligun");
var ll2 = ll.innerHTML;
alert(ll2);
d.setFullYear(ll2);
var a=0;
while(a<ic.length){
if(gunler[d.getDay()]=="Cumartesi"||gunler[d.getDay()]=="Pazar"){
ic[a].innerHTML="";
}
else{
dis[a].innerHTML="";
}
a=a+1;
}
I using these codes in my js file , i taking date in my div tag that id = seciligun. When i use alert it seems like this : 2020-08-15 but when i say alert(d) , browser saying "invalid date". If i write like this d.setFullYear(2020-08-15) everything works correctly but i need use tag's value that id = seciligun.
You need to extract the year from ll2.
var y = ll2.split('-')[0];
d.setFullYear(y);

What is the significance of the if statement in this code?

I am currently learning JavaScript through some tutorials and this example came out in the tutorial.
I'm just confused why must the if statement be there.
I tried erasing the if statement and it still worked. Can someone help me please.
var timesVisited=0;
var dateVisited = 'Never';
if(localStorage.myLastVisit){
var visit = JSON.parse(localStorage.myLastVisit);
timesVisited = visit.numVisits;
dateVisited = visit.dateVisits;
}
$("#dateVisit").html(dateVisited);
timesVisited++;
$("#numVisit").html(timesVisited);
var myVisits = {};
myVisits.numVisits = timesVisited;
var d = new Date();
var hours = d.getHours();
var minutes = d.getMinutes();
myVisits.dateVisits = hours + ':' + minutes;
localStorage.myLastVisit = JSON.stringify(myVisits)
I tried erasing the if statement and it still worked.
Only if myLastVisit is already in localStorage. If it isn't there (which is what the if is testing for), without the if you'll get an error from JSON.parse because you'll pass undefined into it, which will get converted to a string with the charactersundefined in it because JSON.parse requires a string, which will then fail because that's not valid JSON. The if is there so that if the setting isn't present, the default values assigned to timesVisited and dateVisited are used.
Works if the setting is there:
var timesVisited=0;
var dateVisited = 'Never';
var visit = JSON.parse(`{"numVisits": 2, "dateVisits": "2020-03-27"}`);
timesVisited = visit.numVisits;
dateVisited = visit.dateVisits;
console.log(timesVisited); // 2
console.log(dateVisited); // "2020-03-27"
Fails if it isn't:
var timesVisited=0;
var dateVisited = 'Never';
var visit = JSON.parse(undefined); // ERROR
timesVisited = visit.numVisits;
dateVisited = visit.dateVisits;
console.log(timesVisited);
console.log(dateVisited);

Timing Tool for work

I have built a tool for timing indirect workers, it consists of a start and stop button which both place a time stamp into the google sheet and then calculates the difference to record a time. It works great however when I share it with some people it does not allow them to use it saying that they do no have access to run the script. If they open script editor they can manually run it however that will no fly because I will be sending this out to approximately 50 people.
Here is the code and start and stop are two different scripts. Please let me know if I am missing something and I appreciate the help. Thanks
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
var start = new Date();
function StartScript() {
var last = ss.getLastRow();
ss.getRange(last+1,1).setValue(last+1)
var source = ss.getRange(last+1,1).getValue();
source = Number(source);
if (source <= 16) {
ss.getRange(last+1,2).setValue(start);
}
else {
ss.getRange(last+1,2).setValue("Stop Timing");
}
}
function stop() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var date = new Date();
var last1 = ss.getLastRow();
ss.getRange(last1, 3).setValue(date);
var lastrow = ss.getLastRow()
ss.getRange("D" + (lastrow)).setFormula("=C" + (lastrow) + "-B" + (lastrow));
}

create javascript timestamp from innerhtml string values

I'd like to create a javascript timestamp based on a rails date_select and time_select property. I attached an onChange function to the select helper and fetching the innerhtml to read the values into a div which works fine. Now I want to use those strings from the select property and create a timestamp in js (using it for validations).
I did first try this by making integers from the innerhtml values:
function insertText10()
{
var start_day = document.new_link['link[start_at(3i)]'];
var start_month = document.new_link['link[start_at(2i)]'];
var start_year = document.new_link['link[start_at(1i)]'];
var start_hour = document.new_link['link[start_at(4i)]'];
var start_minute = document.new_link['link[start_at(5i)]'];
var selOption1 = start_day[start_day.selectedIndex];
var selOption2 = start_month[start_month.selectedIndex];
var selOption3 = start_year[start_year.selectedIndex];
var selOption4 = start_hour[start_hour.selectedIndex];
var selOption5 = start_minute[start_minute.selectedIndex];
start_date = new Date(parseInt(selOption3.innerHTML),parseInt(selOption2.innerHTML),parseInt(selOption1.innerHTML),parseInt(selOption4.innerHTML),parseInt(selOption5.innerHTML),0,0);
then by using strings:
start_date = new Date(selOption3.innerHTML+selOption2.innerHTML+selOption1.innerHTML+selOption4.innerHTML+selOption5.innerHTML);
but neither works.
What am I doing wrong?
--
PS: I checked the w3s docu http://www.w3schools.com/jsref/jsref_obj_date.asp to find the solution above.
Solved:
start_date = new Date(parseInt(selOption3.value),parseInt(selOption2.value),parseInt(selOption1.value),parseInt(selOption4.value),parseInt(selOption5.value),0,0);

Improving speed and data efficiency with javascript calculator.

I'm building a javascript calculator (with jquery mobile) for simplifying routine calculations in microscopy. I'm looking to create more efficient code and would love any input... I don't expect anyone to dig through the whole thing, but here is the link to the program for reference: http://www.iscopecalc.com
(the javascript for the calculator is at http://www.iscopecalc.com/js/calc.js )
The calculator basically consists of about 12 inputs that the user can set. Using the values received from these inputs, the calculator generates values for about 15 different parameters and outputs the results in the display. Currently, whenever the state of an input changes, I bind that change event to a quick function that writes the value for that input to a cookie. But the meat of the program comes with the "updateCalc()" function which reads the values from all of the inputs (from stored cookies) and then recalculates every one of the parameters to be displayed and outputs them. I've coped just that function here for ease of access:
function updateCalc(){
readValues(); //load current calculator state into cookies
var data = $.cookie(); //puts all cookie data into object
var fluorData = fluoroTable[data['fluorophore']]; //fluorophore data taken from table at the end of the file depending on chosen fluorophore
var fluorem = fluorData['fluorem'];
var fluorex = fluorData['fluorex'];
var cameraData = cameraTable[data['camera']]; //camera data taken from table at the end of the file depending on chosen camera
var campix = cameraData['campix'];
var chipWidth = cameraData['chipWidth'];
var chipHeight = cameraData['chipHeight'];
var chipHpix = cameraData['chipHpix'];
var chipVpix = cameraData['chipVpix'];
var RefInd = data['media']; //simple variables taken directly from calculator inputs
var NA = data['NAslider'];
var obj = data['objective'];
var cammag = data['cameraRelay'];
var CSUmag = data['CSUrelay'];
var bin = data['binning'];
var pinholeRad;
var FOVlimit;
var mode;
if (data['modality']=='widefield'){ //FOVlimit, pinholeRad, and CSU mag will all depend on which modality is chosen
FOVlimit = 28;
pinholeRad = NaN;
mode = 'Widefield';
CSUmag = 1;
}
else if (data['modality']=='confocal'){
if (data['CSUmodel']=='X1'){
pinholeRad = 25;
if(data['borealis']=='true'){
mode = "Borealis CSU-X1";
FOVlimit = 9;
}
else {
mode = "Yokogawa CSU-X1";
FOVlimit = 7;
CSUmag = 1;
}
}
else if (data['CSUmodel']=='W1'){
mode = "Yokogawa CSU-W1";
FOVlimit = 16;
pinholeRad = data['W1-disk']/2;
CSUmag = 1;
}
}
//These are main outputs and they depend on the input variables above
var latRes = 0.61 * fluorem / NA;
var axRes = 1.4 * fluorem * RefInd / (NA*NA);
var BPpinhole = 1000 * pinholeRad / (obj * CSUmag);
var AU = BPpinhole / latRes;
var totalMag = obj * cammag * CSUmag;
var BPpixel = 1000 * campix * bin / totalMag;
var samples = latRes / BPpixel;
var pixperpin = BPpinhole * 2 / BPpixel;
var sampLit = 1000 * FOVlimit / (obj * CSUmag);
var coverage = FOVlimit * cammag / chipHeight;
if (coverage < 1) {
chipUsed = coverage;
FOV = sampLit;
}
else {
chipUsed = 1;
FOV = sampLit * chipHeight / (FOVlimit * cammag);
}
var sampWaste = 1 - FOV / sampLit;
var imgpix = 1000 * FOV / (chipVpix / bin);
//function goes on to update display with calculated values...
}
It works ok and I'm generally pleased with the results but here's what I'd like advice on:
Each of the input variables only really affects a handful of the outputs (for instance, a change in input #3 would only really change the calculation for a few of the outputs... not all 15), however, my function recalculates ALL outputs everytime ANY of the inputs are changed, regardless of relevance... I've considered making a giant If-Then function that would selectively update only the outputs that would have changed based on the input that was changed. This would obviously take a larger amount of code, but I'm wondering if (once loaded) the code would be faster when using the calculator, of if it would just be a waste of my time and clutter up my code.
I'm also wondering if storing inputs in cookies and reading values back from cookies is a reasonable way to do things and if I should maybe make a global variable instead that stores the state of the calculator. (the cookies have the added benefit of storing the users calculator state for later visits).
I'm pretty new at this stuff, so any and all comments on how I might improve the efficiency of my code would be greatly appreciated (feel free to just link to a page that I should read, or a method I should be using for instance...)
if you've made it this far, thanks for your time!!

Categories