Monotone-Parent: 82c1108954dbd812828ef1b00b0345b524a062a7

Monotone-Revision: 1bc4da9c10aec9ded2d443f77aedb8ceeaaf7ce8

Monotone-Author: flachapelle@inverse.ca
Monotone-Date: 2008-08-18T22:45:59
Monotone-Branch: ca.inverse.sogo
maint-2.0.2
Francis Lachapelle 2008-08-18 22:45:59 +00:00
parent 5f2d61a0d7
commit 0bede69b36
10 changed files with 223 additions and 51 deletions

1
NEWS
View File

@ -6,6 +6,7 @@
- fixed a bug where deleting a contact would leave it listed in the contact list until the next refresh
- fixed a bug where events shared among different attendees would no longer be updated automatically
- changed the look of the Calendar module to match the look of Lightning 0.9
- the event details now appear when clicking on it
0.9.0-20080729 (1.0 rc7)
------------------------

View File

@ -22,6 +22,8 @@
#include <math.h>
#import <Foundation/NSDictionary.h>
#import <NGObjWeb/SoObject.h>
#import <NGObjWeb/SoPermissions.h>
#import <NGObjWeb/SoSecurityManager.h>
@ -36,6 +38,7 @@
#import <NGCards/iCalRecurrenceRule.h>
#import <SoObjects/SOGo/SOGoUser.h>
#import <SoObjects/SOGo/SOGoDateFormatter.h>
#import <SoObjects/SOGo/SOGoContentObject.h>
#import <SoObjects/Appointments/SOGoAppointmentFolder.h>
#import <SoObjects/Appointments/SOGoAppointmentsFolder.h>
@ -267,6 +270,34 @@
return [self jsCloseWithRefreshMethod: @"refreshEventsAndDisplay()"];
}
- (id <WOActionResults>) viewAction
{
id <WOActionResults> result;
NSDictionary *data;
SOGoAppointmentFolder *co;
SOGoDateFormatter *dateFormatter;
SOGoUser *user;
result = [context response];
user = [context activeUser];
co = [self clientObject];
dateFormatter = [user dateFormatterInContext: context];
[self event];
data = [NSDictionary dictionaryWithObjectsAndKeys:
[dateFormatter formattedDate: [event startDate]], @"startDate",
[dateFormatter formattedTime: [event startDate]], @"startTime",
([event hasRecurrenceRules]?@"1":@"0"), @"isReccurent",
([event isAllDay]?@"1":@"0"), @"isAllDay",
[event summary], @"summary",
[event location], @"location",
[event comment], @"description",
nil];
[(WOResponse*)result appendContentString: [data jsonRepresentation]];
return result;
}
- (BOOL) shouldTakeValuesFromRequest: (WORequest *) request
inContext: (WOContext*) context
{

View File

@ -172,6 +172,11 @@
};
};
methods = {
view = {
protectedBy = "ViewAllComponent";
pageName = "UIxAppointmentEditor";
actionName = "view";
};
edit = {
protectedBy = "ViewAllComponent";
pageName = "UIxAppointmentEditor";

View File

@ -76,6 +76,15 @@
<li><var:string label:value="Sharing..." /></li>
</ul>
</div>
<div id="eventDialog" style="display: none;">
<div>
<h1><!-- space --></h1>
<p id="startTime"><span class="label"><var:string label:value="Start:" /></span> <span><!-- space --></span></p>
<p id="location"><span class="label"><var:string label:value="Location:" /></span> <span><!-- space --></span></p>
<p id="description"><!-- space --></p>
</div>
</div>
<div id="leftPanel">
<div class="tabsContainer" id="schedulerTabs">

View File

@ -6,6 +6,7 @@
xmlns:const="http://www.skyrix.com/od/constant"
xmlns:rsrc="OGo:url"
xmlns:label="OGo:label">
<a href="#"
class="leftNavigationArrow"
var:date="prevMonthQueryParameters.day"

View File

@ -1,4 +1,3 @@
DIV#leftPanel
{ position: absolute;
top: 5.5em;
@ -282,6 +281,51 @@ TABLE#eventsList TH
TABLE#eventsList TH
{ white-space: pre; }
DIV#eventDialog
{ position: absolute;
top: 100px;
left: 75px;
width: 200px;
z-index: 50; }
DIV#eventDialog DIV
{ border: 1px solid #444;
/*height: 100px;*/
background-color: #fff;
padding: 5px; }
DIV#eventDialog.left
{ background-image: url("dialog-left.png");
background-repeat: no-repeat;
background-position: top left; }
DIV#eventDialog.left DIV
{ border-left: 0;
margin-left: 19px;
text-align: left; }
DIV#eventDialog.right
{ background-image: url("dialog-right.png");
background-repeat: no-repeat;
background-position: top right; }
DIV#eventDialog.right DIV
{ border-right: 0;
margin-right: 19px;
text-align: right; }
DIV#eventDialog H1,
DIV#eventDialog P
{ font-size: 10px;
margin: 0;
padding: 0; }
DIV#eventDialog SPAN.label
{ color: #444; }
DIV#eventDialog p#description
{ margin-top: 1em; }
._unfocused#dateSelector TD._selected,
UL._unfocused > LI._selected,
TABLE._unfocused#eventsList TR._selected TD
@ -354,19 +398,13 @@ SPAN.monthsHeader A:active
border-right: 1px solid #fff; }
SPAN.week2, SPAN.month2
{
font-size: small;
}
{ font-size: small; }
SPAN.day2, SPAN.week1, SPAN.month1
{
font-size: medium;
}
{ font-size: medium; }
SPAN.day1, SPAN.week0, SPAN.month0
{
font-size: large;
}
{ font-size: large; }
SPAN.day0
{ font-size: x-large; }
@ -891,6 +929,9 @@ DIV.monthView DIV.event
padding: 1px;
height: 1.2em; }
DIV#calendarHeader DIV.event
{ height: 1.5em; }
DIV.event DIV.text
{ font-size: 92%; }

View File

@ -77,7 +77,7 @@ function _editEventId(id, calendar, recurrence) {
urlstr += "/" + recurrence;
targetname += recurrence;
}
urlstr += "/edit";
urlstr += "/edit"; log (urlstr);
var win = window.open(urlstr, "_blank",
"width=490,height=470,resizable=0");
if (win)
@ -315,14 +315,96 @@ function _editRecurrenceDialog(eventDiv, method) {
win.focus();
}
function onViewEvent(event) {
if (event.detail == 2) return;
var url = ApplicationBaseURL + this.calendar + "/" + this.cname + "/view";
if (document.viewEventAjaxRequest) {
document.viewEventAjaxRequest.aborted = true;
document.viewEventAjaxRequest.abort();
}
document.viewEventAjaxRequest = triggerAjaxRequest(url, onViewEventCallback, this);
}
function onViewEventCallback(http) {
if (http.readyState == 4
&& http.status == 200) {
if (http.responseText.length > 0) {
var data = http.responseText.evalJSON(true);
// $H(data).keys().each(function(key) {
// log (key + " = " + data[key]);
// });
var cell = http.callbackData;
var cellPosition = cell.cumulativeOffset();
var cellDimensions = cell.getDimensions();
var div = $("eventDialog");
var divDimensions = div.getDimensions();
var view;
var left = cellPosition[0];
var top = cellPosition[1];
if (currentView != "monthview") {
view = $("daysView");
var viewPosition = view.cumulativeOffset();
if (parseInt(data["isAllDay"]) == 0) {
top -= view.scrollTop;
if (viewPosition[1] > top + 2) {
view.stopObserving("scroll", onBodyClickHandler);
view.scrollTop = cell.offsetTop;
top = viewPosition[1];
Event.observe.delay(0.1, view, "scroll", onBodyClickHandler);
}
}
}
else {
view = $("calendarView");
top -= cell.up("DIV.day").scrollTop;
}
if (left > parseInt(window.width()*0.75)) {
left = left - divDimensions["width"] + 10;
div.removeClassName("left");
div.addClassName("right");
}
else {
left = left + cellDimensions["width"] - parseInt(cellDimensions["width"]/3);
div.removeClassName("right");
div.addClassName("left");
}
// Put the event's data in the DIV
div.down("h1").update(data["summary"]);
if (parseInt(data["isAllDay"]) == 0) {
div.down("P", 0).down("SPAN", 1).update(data["startTime"]);
div.down("P", 0).show();
} else
div.down("P", 0).hide();
if (data["location"].length) {
div.down("P", 1).down("SPAN", 1).update(data["location"]);
div.down("P", 1).show();
} else
div.down("P", 1).hide();
if (data["description"].length) {
div.down("P", 2).update(data["description"]);
div.down("P", 2).show();
} else
div.down("P", 2).hide();
div.setStyle({ left: left + "px",
top: top + "px" });
div.show();
}
}
}
function editDoubleClickedEvent(event) {
if (this.recurrenceTime)
_editRecurrenceDialog(this, "confirmEditing");
else
_editEventId(this.cname, this.calendar);
preventDefault(event);
event.cancelBubble = true;
Event.stop(event);
}
function performEventEdition(folder, event, recurrence) {
@ -667,7 +749,7 @@ function changeCalendarDisplay(data, newView) {
day = currentDay;
if (day) {
if (data && newView != "monthview") {
if (data) {
var divs = $$('div.day[day='+day+']');
if (divs.length) {
// Don't reload the view if the event is present in current view
@ -703,14 +785,10 @@ function changeCalendarDisplay(data, newView) {
}
url += "?day=" + day;
}
// if (newView)
// log ("switching to view: " + newView);
// log ("changeCalendarDisplay: " + url);
selectedCalendarCell = null;
if (document.dayDisplayAjaxRequest) {
// log ("aborting day ajaxrq");
document.dayDisplayAjaxRequest.aborted = true;
document.dayDisplayAjaxRequest.abort();
}
@ -747,39 +825,30 @@ function onMonthOverview() {
}
function scrollDayView(scrollEvent) {
var divs;
// Select event in calendar view
if (scrollEvent) {
var contentView;
var eventRow = $(scrollEvent);
selectCalendarEvent(eventRow.calendar, eventRow.cname, eventRow.recurrenceTime);
var eventBlocks = selectCalendarEvent(eventRow.calendar, eventRow.cname, eventRow.recurrenceTime);
var firstEvent = eventBlocks.first();
if (currentView == "monthview")
contentView = firstEvent.up("DIV.day");
else
contentView = $("daysView");
var top = firstEvent.cumulativeOffset()[1] - contentView.scrollTop;
// Don't scroll if the event is visible to the user
if (top < contentView.cumulativeOffset()[1])
contentView.scrollTop = firstEvent.cumulativeOffset()[1] - contentView.cumulativeOffset()[1];
else if (top > contentView.cumulativeOffset()[1] + contentView.getHeight() - firstEvent.getHeight())
contentView.scrollTop = firstEvent.cumulativeOffset()[1] - contentView.cumulativeOffset()[1];
}
// Don't scroll if in month view
if (currentView == "monthview")
return;
var offset = 0;
var daysView = $("daysView");
var hours = $(daysView.childNodesWithTag("div")[0])
.childNodesWithTag("div");
offset = hours[dayStartHour].offsetTop;
if (scrollEvent && calendarEvents) {
var event = calendarEvents[scrollEvent];
if (event) {
// FIXME siblings
var classes = $w(event.siblings[0].className);
for (var i = 0; i < classes.length; i++)
if (classes[i].startsWith("starts")) {
var starts = Math.floor(parseInt(classes[i].substr(6)) / 4);
offset = hours[starts].offsetTop;
}
}
else if (currentView != "monthview") {
var contentView = $("daysView");
var hours = (contentView.childNodesWithTag("div")[0]).childNodesWithTag("div");
contentView.scrollTop = hours[dayStartHour].offsetTop;
}
daysView.scrollTop = offset - 5;
}
function onClickableCellsDblClick(event) {
@ -916,6 +985,7 @@ function newBaseEventDIV(eventRep, event, eventText) {
eventDiv.observe("mousedown", listRowMouseDownHandler);
eventDiv.observe("click", onCalendarSelectEvent);
eventDiv.observe("dblclick", editDoubleClickedEvent);
eventDiv.observe("click", onViewEvent);
event.blocks.push(eventDiv);
@ -1015,9 +1085,11 @@ function calendarDisplayCallback(http) {
var contentView;
if (currentView == "monthview")
contentView = $("calendarContent");
else
else {
contentView = $("daysView");
contentView.observe("scroll", onBodyClickHandler);
}
refreshCalendarEvents(http.callbackData.scrollEvent);
var days = document.getElementsByClassName("day", contentView);
@ -1027,6 +1099,8 @@ function calendarDisplayCallback(http) {
days[i].observe("dblclick", onClickableCellsDblClick);
days[i].observe("selectstart", listRowMouseDownHandler);
//days[i].down(".dayHeader").observe("selectstart", listRowMouseDownHandler);
if (currentView == "monthview")
days[i].observe("scroll", onBodyClickHandler);
}
else {
var headerDivs = $("calendarHeader").childNodesWithTag("div");
@ -1307,6 +1381,8 @@ function selectCalendarEvent(calendar, cname, recurrenceTime) {
selection[i].selectElement();
selectedCalendarCell = selection;
}
return selection;
}
function onCalendarSelectEvent() {
@ -1863,6 +1939,10 @@ function initDateSelectorEvents() {
menuButton.observe("click", popupMonthMenu);
}
function onBodyClickHandler(event) {
$("eventDialog").hide();
}
function initCalendars() {
sorting["attribute"] = "start";
sorting["ascending"] = true;
@ -1875,6 +1955,7 @@ function initCalendars() {
var selector = $("calendarSelector");
if (selector)
selector.attachMenu("calendarsMenu");
$(document.body).observe("click", onBodyClickHandler);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 B

View File

@ -870,13 +870,16 @@ function setSearchCriteria(event) {
var searchValue = $("searchValue");
var searchCriteria = $("searchCriteria");
if (searchValue.ghostPhrase == searchValue.value)
searchValue.value = this.innerHTML;
searchValue.ghostPhrase = this.innerHTML;
searchCriteria.value = this.getAttribute('id');
if (this.parentNode.chosenNode)
this.parentNode.chosenNode.removeClassName("_chosen");
this.addClassName("_chosen");
if (this.parentNode.chosenNode != this) {
searchValue.lastSearch = "";
this.parentNode.chosenNode = this;
@ -959,7 +962,7 @@ function onSearchKeyDown(event) {
function onSearchFormSubmit(event) {
var searchValue = $("searchValue");
var searchCriteria = $("searchCriteria");
if (searchValue.value != searchValue.ghostPhrase
&& (searchValue.value != searchValue.lastSearch
|| searchValue.value.strip().length > 0)) {