--- a/calendar/base/content/calendar-multiday-view.xml
+++ b/calendar/base/content/calendar-multiday-view.xml
@@ -271,32 +271,40 @@
<xul:box anonid="fgdragspacer" style="display: inherit; overflow: hidden;">
<xul:spacer flex="1"/>
<xul:label anonid="fgdragbox-startlabel" class="fgdragbox-label"/>
</xul:box>
<xul:box anonid="fgdragbox" class="fgdragbox" />
<xul:label anonid="fgdragbox-endlabel" class="fgdragbox-label"/>
</xul:box>
</xul:stack>
- <xul:calendar-event-box anonid="config-box" hidden="true" xbl:inherits="orient"/>
+ <xul:calendar-event-box anonid="config-box" hidden="true" xbl:inherits="orient"/>
</content>
<implementation>
<constructor><![CDATA[
- this.mEvents = Array();
+ this.mEventInfos = Array();
this.mTimezone = UTC();
]]></constructor>
<!-- fields -->
<field name="mPixPerMin">0.6</field>
<field name="mStartMin">0*60</field>
<field name="mEndMin">24*60</field>
<field name="mDayStartMin">8*60</field>
<field name="mDayEndMin">17*60</field>
- <field name="mEvents">new Array()</field>
+ an Array of objects that contain information about the events that are to be
+ displayed. The contained fields are:
+ event: The event that is to be displayed in a 'calendar-event-box'
+ layoutStart: The 'start'-datetime object of the event in the timezone of the view
+ layoutEnd: The 'end'-datetime object of the event in the timezone of the view.
+ The 'layoutEnd' may be different from the real 'end' time of the
+ event because it considers a certain minimum duration of the event
+ that is basically dependent of the font-size of the event-box label
+ <field name="mEventInfos">new Array()</field>
<field name="mEventMap">null</field>
<field name="mCalendarView">null</field>
<field name="mDate">null</field>
<field name="mTimezone">null</field>
<field name="mDragState">null</field>
<field name="mLayoutBatchCount">0</field>
<!-- Since we'll often be getting many events in rapid succession, this
timer helps ensure that we don't re-compute the event map too many
@@ -420,17 +428,17 @@
return this.mDayOff;
]]></getter>
<setter><![CDATA[
this.mDayOff = val;
return val;
]]></setter>
</property>
- <!-- mEvents -->
+ <!-- mEventInfos -->
<field name="mSelectedChunks">[]</field>
<method name="selectOccurrence">
<parameter name="aOccurrence"/>
<body><![CDATA[
if (aOccurrence) {
this.mSelectedItemIds[aOccurrence.hashId] = true;
var chunk = this.findChunkForOccurrence(aOccurrence);
@@ -502,43 +510,43 @@
]]></body>
</method>
<method name="internalDeleteEvent">
<parameter name="aOccurrence"/>
<body><![CDATA[
var itemIndex = -1;
var occ;
- for (var i in this.mEvents) {
- occ = this.mEvents[i].event;
+ for (var i in this.mEventInfos) {
+ occ = this.mEventInfos[i].event;
if (occ.hashId == aOccurrence.hashId)
{
itemIndex = i;
break;
}
}
if (itemIndex != -1) {
delete this.mSelectedItemIds[occ.hashId];
function isNotItem(a) {
return a.occurrence.hashId != aOccurrence.hashId;
}
this.mSelectedChunks = this.mSelectedChunks.filter(isNotItem);
- this.mEvents.splice(itemIndex, 1);
+ this.mEventInfos.splice(itemIndex, 1);
return true;
} else {
return false;
}
]]></body>
</method>
<method name="recalculateStartEndMinutes">
<body><![CDATA[
- for each (var chunk in this.mEvents) {
+ for each (var chunk in this.mEventInfos) {
var mins = this.getStartEndMinutesForOccurrence(chunk.event);
chunk.startMinute = mins.start;
chunk.endMinute = mins.end;
}
this.relayout();
]]></body>
</method>
@@ -595,17 +603,17 @@
</method>
<method name="addEvent">
<parameter name="aOccurrence"/>
<body><![CDATA[
this.internalDeleteEvent(aOccurrence);
var chunk = this.createChunk(aOccurrence);
- this.mEvents.push(chunk);
+ this.mEventInfos.push(chunk);
if (this.mEventMapTimeout) {
clearTimeout(this.mEventMapTimeout);
}
var column = this;
if (this.mCreatedNewEvent) {
this.mEventToEdit = aOccurrence;
}
@@ -643,19 +651,19 @@
var orient = this.getAttribute("orient");
this.bgbox.setAttribute("orient", orient);
// bgbox is used mainly for drawing the grid. at some point it may
// also be used for all-day events.
var otherorient = getOtherOrientation(orient);
var configBox = document.getAnonymousElementByAttribute(this, "anonid", "config-box");
- configBox.removeAttribute("hidden");
+ configBox.removeAttribute("hidden");
var minSize = configBox.getOptimalMinSize();
- configBox.setAttribute("hidden", "true");
+ configBox.setAttribute("hidden", "true");
this.mMinDuration = Components.classes["@mozilla.org/calendar/duration;1"]
.createInstance(Components.interfaces.calIDuration);
this.mMinDuration.minutes = parseInt(minSize/this.mPixPerMin);
var theMin = this.mStartMin;
while (theMin < this.mEndMin) {
var dur = theMin % 60;
theMin += dur;
@@ -865,44 +873,46 @@
* item: the event/task
* startCol: the starting column to display the event in (0-indexed)
* colSpan: the number of columns the item spans
*
* An item with no conflicts will have startCol: 0 and colSpan: 1.
*/
var blobs = new Array();
var currentBlob = new Array();
- function sortByStart(a, b) {
- function assureFloating(aDateTime) {
- if (aDateTime.timezone.isFloating) {
- aDateTime = aDateTime.getInTimezone(self.mTimezone);
- }
- return aDateTime;
- }
+ function sortByStart(aEventInfo, bEventInfo) {
// If you pass in tasks without both entry and due dates, I will
// kill you
- var aStart = a.event.startDate || a.event.entryDate;
- aStart = assureFloating(aStart);
- var bStart = b.event.startDate || b.event.entryDate;
- bStart = assureFloating(bStart);
- var startComparison = aStart.compare(bStart);
+ var startComparison = aEventInfo.layoutStart.compare(bEventInfo.layoutStart);
if (startComparison != 0) {
return startComparison;
} else {
- var aEnd = a.event.endDate || a.event.dueDate;
- aEnd = assureFloating(aEnd);
- var bEnd = b.event.endDate || b.event.dueDate;
- bEnd = assureFloating(bEnd);
// If the items start at the same time, return the longer one
// first
- return bEnd.compare(aEnd);
+ return bEventInfo.layoutEnd.compare(aEventInfo.layoutEnd);
}
}
var self = this;
- this.mEvents.sort(sortByStart);
+ this.mEventInfos.forEach(function(aEventInfo) {
+ let item = aEventInfo.event.clone();
+ let start = item.startDate || item.entryDate;
+ start = start.getInTimezone(self.mTimezone);
+ aEventInfo.layoutStart = start;
+ let end = item.endDate || item.dueDate
+ end = end.getInTimezone(self.mTimezone);
+ let secEnd = start.clone();
+ secEnd.addDuration(self.mMinDuration);
+ if (secEnd.nativeTime > end.nativeTime) {
+ aEventInfo.layoutEnd = secEnd;
+ } else {
+ aEventInfo.layoutEnd = end;
+ }
+ return aEventInfo;
+ });
+ this.mEventInfos.sort(sortByStart);
// The end time of the last ending event in the entire blob
var latestItemEnd;
// This array keeps track of the last (latest ending) item in each of
// the columns of the current blob. We could reconstruct this data at
// any time by looking at the items in the blob, but that would hurt
// perf.
@@ -911,25 +921,25 @@
/* Go through a 3 step process to try and place each item.
* Step 1: Look for an existing column with room for the item.
* Step 2: Look for a previously placed item that can be shrunk in
* width to make room for the item.
* Step 3: Give up and create a new column for the item.
*
* (The steps are explained in more detail as we come to them)
*/
- for (var i in this.mEvents) {
- var item = this.mEvents[i].event;
- var itemStart, itemEnd;
- [itemStart, itemEnd] = this.getLayoutEnd(item);
+ for (var i in this.mEventInfos) {
+ var curItemInfo = {event: this.mEventInfos[i].event,
+ layoutStart: this.mEventInfos[i].layoutStart,
+ layoutEnd: this.mEventInfos[i].layoutEnd};
if (!latestItemEnd) {
- latestItemEnd = itemEnd;
+ latestItemEnd = curItemInfo.layoutEnd;
}
if (currentBlob.length && latestItemEnd &&
- itemStart.compare(latestItemEnd) != -1) {
+ curItemInfo.layoutStart.compare(latestItemEnd) != -1) {
// We're done with this current blob because item starts
// after the last event in the current blob ended.
blobs.push({blob: currentBlob, totalCols: colEndArray.length});
// Reset our variables
currentBlob = new Array();
colEndArray = new Array();
}
@@ -949,45 +959,45 @@
// | | |
// |OPEN! | |<--Our item's start time might be here
// | |______|
// | | |
//
// Remember that any time we're starting a new blob, colEndArray
// will be empty, but that's ok.
for (var ii = 0; ii < colEndArray.length; ++ii) {
- var colStart, colEnd;
- [colStart, colEnd] = this.getLayoutEnd(colEndArray[ii]);
- if (colEnd.compare(itemStart) != 1) {
+ var colStart = colEndArray[ii].layoutStart;
+ var colEnd = colEndArray[ii].layoutEnd;
+ if (colEnd.compare(curItemInfo.layoutStart) != 1) {
// Yay, we can jump into this column
- colEndArray[ii] = item;
+ colEndArray[ii] = curItemInfo;
// Check and see if there are any adjacent columns we can
// jump into as well.
var lastCol = Number(ii) + 1;
while (lastCol < colEndArray.length) {
- var nextColStart, nextColEnd;
- [nextColStart, nextColEnd] = this.getLayoutEnd(colEndArray[lastCol]);
+ var nextColStart = colEndArray[lastCol].layoutStart;
+ var nextColEnd = colEndArray[lastCol].layoutEnd;
// If the next column's item ends after we start, we
// can't expand any further
- if (nextColEnd.compare(itemStart) == 1) {
+ if (nextColEnd.compare(curItemInfo.layoutStart) == 1) {
break;
}
- colEndArray[lastCol] = item;
+ colEndArray[lastCol] = curItemInfo;
lastCol++;
}
// Now construct the info we need to push into the blob
- currentBlob.push({item: item,
+ currentBlob.push({itemInfo: curItemInfo,
startCol: ii,
colSpan: lastCol - ii});
// Update latestItemEnd
if (latestItemEnd &&
- itemEnd.compare(latestItemEnd) == 1) {
- latestItemEnd = itemEnd;
+ curItemInfo.layoutEnd.compare(latestItemEnd) == 1) {
+ latestItemEnd = curItemInfo.layoutEnd;
}
placedItem = true;
break; // Stop iterating through colEndArray
}
}
if (placedItem) {
// Go get the next item
@@ -1006,40 +1016,40 @@
// | | |______|
// | |_____________|
// | |ev2 |
// |______| |<--If our item's start time is
// | |_____________| here, we can shrink ev2 and jump
// | | | | in column #3
//
for (var jj=1; jj<colEndArray.length; ++jj) {
- if (colEndArray[jj].hashId == colEndArray[jj-1].hashId) {
+ if (colEndArray[jj].event.hashId == colEndArray[jj-1].event.hashId) {
// Good we found a item that spanned multiple columns.
// Find it in the blob so we can modify its properties
for (var kk in currentBlob) {
- if (currentBlob[kk].item.hashId == colEndArray[jj].hashId) {
+ if (currentBlob[kk].itemInfo.event.hashId == colEndArray[jj].event.hashId) {
// Take all but the first spot that the item spanned
var spanOfShrunkItem = currentBlob[kk].colSpan;
- currentBlob.push({item: item,
+ currentBlob.push({itemInfo: curItemInfo,
startCol: Number(currentBlob[kk].startCol) + 1,
colSpan: spanOfShrunkItem - 1});
// Update colEndArray
for (var ll = jj; ll < jj + spanOfShrunkItem - 1; ll++) {
- colEndArray[ll] = item;
+ colEndArray[ll] = curItemInfo;
}
// Modify the data on the old item
- currentBlob[kk] = {item: currentBlob[kk].item,
+ currentBlob[kk] = {itemInfo: currentBlob[kk].itemInfo,
startCol: currentBlob[kk].startCol,
colSpan: 1};
// Update latestItemEnd
if (latestItemEnd &&
- itemEnd.compare(latestItemEnd) == 1) {
- latestItemEnd = itemEnd;
+ curItemInfo.layoutEnd.compare(latestItemEnd) == 1) {
+ latestItemEnd = curItemInfo.layoutEnd;
}
break; // Stop iterating through currentBlob
}
}
placedItem = true;
break; // Stop iterating through colEndArray
}
}
@@ -1057,66 +1067,42 @@
// conflicts with the item we're trying to place, need to have
// their span extended by 1, since we're adding the new column
//
// * Note that there can only be one, because we sorted our
// events by start time, so this event must start later than
// the start of any possible conflicts.
var lastColNum = colEndArray.length;
for (var mm in currentBlob) {
- var mmStart, mmEnd;
- [mmStart, mmEnd] = this.getLayoutEnd(currentBlob[mm].item);
+ var mmStart = currentBlob[mm].itemInfo.layoutStart;
+ var mmEnd = currentBlob[mm].itemInfo.layoutEnd;
if (currentBlob[mm].startCol + currentBlob[mm].colSpan == lastColNum &&
- mmEnd.compare(itemStart) != 1) {
- currentBlob[mm] = {item: currentBlob[mm].item,
+ mmEnd.compare(curItemInfo.layoutStart) != 1) {
+ currentBlob[mm] = {itemInfo: currentBlob[mm].itemInfo,
startCol: currentBlob[mm].startCol,
colSpan: currentBlob[mm].colSpan + 1};
}
}
- currentBlob.push({item: item,
+ currentBlob.push({itemInfo: curItemInfo,
startCol: colEndArray.length,
colSpan: 1});
- colEndArray.push(item);
+ colEndArray.push(curItemInfo);
// Update latestItemEnd
- if (latestItemEnd && itemEnd.compare(latestItemEnd) == 1) {
- latestItemEnd = itemEnd;
+ if (latestItemEnd && curItemInfo.layoutEnd.compare(latestItemEnd) == 1) {
+ latestItemEnd = curItemInfo.layoutEnd;
}
// Go get the next item
}
// Add the last blob
blobs.push({blob: currentBlob,
totalCols: colEndArray.length});
-
return this.setupBoxStructure(blobs);
]]></body>
</method>
-
- <method name="getLayoutEnd">
- <parameter name="aItem"/>
- <body><![CDATA[
- var item = aItem.clone();
- var start = item.startDate || item.entryDate;
- if (!compareObjects(start.timezone, this.mTimezone)) {
- start = start.getInTimezone(this.mTimezone);
- }
- var end = item.endDate || item.dueDate
- if (!compareObjects(end.timezone, this.mTimezone)) {
- end = end.getInTimezone(this.mTimezone);
- }
- var secEnd = start.clone();
- secEnd.addDuration(this.mMinDuration);
- if (secEnd.nativeTime > end.nativeTime) {
- return [start, secEnd];
- } else {
- return [start, end];
- }
- ]]></body>
- </method>
-
<method name="setupBoxStructure">
<parameter name="aBlobs"/>
<body><![CDATA[
// This is actually going to end up being a 3-d array
// 1st dimension: "layers", sets of columns of events that all
// should have equal width*
// 2nd dimension: "columns", individual columns of non-conflicting
// items
@@ -1184,18 +1170,18 @@
var col = layers[layerIndex][data.startCol];
if (specialSpan) {
col.specialSpan = specialSpan;
}
// take into account that items can span several days.
// that's why i'm clipping the start- and end-time to the
// timespan of this column.
- var start, end;
- [start, end] = this.getLayoutEnd(data.item);
+ var start = data.itemInfo.layoutStart;
+ var end = data.itemInfo.layoutEnd;
if (start.year != this.date.year ||
start.month != this.date.month ||
start.day != this.date.day) {
start = start.clone();
start.resetTo(this.date.year,
this.date.month,
this.date.day,
0,this.mStartMin,0,
@@ -1232,17 +1218,17 @@
var floatstart = start.clone();
floatstart.timezone = floating();
var dur = floatstart.subtractDate(prevEnd);
if (dur.inSeconds) {
col.push({duration: dur});
}
var floatend = end.clone();
floatend.timezone = floating();
- col.push({event: data.item,
+ col.push({event: data.itemInfo.event,
endDate: end,
duration: floatend.subtractDate(floatstart)});
}
layerOffset = layers.length;
}
return layers;
]]></body>
</method>
@@ -3144,17 +3130,17 @@
<parameter name="aVal"/>
<body><![CDATA[
var needsreorient = false;
var needsrelayout = false;
if (aAttr == "orient") {
if (this.getAttribute("orient") != aVal)
needsreorient = true;
}
-
+
if (aAttr == "context" || aAttr == "item-context")
needsrelayout = true;
// this should be done using lookupMethod(), see bug 286629
var ret = XULElement.prototype.setAttribute.call (this, aAttr, aVal);
if (needsrelayout && !needsreorient)
this.relayout();
@@ -3344,17 +3330,17 @@
var headerboxkids = headerdaybox.childNodes;
var labelboxkids = labeldaybox.childNodes;
for each (var d in computedDateList) {
var dayEventsBox;
if (counter < dayboxkids.length) {
dayEventsBox = dayboxkids[counter];
dayEventsBox.removeAttribute("relation");
- dayEventsBox.mEvents = new Array();
+ dayEventsBox.mEventInfos = new Array();
} else {
dayEventsBox = createXULElement("calendar-event-column");
dayEventsBox.setAttribute("flex", "1");
daybox.appendChild(dayEventsBox);
}
setUpDayEventsBox(dayEventsBox);
var dayHeaderBox;