0.6 8*60 20*60 this.relayout(); aEndMin) throw Components.results.NS_ERROR_INVALID_ARG; if (aEndMin < 0 || aEndMin > 24*60) throw Components.results.NS_ERROR_INVALID_ARG; if (this.mStartMin != aStartMin || this.mEndMin != aEndMin) { this.mStartMin = aStartMin; this.mEndMin = aEndMin; this.relayout(); } ]]> 0) { var dur; if (this.mEndMin - theMin < 60) { dur = this.mEndMin - theMin; } else { dur = theMin % 60; } theMin += dur; if (dur == 0) dur = 60; var box; if (dur != 60) { box = makeTimeBox("", dur * this.mPixPerMin); } else { timeString = formatter.FormatTime("", Components.interfaces.nsIScriptableDateFormat .timeFormatNoSeconds, theHour, 0, 0); box = makeTimeBox(timeString, dur * this.mPixPerMin); } box.setAttribute("class", "calendar-time-bar-box-" + (theHour % 2 == 0 ? "even" : "odd")); topbox.appendChild(box); durLeft -= dur; theMin += dur; theHour++; } ]]> null top false 0 0 var evbox = this.parentNode.parentNode; // still select it (since we'll stopPropagation()) evbox.calendarView.selectedItem = evbox.mOccurrence; // then start dragging it evbox.parentColumn.startSweepingToModifyEvent(evbox, evbox.mOccurrence, whichside, event.screenX, event.screenY); ]]> 0.6 8*60 20*60 new Array() null null null "UTC" null 0 null null aEndMin) throw Components.results.NS_ERROR_INVALID_ARG; if (aEndMin < 0 || aEndMin > 24*60) throw Components.results.NS_ERROR_INVALID_ARG; if (this.mStartMin != aStartMin || this.mEndMin != aEndMin) { this.mStartMin = aStartMin; this.mEndMin = aEndMin; this.relayout(); } ]]> 0) return; function createXULElement(el) { return document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", el); } this.clear(); var orient = this.getAttribute("orient"); var otherorient = "vertical"; if (!orient) orient = "horizontal"; if (orient == "vertical") otherorient = "horizontal"; // bgbox is used mainly for drawing the grid. at some point it may // also be used for all-day events. this.bgbox.setAttribute("orient", orient); var theMin = this.mStartMin; while (theMin < this.mEndMin) { var dur = theMin % 60; theMin += dur; if (dur == 0) dur = 60; var box = createXULElement("spacer"); // we key off this in a CSS selector box.setAttribute("orient", orient); box.setAttribute("class", "calendar-event-column-linebox"); if (orient == "vertical") box.setAttribute("height", dur * this.mPixPerMin); else box.setAttribute("width", dur * this.mPixPerMin); box.setAttribute("style", "min-width: 1px; min-height: 1px;"); this.bgbox.appendChild(box); theMin += 60; } // fgbox is used for dragging events this.fgboxes.box.setAttribute("orient", orient); document.getAnonymousElementByAttribute(this, "anonid", "fgdragspacer").setAttribute("orient", orient); // this one is set to otherorient, since it will contain // child boxes set to "orient" (one for each set of // overlapping event areas) this.topbox.setAttribute("orient", otherorient); this.mEventMap = this.computeEventMap(); for each (var column in this.mEventMap) { var xulColumn = createXULElement("box"); xulColumn.setAttribute("orient", orient); xulColumn.setAttribute("flex", "1"); xulColumn.setAttribute("style", "min-width: 1px; min-height: 1px;"); this.topbox.appendChild(xulColumn); var numBlocksInserted = 0 var curTime = 0; for each (var chunk in column) { var duration = chunk.duration; //dump ("curTime: " + curTime + " duration: " + duration + " ev: " + chunk.event + "\n"); // if this chunk isn't entirely visible, we skip it if (curTime < this.mStartMin) { if (curTime + duration <= this.mStartMin) { curTime += duration; continue; } // offset the duration so that stuff starts at // whatever our start time is set to, if this item // starts before our start time var delta = this.mStartMin - curTime; if (delta > 0) { duration -= delta; curTime += delta; } } if (chunk.event) { var chunkBox = createXULElement("calendar-event-box"); chunkBox.setAttribute("context", this.getAttribute("item-context") || this.getAttribute("context")); chunkBox.setAttribute("style", "min-width: 1px; min-height: 1px;"); chunkBox.setAttribute("orient", orient); if (orient == "vertical") chunkBox.setAttribute("height", duration * this.mPixPerMin); else chunkBox.setAttribute("width", duration * this.mPixPerMin); xulColumn.appendChild(chunkBox); chunkBox.calendarView = this.calendarView; chunkBox.occurrence = chunk.event.event; chunkBox.parentColumn = this; chunk.event.eventbox = chunkBox; } else { var chunkBox = createXULElement("spacer"); chunkBox.setAttribute("context", this.getAttribute("context")); chunkBox.setAttribute("style", "min-width: 1px; min-height: 1px;"); chunkBox.setAttribute("orient", orient); chunkBox.setAttribute("class", "calendar-empty-space-box"); xulColumn.appendChild(chunkBox); if (orient == "vertical") chunkBox.setAttribute("height", duration * this.mPixPerMin); else chunkBox.setAttribute("width", duration * this.mPixPerMin); } numBlocksInserted++; curTime += duration; } if (numBlocksInserted == 0) { // if we didn't insert any blocks, then // forget about this column this.topbox.removeChild(xulColumn); } } ]]> startAt) { // We want to insert the event here. prevblock contains the // preceeding block, if any. block contains the block that already // exists at this location, e.g.: // .....v- startAt // ~~----------+----------~~ // prevblock | block // ~~----------+----------~~ // ^- curOffset // // The event we're trying to insert starts at startAt, // which can be anywhere from curOffset - prevblock.duration to // curOffset + block.duration. // // We need to look at block; if it's an event, then we evict ourselves // to the next eventMap index. We also do this if it's free space // and we can't fit ourselves here. // If the previous block is an event, and we // need to start in the middle of it, we push // to the next column. if (prevblock && prevblock.event && startAt < curOffset) { //dump ("** break 1\n"); break; } // If the next block is an event, we push to the // next column, since we can't break it. if (block.event) { //dump ("** break 2\n"); break; } // If the next block is free space, but it isn't // large enough to hold our event, we push to the // next column. if (curOffset + block.duration < endAt) { //dump ("** break 3\n"); break; } // Otherwise, we are ready to insert the event. // Figure out how much to shrink the previous/following // blocks. var startDelta = startAt - curOffset; if (startDelta < 0 || (prevblock && !prevblock.event)) { // we need to shrink or expand the previous free space eventMap[curCol][blockIndex-1].duration += startDelta; curOffset += startDelta; } else if (startDelta > 0) { eventMap[curCol].splice(blockIndex, 0, { duration: startDelta }); curOffset += startDelta; blockIndex++; } var endDelta = endAt - curOffset; if (endDelta > 0) { eventMap[curCol][blockIndex].duration -= startDelta; } // insert our event block eventMap[curCol].splice(blockIndex, 0, { duration: endAt - startAt, event: event }); finished = true; break; } prevblock = block; curOffset += block.duration; blockIndex++; } // we got to the end of the list, so just add to the end if (blockIndex == eventMap[curCol].length && curOffset <= startAt) { var delta = startAt - curOffset; if (delta) eventMap[curCol].push({ duration: delta }); eventMap[curCol].push({ duration: endAt - startAt, event: event }); finished = true; } if (finished) { //dump (eventMap.toSource() + "\n"); break; } if (curCol+1 == eventMap.length) { eventMap.push(new Array()); } curCol++; } } return eventMap; ]]> >> drag is: " + this.mDragState.dragType + "\n"); window.addEventListener("mousemove", this.onEventSweepMouseMove, false); window.addEventListener("mouseup", this.onEventSweepMouseUp, false); ]]> null null null null 9) { if (this.parentColumn) { if (this.editingTimer) { clearTimeout(this.editingTimer); this.editingTimer = null; } this.calendarView.selectedItem = this.mOccurrence; this.mEditing = false; if (this.calendarView) this.calendarView.activeInPlaceEdit = false; this.parentColumn.startSweepingToModifyEvent(this, this.mOccurrence, "middle", this.mMouseX, this.mMouseY); this.mInMouseDown = false; } } ]]> null 0 size) { self.pixelsPerMinute = 0.01; self.mLastSize = size; if (self.orient == "horizontal") size = daybox.boxObject.width; else size = daybox.boxObject.height; } self.mLastSize = size; //self.removeAttribute("hidden"); var minutes = self.mEndMin - self.mStartMin; var ppm = size / minutes; ppm = Math.round(ppm * 10) / 10; if (ppm < self.mMinPPM) { ppm = self.mMinPPM; } self.pixelsPerMinute = ppm; ]]> null null null null null null 0 0.6 0.4 null null 8*60 20*60 8*60 20*60 true [0,6] "UTC" 0) return this.mDateList[0]; else return null; ]]> 0) return this.mDateList[this.mDateList.length-1]; else return null; ]]> = 0) return; } else if (this.mDateList) { for each (var d in this.mDateList) { // if date is already visible, nothing to do if (d.compare(targetDate) == 0) return; } } // if we're only showing one date, then continue // to only show one date; otherwise, show the week. if (this.numVisibleDates == 1) { this.setDateRange(aDate, aDate); } else { this.setDateRange(aDate.startOfWeek, aDate.endOfWeek); } this.selectedDay = targetDate; ]]> 0) { var start = val.startDate || val.entryDate; for each (col in cols) { if(start.isDate) { col.header.selectOccurrence(val); } else { col.column.selectOccurrence(val); } } if(this.mController.selectionManager) this.mController.selectionManager.replaceSelection(val); } else { val = null; } } this.mSelectedItem = val; } return val; ]]> return this.mPixPerMin this.setPixelsPerMin(val); return val; return (this.getAttribute("orient") || "vertical"); this.setAttribute("orient", val); return val; aEndMin) throw Components.results.NS_ERROR_INVALID_ARG; if (aEndMin < 0 || aEndMin > 24*60) throw Components.results.NS_ERROR_INVALID_ARG; if (this.mDefaultStartMin != aStartMin || this.mDefaultEndMin != aEndMin || this.mStartMin != aStartMin || this.mEndMin != aEndMin) { this.mDefaultStartMin = aStartMin; this.mDefaultEndMin = aEndMin; this.mStartMin = aStartMin; this.mEndMin = aEndMin; this.refresh(); } ]]> = 0; i--) { dayHeaderBox.deleteEvent(dayHeaderBox.mItemBoxes[i].occurrence); } } else { dayHeaderBox = createXULElement("calendar-header-container"); dayHeaderBox.setAttribute("flex", "1"); headerdaybox.appendChild(dayHeaderBox); } setUpDayHeaderBox(dayHeaderBox); function matchesDayOff(dayOffNum) { return dayOffNum == d.weekday; } if (this.mDaysOffArray.some(matchesDayOff)) { dayEventsBox.setAttribute("weekend", "true"); dayHeaderBox.setAttribute("weekend", "true"); } else { dayEventsBox.removeAttribute("weekend"); dayHeaderBox.removeAttribute("weekend"); } // highlight today if (this.numVisibleDates > 1 && d.compare(today) == 0) { dayEventsBox.setAttribute("today", "true"); dayHeaderBox.setAttribute("today", "true"); } var labelbox; if (counter < labelboxkids.length) { labelbox = labelboxkids[counter]; labelbox.firstChild.setAttribute("value", (d.month + 1) + "/" + d.day); labelbox.childNodes[1].setAttribute("value", calGetString("dateFormat", "day."+ (d.weekday+1)+ ".Mmm")); } else { labelbox = createXULElement("box"); labelbox.setAttribute("flex", "1"); labelbox.setAttribute("class", "calendar-day-label-box"); var label = createXULElement("label"); label.setAttribute("value", (d.month + 1) + "/" + d.day); label.setAttribute("class", "calendar-day-label-date"); labelbox.appendChild(label); labeldaybox.appendChild(labelbox); label = createXULElement("label"); label.setAttribute("value", calGetString("dateFormat", "day."+ (d.weekday+1)+ ".Mmm")); label.setAttribute("class", "calendar-day-label-name"); labelbox.appendChild(label); labeldaybox.appendChild(labelbox); } labelbox.setAttribute("orient", orient); // We don't want to actually mess with our original dates, plus // they're likely to be immutable. var d2 = d.clone(); d2.isDate = true; d2.makeImmutable(); this.mDateColumns.push ( { date: d2, column: dayEventsBox, header: dayHeaderBox } ); counter++; } // Remove any extra columns that may have been hanging around function removeExtraKids(elem) { while (counter < elem.childNodes.length) { elem.removeChild(elem.childNodes[counter]); } } removeExtraKids(daybox); removeExtraKids(headerdaybox); removeExtraKids(labeldaybox); // fix pixels-per-minute this.onResize(); for each (col in this.mDateColumns) { col.column.endLayoutBatchChange(); } // adjust scrollbar spacers // XXX For performance reasons this method call can be moved to the // XXX constructor and the reorient method as soon as the views // XXX are constructed statically (24 hrs). this.adjustScrollBarSpacers(); ]]> = bo.screenX) && (aClientX < (bo.screenX + bo.width)) && (aClientY >= bo.screenY) && (aClientY < (bo.screenY + bo.height))) { return col.column; } } return null; ]]> latestChunkEndMin) { latestChunkEndMin = chunk.endMinute; } // break, if the start and end time match the day range if (earliestChunkStartMin <= DAY_START_MIN && latestChunkEndMin >= DAY_END_MIN) { break; } } // round down if (earliestChunkStartMin % MINS_PER_HOUR) { earliestChunkStartMin -= (earliestChunkStartMin % MINS_PER_HOUR); } // round up if (latestChunkEndMin % MINS_PER_HOUR) { latestChunkEndMin += MINS_PER_HOUR - (latestChunkEndMin % MINS_PER_HOUR); } // The only reason try/catch is necessary here is to work // around XBL lossage. Without it, control never makes it // through the try block, even though no exception is ever thrown! try { if (aIsAllChunks) { // Since we've looked at all the in-view chunks, // it's safe to either shrink or expand the time shown. // Shrinking might be necessary when switching // weeks, or if an event has been deleted, moved or // shrunk out of the "non-default" area. if (this.mStartMin != earliestChunkStartMin) { this.mStartMin = earliestChunkStartMin; hasChanged = true; } if (this.mEndMin != latestChunkEndMin) { this.mEndMin = latestChunkEndMin; hasChanged = true; } } else { // here we are doing incremental adjustment, so we // can only expand the time shown, never shrink it if (this.mStartMin > earliestChunkStartMin) { this.mStartMin = earliestChunkStartMin; hasChanged = true; } if (this.mEndMin < latestChunkEndMin) { this.mEndMin = latestChunkEndMin; hasChanged = true; } } } catch (e) { Components.utils.reportError("Unexpected exception in " + "readjustStartEndMinutes: " + e); throw e; } return hasChanged; ]]>