find next/prev slot
Monotone-Parent: 03b6f11c1a9a04660326370486a96b95a63cbaf2 Monotone-Revision: 4efc308e378492efdb95420253ab9f2c2b3ab674 Monotone-Author: crobert@inverse.ca Monotone-Date: 2009-06-04T14:57:50 Monotone-Branch: ca.inverse.sogomaint-2.0.2
parent
bfab0126e3
commit
52a4de60bd
|
@ -1,3 +1,11 @@
|
||||||
|
2009-06-04 Cyril Robert <crobert@inverse.ca>
|
||||||
|
|
||||||
|
* UI/Scheduler/UIxCalListingActions.m: Added everything needed for the
|
||||||
|
findSlot action.
|
||||||
|
* UI/WebServerResources/UIxAttendeesEditor.js: Added everything needed for
|
||||||
|
the findSlot action.
|
||||||
|
* UI/Scheduler/UIxCalListingActions.h (findPossibleSlotAction): Added header.
|
||||||
|
|
||||||
2009-06-03 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
2009-06-03 Wolfgang Sourdeau <wsourdeau@inverse.ca>
|
||||||
|
|
||||||
* SoObjects/SOGo/SOGoGCSFolder.m
|
* SoObjects/SOGo/SOGoGCSFolder.m
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
- (WOResponse *) alarmsListAction;
|
- (WOResponse *) alarmsListAction;
|
||||||
- (WOResponse *) eventsListAction;
|
- (WOResponse *) eventsListAction;
|
||||||
- (WOResponse *) tasksListAction;
|
- (WOResponse *) tasksListAction;
|
||||||
|
- (WOResponse *) findPossibleSlotAction;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#import <SoObjects/Appointments/SOGoAppointmentFolder.h>
|
#import <SoObjects/Appointments/SOGoAppointmentFolder.h>
|
||||||
#import <SoObjects/Appointments/SOGoAppointmentFolders.h>
|
#import <SoObjects/Appointments/SOGoAppointmentFolders.h>
|
||||||
#import <SoObjects/Appointments/SOGoAppointmentObject.h>
|
#import <SoObjects/Appointments/SOGoAppointmentObject.h>
|
||||||
|
#import <Appointments/SOGoFreeBusyObject.h>
|
||||||
|
|
||||||
#import <UI/Common/WODirectAction+SOGo.h>
|
#import <UI/Common/WODirectAction+SOGo.h>
|
||||||
|
|
||||||
|
@ -57,6 +58,12 @@ static NSArray *tasksFields = nil;
|
||||||
#define dayLength 86400
|
#define dayLength 86400
|
||||||
#define quarterLength 900
|
#define quarterLength 900
|
||||||
|
|
||||||
|
#define intervalSeconds 900
|
||||||
|
#define offsetHours 24 * 5
|
||||||
|
#define offsetSeconds offsetHours * 60 * 60
|
||||||
|
#define offsetBlocks offsetHours * 4
|
||||||
|
#define maxBlocks offsetBlocks * 2
|
||||||
|
|
||||||
@implementation UIxCalListingActions
|
@implementation UIxCalListingActions
|
||||||
|
|
||||||
+ (void) initialize
|
+ (void) initialize
|
||||||
|
@ -953,4 +960,289 @@ _computeBlocksPosition (NSArray *blocks)
|
||||||
return [self _responseWithData: filteredTasks];
|
return [self _responseWithData: filteredTasks];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
- (void) _fillFreeBusy: (unsigned int *) fb
|
||||||
|
forUid: (NSString *) uid
|
||||||
|
fromDate: (NSCalendarDate *) start
|
||||||
|
{
|
||||||
|
SOGoUser *user;
|
||||||
|
SOGoFreeBusyObject *fbObject;
|
||||||
|
NSCalendarDate *end;
|
||||||
|
NSTimeInterval interval;
|
||||||
|
NSArray *records;
|
||||||
|
NSDictionary *record;
|
||||||
|
NSArray *emails, *partstates;
|
||||||
|
NSCalendarDate *currentDate;
|
||||||
|
unsigned int intervals, recordCount, recordMax;
|
||||||
|
int count, startInterval, endInterval, i, type;
|
||||||
|
int itemCount = (offsetBlocks + maxBlocks) * 15 * 60;
|
||||||
|
|
||||||
|
user = [SOGoUser userWithLogin: uid roles: nil];
|
||||||
|
fbObject = [[user homeFolderInContext: context]
|
||||||
|
freeBusyObject: @"freebusy.ifb"
|
||||||
|
inContext: context];
|
||||||
|
|
||||||
|
end = [start addTimeInterval: itemCount];
|
||||||
|
|
||||||
|
interval = [end timeIntervalSinceDate: start];// + 60;
|
||||||
|
intervals = interval / intervalSeconds; /* slices of 15 minutes */
|
||||||
|
|
||||||
|
records = [fbObject fetchFreeBusyInfosFrom: start to: end];
|
||||||
|
recordMax = [records count];
|
||||||
|
|
||||||
|
for (recordCount = 0; recordCount < recordMax; recordCount++)
|
||||||
|
{
|
||||||
|
record = [records objectAtIndex: recordCount];
|
||||||
|
if ([[record objectForKey: @"c_isopaque"] boolValue])
|
||||||
|
{
|
||||||
|
type = 0;
|
||||||
|
|
||||||
|
// If the event has NO organizer (which means it's the user that has created it) OR
|
||||||
|
// If we are the organizer of the event THEN we are automatically busy
|
||||||
|
if ([[record objectForKey: @"c_orgmail"] length] == 0 ||
|
||||||
|
[user hasEmail: [record objectForKey: @"c_orgmail"]])
|
||||||
|
{
|
||||||
|
type = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We check if the user has accepted/declined or needs action
|
||||||
|
// on the current event.
|
||||||
|
emails = [[record objectForKey: @"c_partmails"] componentsSeparatedByString: @"\n"];
|
||||||
|
|
||||||
|
for (i = 0; i < [emails count]; i++)
|
||||||
|
{
|
||||||
|
if ([user hasEmail: [emails objectAtIndex: i]])
|
||||||
|
{
|
||||||
|
// We now fetch the c_partstates array and get the participation
|
||||||
|
// status of the user for the event
|
||||||
|
partstates = [[record objectForKey: @"c_partstates"] componentsSeparatedByString: @"\n"];
|
||||||
|
|
||||||
|
if (i < [partstates count])
|
||||||
|
{
|
||||||
|
type = ([[partstates objectAtIndex: i] intValue] < 2 ? 1 : 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
currentDate = [record objectForKey: @"startDate"];
|
||||||
|
if ([currentDate earlierDate: start] == currentDate)
|
||||||
|
startInterval = 0;
|
||||||
|
else
|
||||||
|
startInterval = ([currentDate timeIntervalSinceDate: start]
|
||||||
|
/ intervalSeconds);
|
||||||
|
|
||||||
|
currentDate = [record objectForKey: @"endDate"];
|
||||||
|
if ([currentDate earlierDate: end] == end)
|
||||||
|
endInterval = itemCount - 1;
|
||||||
|
else
|
||||||
|
endInterval = ([currentDate timeIntervalSinceDate: start]
|
||||||
|
/ intervalSeconds);
|
||||||
|
|
||||||
|
if (type == 1)
|
||||||
|
for (count = startInterval; count < endInterval; count++)
|
||||||
|
*(fb + count) = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
- (unsigned int **) _loadFreeBusyForUsers: (NSArray *) uids
|
||||||
|
fromDate: (NSCalendarDate *) start
|
||||||
|
{
|
||||||
|
unsigned int **fbData, **node, count;
|
||||||
|
|
||||||
|
fbData = calloc ([uids count], sizeof (unsigned int *));
|
||||||
|
for (count = 0; count < [uids count]; count++)
|
||||||
|
{
|
||||||
|
fbData[count] = calloc (offsetBlocks + maxBlocks, sizeof (unsigned int *));
|
||||||
|
node = fbData + count;
|
||||||
|
[self _fillFreeBusy: *node
|
||||||
|
forUid: [uids objectAtIndex: count]
|
||||||
|
fromDate: start];
|
||||||
|
}
|
||||||
|
|
||||||
|
return fbData;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) _possibleBlock: (int) block
|
||||||
|
forUsers: (int) users
|
||||||
|
freeBusy: (unsigned int **) fbData
|
||||||
|
interval: (int) blocks
|
||||||
|
{
|
||||||
|
unsigned int *node;
|
||||||
|
int bCount, uCount;
|
||||||
|
BOOL rc = YES;
|
||||||
|
|
||||||
|
for (uCount = 0; uCount < users; uCount++)
|
||||||
|
{
|
||||||
|
node = *(fbData + uCount);
|
||||||
|
for (bCount = block; bCount < block + blocks; bCount++)
|
||||||
|
{
|
||||||
|
if (*(node+bCount) != 0)
|
||||||
|
{
|
||||||
|
rc = NO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSCalendarDate *) _parseDateField: (NSString *) dateF
|
||||||
|
timeField: (NSString *) timeF
|
||||||
|
{
|
||||||
|
NSString *buffer;
|
||||||
|
NSCalendarDate *rc;
|
||||||
|
|
||||||
|
buffer = [NSString stringWithFormat: @"%@ %@",
|
||||||
|
[[context request] formValueForKey: dateF],
|
||||||
|
[[context request] formValueForKey: timeF]];
|
||||||
|
rc = [NSCalendarDate dateWithString: buffer
|
||||||
|
calendarFormat: @"%Y%m%d %H:%M"];
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSMutableDictionary *) _makeValidResponseFrom: (NSCalendarDate *) nStart
|
||||||
|
to: (NSCalendarDate *) nEnd
|
||||||
|
{
|
||||||
|
NSMutableDictionary *rc;
|
||||||
|
|
||||||
|
rc = [NSMutableDictionary dictionaryWithCapacity: 512];
|
||||||
|
[rc setObject: [nStart descriptionWithCalendarFormat: @"%Y%m%d"]
|
||||||
|
forKey: @"startDate"];
|
||||||
|
[rc setObject: [nStart descriptionWithCalendarFormat: @"%H"]
|
||||||
|
forKey: @"startHour"];
|
||||||
|
[rc setObject: [nStart descriptionWithCalendarFormat: @"%M"]
|
||||||
|
forKey: @"startMinute"];
|
||||||
|
|
||||||
|
[rc setObject: [nEnd descriptionWithCalendarFormat: @"%Y%m%d"]
|
||||||
|
forKey: @"endDate"];
|
||||||
|
[rc setObject: [nEnd descriptionWithCalendarFormat: @"%H"]
|
||||||
|
forKey: @"endHour"];
|
||||||
|
[rc setObject: [nEnd descriptionWithCalendarFormat: @"%M"]
|
||||||
|
forKey: @"endMinute"];
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL) _validateStart: (NSCalendarDate *) start
|
||||||
|
andEnd: (NSCalendarDate *) end
|
||||||
|
against: (NSArray *) limits
|
||||||
|
{
|
||||||
|
NSCalendarDate *maxFrom, *maxTo;
|
||||||
|
NSString *buffer;
|
||||||
|
BOOL rc = YES;
|
||||||
|
|
||||||
|
buffer = [NSString stringWithFormat: @"%04d-%02d-%02d %@ %05d",
|
||||||
|
[start yearOfCommonEra], [start monthOfYear], [start dayOfMonth],
|
||||||
|
[[limits objectAtIndex: 0] descriptionWithCalendarFormat: @"%H:%M"],
|
||||||
|
([[start timeZone] secondsFromGMTForDate: start]/36)];
|
||||||
|
maxFrom = [NSCalendarDate dateWithString: buffer
|
||||||
|
calendarFormat: @"%Y-%m-%d %H:%M %z"];
|
||||||
|
|
||||||
|
buffer = [NSString stringWithFormat: @"%04d-%02d-%02d %@ %05d",
|
||||||
|
[start yearOfCommonEra], [start monthOfYear], [start dayOfMonth],
|
||||||
|
[[limits objectAtIndex: 1] descriptionWithCalendarFormat: @"%H:%M"],
|
||||||
|
([[end timeZone] secondsFromGMTForDate: end]/36)];
|
||||||
|
maxTo = [NSCalendarDate dateWithString: buffer
|
||||||
|
calendarFormat: @"%Y-%m-%d %H:%M %z"];
|
||||||
|
|
||||||
|
if ([maxFrom compare: start] == NSOrderedDescending)
|
||||||
|
rc = NO;
|
||||||
|
if ([maxTo compare: end] == NSOrderedAscending)
|
||||||
|
rc = NO;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray *) _loadScheduleLimitsForUsers: (NSArray *) users
|
||||||
|
{
|
||||||
|
SOGoUserDefaults *ud;
|
||||||
|
NSCalendarDate *from, *to, *maxFrom, *maxTo;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
maxFrom = [NSCalendarDate dateWithString: @"00:01"
|
||||||
|
calendarFormat: @"%H:%M"];
|
||||||
|
maxTo = [NSCalendarDate dateWithString: @"23:59"
|
||||||
|
calendarFormat: @"%H:%M"];
|
||||||
|
|
||||||
|
for (count = 0; count < [users count]; count++)
|
||||||
|
{
|
||||||
|
ud = [[SOGoUser userWithLogin: [users objectAtIndex: count]
|
||||||
|
roles: nil] primaryUserDefaults];
|
||||||
|
from = [NSCalendarDate dateWithString: [ud objectForKey: @"DayStartTime"]
|
||||||
|
calendarFormat: @"%H:%M"];
|
||||||
|
to = [NSCalendarDate dateWithString: [ud objectForKey: @"DayEndTime"]
|
||||||
|
calendarFormat: @"%H:%M"];
|
||||||
|
maxFrom = (NSCalendarDate *)[from laterDate: maxFrom];
|
||||||
|
maxTo = (NSCalendarDate *)[to earlierDate: maxTo];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [NSArray arrayWithObjects: maxFrom, maxTo, nil];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (WOResponse *) findPossibleSlotAction
|
||||||
|
{
|
||||||
|
WORequest *r;
|
||||||
|
NSCalendarDate *nStart, *nEnd;
|
||||||
|
NSArray *uids, *limits;
|
||||||
|
NSMutableDictionary *rc;
|
||||||
|
int direction, count, blockDuration;
|
||||||
|
unsigned int **fbData;
|
||||||
|
|
||||||
|
r = [context request];
|
||||||
|
rc = nil;
|
||||||
|
|
||||||
|
uids = [[r formValueForKey: @"uids"] componentsSeparatedByString: @","];
|
||||||
|
if ([uids count] > 0)
|
||||||
|
{
|
||||||
|
limits = [self _loadScheduleLimitsForUsers: uids];
|
||||||
|
|
||||||
|
direction = [[r formValueForKey: @"direction"] intValue];
|
||||||
|
nStart = [[self _parseDateField: @"startDate"
|
||||||
|
timeField: @"startTime"]
|
||||||
|
addTimeInterval: intervalSeconds * direction];
|
||||||
|
nEnd = [[self _parseDateField: @"endDate"
|
||||||
|
timeField: @"endTime"]
|
||||||
|
addTimeInterval: intervalSeconds * direction];
|
||||||
|
blockDuration = [nEnd timeIntervalSinceDate: nStart] / intervalSeconds;
|
||||||
|
|
||||||
|
fbData = [self _loadFreeBusyForUsers: uids
|
||||||
|
fromDate: [nStart addTimeInterval: -offsetSeconds]];
|
||||||
|
|
||||||
|
for (count = offsetBlocks;
|
||||||
|
(count < offsetBlocks + maxBlocks) && count >= 0;
|
||||||
|
count += direction)
|
||||||
|
{
|
||||||
|
if ([self _validateStart: nStart
|
||||||
|
andEnd: nEnd
|
||||||
|
against: limits])
|
||||||
|
{
|
||||||
|
if ([self _possibleBlock: count
|
||||||
|
forUsers: [uids count]
|
||||||
|
freeBusy: fbData
|
||||||
|
interval: blockDuration])
|
||||||
|
{
|
||||||
|
rc = [self _makeValidResponseFrom: nStart
|
||||||
|
to: nEnd];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nStart = [nStart addTimeInterval: intervalSeconds * direction];
|
||||||
|
nEnd = [nEnd addTimeInterval: intervalSeconds * direction];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (count = 0; count < [uids count]; count++)
|
||||||
|
free (*(fbData+count));
|
||||||
|
free (fbData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [self _responseWithData: [NSArray arrayWithObjects: rc, nil]];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -74,6 +74,11 @@
|
||||||
actionClass = "UIxCalListingActions";
|
actionClass = "UIxCalListingActions";
|
||||||
actionName = "tasksList";
|
actionName = "tasksList";
|
||||||
};
|
};
|
||||||
|
findPossibleSlot = {
|
||||||
|
protectedBy = "View";
|
||||||
|
actionClass = "UIxCalListingActions";
|
||||||
|
actionName = "findPossibleSlot";
|
||||||
|
};
|
||||||
dayview = {
|
dayview = {
|
||||||
protectedBy = "View";
|
protectedBy = "View";
|
||||||
pageName = "UIxCalDayView";
|
pageName = "UIxCalDayView";
|
||||||
|
|
|
@ -21,9 +21,9 @@
|
||||||
<div id="attendeesView">
|
<div id="attendeesView">
|
||||||
<div id="freeBusyViewButtons">
|
<div id="freeBusyViewButtons">
|
||||||
<var:string label:value="Suggest time slot:"/>
|
<var:string label:value="Suggest time slot:"/>
|
||||||
<a href="#" class="button _disabled"
|
<a id="previousSlot" href="#" class="button"
|
||||||
><var:string label:value="Previous slot" /></a>
|
><var:string label:value="Previous slot" /></a>
|
||||||
<a href="#" class="button _disabled"
|
<a id="nextSlot" href="#" class="button"
|
||||||
><var:string label:value="Next slot" /></a>
|
><var:string label:value="Next slot" /></a>
|
||||||
</div>
|
</div>
|
||||||
<!--
|
<!--
|
||||||
|
|
|
@ -447,9 +447,9 @@ function initializeWindowButtons() {
|
||||||
okButton.observe("click", onEditorOkClick, false);
|
okButton.observe("click", onEditorOkClick, false);
|
||||||
cancelButton.observe("click", onEditorCancelClick, false);
|
cancelButton.observe("click", onEditorCancelClick, false);
|
||||||
|
|
||||||
var buttons = $("freeBusyViewButtons").childNodesWithTag("a");
|
$("previousSlot").observe ("click", onPreviousSlotClick, false);
|
||||||
for (var i = 0; i < buttons.length; i++)
|
$("nextSlot").observe ("click", onNextSlotClick, false);
|
||||||
buttons[i].observe("click", listRowMouseDownHandler, false);
|
|
||||||
/* buttons = $("freeBusyZoomButtons").childNodesWithTag("a");
|
/* buttons = $("freeBusyZoomButtons").childNodesWithTag("a");
|
||||||
for (var i = 0; i < buttons.length; i++)
|
for (var i = 0; i < buttons.length; i++)
|
||||||
buttons[i].observe("click", listRowMouseDownHandler, false);
|
buttons[i].observe("click", listRowMouseDownHandler, false);
|
||||||
|
@ -459,6 +459,84 @@ function initializeWindowButtons() {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findSlot (direction) {
|
||||||
|
var userList = UserLogin;
|
||||||
|
var table = $("freeBusy");
|
||||||
|
var inputs = table.getElementsByTagName("input");
|
||||||
|
var sd = window.timeWidgets['start']['date'].valueAsShortDateString();
|
||||||
|
var st = window.timeWidgets['start']['hour'].value
|
||||||
|
+ ":" + window.timeWidgets['start']['minute'].value;
|
||||||
|
var ed = window.timeWidgets['end']['date'].valueAsShortDateString();
|
||||||
|
var et = window.timeWidgets['end']['hour'].value
|
||||||
|
+ ":" + window.timeWidgets['end']['minute'].value;
|
||||||
|
|
||||||
|
for (var i = 0; i < inputs.length - 2; i++)
|
||||||
|
{
|
||||||
|
userList += "," + inputs[i].uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Abort any pending request
|
||||||
|
if (document.findSlotAjaxRequest) {
|
||||||
|
document.findSlotAjaxRequest.aborted = true;
|
||||||
|
document.findSlotAjaxRequest.abort();
|
||||||
|
}
|
||||||
|
var urlstr = (ApplicationBaseURL
|
||||||
|
+ "/findPossibleSlot?direction=" + direction
|
||||||
|
+ "&uids=" + escape (userList)
|
||||||
|
+ "&startDate=" + escape (sd)
|
||||||
|
+ "&startTime=" + escape (st)
|
||||||
|
+ "&endDate=" + escape (ed)
|
||||||
|
+ "&endTime=" + escape (et));
|
||||||
|
document.findSlotAjaxRequest = triggerAjaxRequest(urlstr,
|
||||||
|
updateSlotDisplayCallback,
|
||||||
|
userList);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanInt (data) {
|
||||||
|
var rc = data;
|
||||||
|
if (rc.substr (0, 1) == "0")
|
||||||
|
rc = rc.substr (1, rc.length - 1);
|
||||||
|
return parseInt (rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSlotDisplayCallback (http) {
|
||||||
|
var data = http.responseText.evalJSON (true);
|
||||||
|
var start = new Date ();
|
||||||
|
var end = new Date ();
|
||||||
|
var cb = redisplayFreeBusyZone;
|
||||||
|
|
||||||
|
start.setFullYear (parseInt (data[0]['startDate'].substr (0, 4)),
|
||||||
|
parseInt (data[0]['startDate'].substr (4, 2)) - 1,
|
||||||
|
parseInt (data[0]['startDate'].substr (6, 2)));
|
||||||
|
end.setFullYear (parseInt (data[0]['endDate'].substr (0, 4)),
|
||||||
|
parseInt (data[0]['endDate'].substr (4, 2)) - 1,
|
||||||
|
parseInt (data[0]['endDate'].substr (6, 2)));
|
||||||
|
|
||||||
|
window.timeWidgets['end']['date'].setValueAsDate (end);
|
||||||
|
window.timeWidgets['end']['hour'].value = cleanInt (data[0]['endHour']);
|
||||||
|
window.timeWidgets['end']['minute'].value = cleanInt (data[0]['endMinute']);
|
||||||
|
|
||||||
|
if (window.timeWidgets['start']['date'].valueAsShortDateString () !=
|
||||||
|
data[0]['startDate'])
|
||||||
|
{
|
||||||
|
cb = onTimeDateWidgetChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.timeWidgets['start']['date'].setValueAsDate (start);
|
||||||
|
window.timeWidgets['start']['hour'].value = cleanInt (data[0]['startHour']);
|
||||||
|
window.timeWidgets['start']['minute'].value = cleanInt (data[0]['startMinute']);
|
||||||
|
|
||||||
|
cb ();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPreviousSlotClick (event) {
|
||||||
|
findSlot (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onNextSlotClick (event) {
|
||||||
|
findSlot (1);
|
||||||
|
}
|
||||||
|
|
||||||
function onEditorOkClick(event) {
|
function onEditorOkClick(event) {
|
||||||
preventDefault(event);
|
preventDefault(event);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue