Monotone-Parent: 58a952b10d4574c10176dc598afd887a5e7d2ad2

Monotone-Revision: 01f82c6cdad306ebc5d1e92bf6efe32e51a0d96d

Monotone-Author: wsourdeau@inverse.ca
Monotone-Date: 2006-10-25T23:58:29
Monotone-Branch: ca.inverse.sogo
This commit is contained in:
Wolfgang Sourdeau
2006-10-25 23:58:29 +00:00
parent 1f2533e6ed
commit 1441a66636
6 changed files with 506 additions and 1 deletions
+1
View File
@@ -39,6 +39,7 @@ SchedulerUI_OBJC_FILES = \
UIxCalYearOverview.m \
UIxCalInlineMonthOverview.m \
UIxComponentEditor.m \
UIxFreeBusyUserSelector.m \
UIxAppointmentView.m \
UIxAppointmentEditor.m \
UIxAppointmentProposal.m \
+62
View File
@@ -0,0 +1,62 @@
/* UIxFreeBusyUserSelector.h - this file is part of SOGo
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef UIXFREEBUSYUSERSELECTOR_H
#define UIXFREEBUSYUSERSELECTOR_H
#import <SOGoUI/UIxComponent.h>
@class NSArray;
@class NSMutableArray;
@class NSCalendarDate;
@class NSNumber;
@class SOGoDateFormatter;
@interface UIxFreeBusyUserSelector : UIxComponent
{
SOGoDateFormatter *dateFormatter;
NSCalendarDate *startDate;
NSCalendarDate *endDate;
NSNumber *dayStartHour;
NSNumber *dayEndHour;
NSMutableArray *daysToDisplay;
NSMutableArray *hoursToDisplay;
NSCalendarDate *currentDayToDisplay;
NSNumber *currentHourToDisplay;
}
- (void) setStartDate: (NSCalendarDate *) newStartDate;
- (void) setEndDate: (NSCalendarDate *) newEndDate;
- (void) setDayStartHour: (NSNumber *) newDayStartHour;
- (void) setDayEndHour: (NSNumber *) newDayEndHour;
- (NSArray *) daysToDisplay;
- (NSArray *) hoursToDisplay;
- (void) setCurrentDayToDisplay: (NSCalendarDate *) newCurrentDayToDisplay;
- (void) setCurrentHourToDisplay: (NSNumber *) newCurrentHourToDisplay;
- (NSCalendarDate *) currentDayToDisplay;
- (NSNumber *) currentHourToDisplay;
@end
#endif /* UIXFREEBUSYUSERSELECTOR_H */
+169
View File
@@ -0,0 +1,169 @@
/* UIxFreeBusyUserSelector.m - this file is part of SOGo
*
* Copyright (C) 2006 Inverse groupe conseil
*
* Author: Wolfgang Sourdeau <wsourdeau@inverse.ca>
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#import <Foundation/NSArray.h>
#import <Foundation/NSValue.h>
#import <NGExtensions/NSCalendarDate+misc.h>
#import <SOGoUI/SOGoDateFormatter.h>
#import "UIxFreeBusyUserSelector.h"
@implementation UIxFreeBusyUserSelector
- (id) init
{
if ((self = [super init]))
{
startDate = [NSCalendarDate calendarDate];
[startDate retain];
endDate = [NSCalendarDate calendarDate];
[endDate retain];
dayStartHour = [NSNumber numberWithInt: 8];
[dayStartHour retain];
dayEndHour = [NSNumber numberWithInt: 18];
[dayEndHour retain];
daysToDisplay = nil;
hoursToDisplay = nil;
dateFormatter = [[SOGoDateFormatter alloc]
initWithLocale: [self locale]];
}
return self;
}
- (void) dealloc
{
[startDate release];
[endDate release];
[dayStartHour release];
[dayEndHour release];
if (daysToDisplay)
[daysToDisplay release];
if (hoursToDisplay)
[hoursToDisplay release];
[dateFormatter release];
[super dealloc];
}
- (void) setStartDate: (NSCalendarDate *) newStartDate
{
ASSIGN (startDate, newStartDate);
#warning The following code is hackish and should not be shown to children < 18.
if (daysToDisplay)
{
[daysToDisplay release];
daysToDisplay = nil;
}
}
- (void) setEndDate: (NSCalendarDate *) newEndDate
{
ASSIGN (endDate, newEndDate);
if (daysToDisplay)
{
[daysToDisplay release];
daysToDisplay = nil;
}
}
- (void) setDayStartHour: (NSNumber *) newDayStartHour
{
ASSIGN (dayStartHour, newDayStartHour);
}
- (void) setDayEndHour: (NSNumber *) newDayEndHour
{
ASSIGN (dayEndHour, newDayEndHour);
}
/* in-template operations */
- (NSArray *) daysToDisplay
{
NSCalendarDate *currentDay, *finalDay;
if (!daysToDisplay)
{
daysToDisplay = [NSMutableArray new];
finalDay = [endDate dateByAddingYears: 0 months: 0 days: 2];
currentDay = startDate;
[daysToDisplay addObject: currentDay];
while (![currentDay isDateOnSameDay: finalDay])
{
currentDay = [currentDay dateByAddingYears: 0 months: 0 days: 1];
[daysToDisplay addObject: currentDay];
}
}
return daysToDisplay;
}
- (NSArray *) hoursToDisplay
{
NSNumber *currentHour;
if (!hoursToDisplay)
{
hoursToDisplay = [NSMutableArray new];
currentHour = dayStartHour;
[hoursToDisplay addObject: currentHour];
while (![currentHour isEqual: dayEndHour])
{
currentHour = [NSNumber numberWithInt: [currentHour intValue] + 1];
[hoursToDisplay addObject: currentHour];
}
}
return hoursToDisplay;
}
- (void) setCurrentDayToDisplay: (NSCalendarDate *) newCurrentDayToDisplay
{
currentDayToDisplay = newCurrentDayToDisplay;
}
- (void) setCurrentHourToDisplay: (NSNumber *) newCurrentHourToDisplay
{
currentHourToDisplay = newCurrentHourToDisplay;
}
- (NSCalendarDate *) currentDayToDisplay
{
return currentDayToDisplay;
}
- (NSNumber *) currentHourToDisplay
{
return currentHourToDisplay;
}
- (NSString *) currentFormattedDay
{
return [NSString stringWithFormat: @"%@, %.4d-%.2d-%.2d",
[dateFormatter shortDayOfWeek: [currentDayToDisplay dayOfWeek]],
[currentDayToDisplay yearOfCommonEra],
[currentDayToDisplay monthOfYear],
[currentDayToDisplay dayOfMonth]];
}
@end
+6 -1
View File
@@ -1,5 +1,5 @@
{
requires = ( MAIN, CommonUI, Appointments );
requires = ( MAIN, CommonUI, Appointments, Contacts );
publicResources = (
previous_week.gif,
@@ -188,6 +188,11 @@
pageName = "UIxAppointmentEditor";
actionName = "test";
};
contactSearch = {
protectedBy = "View";
pageName = "UIxFreeBusyUserSelector";
actionName = "contactSearch";
};
};
};
@@ -0,0 +1,60 @@
<?xml version='1.0' standalone='yes'?>
<container
xmlns="http://www.w3.org/1999/xhtml"
xmlns:var="http://www.skyrix.com/od/binding"
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:uix="OGo:uix"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<script type="text/javascript" rsrc:src="UIxFreeBusyUserSelector.js"><!-- space --></script>
<div class="freeBusyView">
<table class="freeBusy">
<thead>
<tr class="freeBusyHeader1">
<th class="attendees"></th>
<var:foreach list="daysToDisplay" item="currentDayToDisplay"
><th colspan="11"><var:string value="currentFormattedDay" /></th
></var:foreach>
</tr>
<tr class="freeBusyHeader2">
<th class="attendees"></th>
<var:foreach list="daysToDisplay" item="currentDayToDisplay"
><var:foreach list="hoursToDisplay" item="currentHourToDisplay"
><th><var:string value="currentHourToDisplay" const:numberformat="00:"/>00</th
></var:foreach
></var:foreach>
</tr>
<tr class="freeBusyHeader3">
<th class="attendees"></th>
<var:foreach list="daysToDisplay" item="currentDayToDisplay"
><var:foreach list="hoursToDisplay" item="currentHourToDisplay"
><th><span class="freeBusyZoneElement"><!-- space --></span><span class="freeBusyZoneElement"><!-- space --></span><span class="freeBusyZoneElement"><!-- space --></span><span class="freeBusyZoneElement"><!-- space --></span></th
></var:foreach
></var:foreach>
</tr>
</thead>
<tbody>
<tr class="futureAttendee">
<td class="attendees"><input type="text" class="textField"
readonly="readonly"
onclick="newAttendee(this);" /></td>
<var:foreach list="daysToDisplay" item="currentDayToDisplay"
><var:foreach list="hoursToDisplay" item="currentHourToDisplay"
><td></td
></var:foreach
></var:foreach>
</tr>
<tr class="attendeeModel">
<td class="attendees"><input type="text" class="textField"
onkeyup="onContactKeyUp(this, event);"
onblur="checkAttendee(this);" /></td>
<var:foreach list="daysToDisplay" item="currentDayToDisplay"
><var:foreach list="hoursToDisplay" item="currentHourToDisplay"
><td></td
></var:foreach
></var:foreach>
</tr>
</tbody>
</table>
</div>
</container>
@@ -0,0 +1,208 @@
var resultsDiv;
var searchField;
var running = false;
var address;
var delay = 500;
var requestField;
function onContactKeyUp(node, event)
{
if (!running && (event.keyCode == 8
|| event.keyCode == 13
|| event.keyCode == 32
|| event.keyCode > 47)) {
running = true;
requestField = node;
setTimeout("triggerRequest()", delay);
}
}
function triggerRequest() {
if (document.contactLookupAjaxRequest) {
document.contactLookupAjaxRequest.aborted = yes;
document.contactLookupAjaxRequest.abort();
}
var urlstr = ( UserFolderURL + "Contacts/contactSearch?search="
+ requestField.value );
document.contactLookupAjaxRequest = triggerAjaxRequest(urlstr,
updateResults,
requestField);
}
function updateResults(http)
{
if (http.readyState == 4) {
if (http.status == 200) {
var searchField = http.callbackData;
var start = searchField.value.length;
var text = http.responseText.split(":");
if (text[0].length > 0)
searchField.uid = text[0];
else
searchField.uid = null;
searchField.hasfreebusy = false;
searchField.value = text[1];
var end = searchField.value.length;
searchField.setSelectionRange(start, end);
}
running = false;
document.contactLookupAjaxRequest = null;
}
}
function resetFreeBusyZone()
{
var table = $("attendeesView").childNodesWithTag("div")[0].childNodesWithTag("table")[0];
var row = table.tHead.rows[2];
for (var i = 1; i < row.cells.length; i++)
{
var nodes = row.cells[i].childNodesWithTag("span");
for (var j = 0; j < nodes.length; j++)
nodes[j].removeClassName("busy");
}
}
function redisplayFreeBusyZone()
{
var table = $("attendeesView").childNodesWithTag("div")[0].childNodesWithTag("table")[0];
var row = table.tHead.rows[2];
var stHour = parseInt(document.forms['editform']["startTime_time_hour"].value);
var stMinute
= parseInt(document.forms['editform']["startTime_time_minute"].value) / 15;
var etHour = parseInt(document.forms['editform']["endTime_time_hour"].value);
var etMinute
= parseInt(document.forms['editform']["endTime_time_minute"].value) / 15;
if (stHour < 8) {
stHour = 8;
stMinute = 0;
}
if (stHour > 18) {
stHour = 18;
stMinute = 0;
}
if (etHour < 8) {
etHour = 8;
etMinute = 0;
}
if (etHour > 18) {
etHour = 18;
etMinute = 0;
}
if (stHour > etHour) {
var swap = etHour;
etHour = stHour;
stHour = swap;
swap = etMinute;
etMinute = stMinute;
stMinute = etMinute;
}
var deltaCells = (etHour - stHour);
var deltaSpans = (deltaCells * 4 ) + (etMinute - stMinute);
var currentCellNbr = stHour - 7;
var currentCell = row.cells[currentCellNbr];
var currentSpanNbr = stMinute;
var spans = currentCell.childNodesWithTag("span");
resetFreeBusyZone();
while (deltaSpans > 0) {
var currentSpan = spans[currentSpanNbr];
currentSpan.addClassName("busy");
currentSpanNbr++;
if (currentSpanNbr > 3) {
currentSpanNbr = 0;
currentCellNbr++;
currentCell = row.cells[currentCellNbr];
spans = currentCell.childNodesWithTag("span");
}
deltaSpans--;
}
}
function newAttendee(node)
{
var table = $("attendeesView").childNodesWithTag("div")[0].childNodesWithTag("table")[0];
var tbody = table.childNodesWithTag("tbody")[0];
var model = tbody.rows[tbody.rows.length - 1];
var newAttendeeRow = tbody.rows[tbody.rows.length - 2]
var newRow = model.cloneNode(true);
newRow.setAttribute("class", "");
tbody.insertBefore(newRow, newAttendeeRow);
newRow.childNodesWithTag("td")[0].childNodesWithTag("input")[0].focus();
}
function checkAttendee(node)
{
var th = node.parentNode.parentNode;
var tbody = th.parentNode;
if (node.value.trim().length == 0)
tbody.removeChild(th);
else if (!node.hasfreebusy) {
displayFreeBusyForNode(node);
node.hasfreebusy = true;
}
}
function displayFreeBusyForNode(node)
{
if (node.uid) {
var nodes = node.parentNode.parentNode.cells;
for (var i = 1; i < nodes.length; i++) {
nodes[i].removeClassName("noFreeBusy");
nodes[i].innerHTML = ('<span class="freeBusyZoneElement"></span>'
+ '<span class="freeBusyZoneElement"></span>'
+ '<span class="freeBusyZoneElement"></span>'
+ '<span class="freeBusyZoneElement"></span>');
}
if (document.contactFreeBusyAjaxRequest) {
document.contactFreeBusyAjaxRequest.aborted = true;
document.contactFreeBusyAjaxRequest.abort();
}
var sd = startDayAsShortString();
var ed = endDayAsShortString();
var urlstr = ( UserFolderURL + "../" + node.uid + "/freebusy.ifb/ajaxRead?"
+ "sday=" + sd + "&eday=" + ed);
document.contactFreeBusyAjaxRequest = triggerAjaxRequest(urlstr,
updateFreeBusyData,
node);
} else {
var nodes = node.parentNode.parentNode.cells;
for (var i = 1; i < nodes.length; i++) {
nodes[i].addClassName("noFreeBusy");
nodes[i].innerHTML = '';
}
}
}
function setSlot(tds, nbr, status) {
var tdnbr = Math.floor(nbr / 4);
var spannbr = nbr - (tdnbr * 4);
var days = 0;
if (tdnbr > 24) {
days = tdnbr / 24;
tdnbr -= (days * 24);
}
log("td: " + tdnbr);
if (tdnbr > 7 && tdnbr < 19) {
log("length: " + tds.length);
log("td: " + days * 12 + tdnbr - 8);
var td = tds[days * 12 + tdnbr - 7];
var spans = td.childNodesWithTag("span");
spans[spannbr].addClassName("busy");
}
}
function updateFreeBusyData(http)
{
if (http.readyState == 4) {
if (http.status == 200) {
var node = http.callbackData;
var slots = http.responseText.split(",");
var tds = node.parentNode.parentNode.cells;
for (var i = 0; i < slots.length; i++) {
if (slots[i] != '0')
setSlot(tds, i, slots[i]);
}
}
document.contactFreeBusyAjaxRequest = null;
}
}