gecko-dev/calendar/resources/content/monthView.js
2003-06-17 17:17:44 +00:00

1118 lines
40 KiB
JavaScript

/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is OEone Calendar Code, released October 31st, 2001.
*
* The Initial Developer of the Original Code is
* OEone Corporation.
* Portions created by the Initial Developer are Copyright (C) 2001
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Garth Smedley <garths@oeone.com>
* Mike Potter <mikep@oeone.com>
* Karl Guertin <grayrest@grayrest.com>
* Colin Phillips <colinp@oeone.com>
* Eric Belhaire <belhaire@ief.u-psud.fr>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/*-----------------------------------------------------------------
* MonthView Class subclass of CalendarView
*
* Calendar month view class
*
* PROPERTIES
* selectedEventBox - Events are displayed in dynamically created event boxes
* this is the selected box, or null
*
* showingLastDay - When the user changes to a new month we select
* the same day in the new month that was selected in the original month. If the
* new month does not have that day ( i.e. 31 was selected and the new month has
* only 30 days ) we move the selection to the last day. When this happens we turn on
* the 'showingLastDay' flag. Now we will always select the last day when the month
* is changed so that if they go back to the original month, 31 is selected again.
* 'showingLastDay' is turned off when the user selects a new day or changes the view.
*
*
* dayNumberItemArray - An array [ 0 to 41 ] of text boxes that hold the day numbers in the month view.
* We set the value attribute to the day number.
* In the XUL they have id's of the form month-week-<row_number>-day-<column_number>
* where row_number is 1 - 6 and column_number is 1 - 7.
*
* dayBoxItemArray - An array [ 0 to 41 ] of boxes, one for each day in the month view. These boxes
* are selected when a day is selected. They contain a dayNumberItem and event boxes.
* In the XUL they have id's of the form month-week-<row_number>-day-<column_number>-box
* where row_number is 1 - 6 and column_number is 1 - 7.
*
* firstDateOfView - A date equal to the date of the first box of the View (the date of
* dayBoxItemArray[0])
*
* lastDateOfView - A date equal to the date of the last box of the View (the date of
* dayBoxItemArray[41])
*
*
* kungFooDeathGripOnEventBoxes - This is to keep the event box javascript objects around so when we get
* them back they still have the calendar event property on them.
*
*
* NOTES
*
* Events are displayed in dynamically created event boxes. these boxes have a property added to them
* called "calendarEvent" which contains the event represented by the box.
*
* There is one day box item for every day box in the month grid. These have an attribute
* called "empty" which is set to "true", like so:
*
* dayBoxItem.setAttribute( "empty" , "true" );
*
* when the day box is not in the month. This allows the display to be controlled from css.
*
* The day boxes also have a couple of properties added to them:
*
* dayBoxItem.dayNumber - null when day is not in month.
* - the date, 1 to 31, otherwise,
*
* dayBoxItem.numEvents - The number of events for the day, used to limit the number displayed
* since there is only room for 3.
*
* dayBoxItem.date - Date of the Box.
*
*/
var msPerDay = kDate_MillisecondsInDay ;
var msPerMin = kDate_MillisecondsInMinute ;
// Make MonthView inherit from CalendarView
MonthView.prototype = new CalendarView();
MonthView.prototype.constructor = MonthView;
/**
* MonthView Constructor.
*
* PARAMETERS
* calendarWindow - the owning instance of CalendarWindow.
*
*/
function MonthView( calendarWindow )
{
// call the super constructor
this.superConstructor( calendarWindow );
this.numberOfEventsToShow = false;
var monthViewEventSelectionObserver =
{
onSelectionChanged : function( EventSelectionArray )
{
dump( "\nIn Month view, on selection changed");
if( EventSelectionArray.length > 0 )
{
//if there are selected events.
//for some reason, this function causes the tree to go into a select / unselect loop
//putting it in a settimeout fixes this.
setTimeout( "gCalendarWindow.monthView.clearSelectedDate();", 1 );
gCalendarWindow.monthView.clearSelectedBoxes();
//dump( "\nIn Month view, eventSelectionArray.length is "+EventSelectionArray.length );
var i = 0;
for( i = 0; i < EventSelectionArray.length; i++ )
{
//dump( "\nin Month view, going to try and get the event boxes with name 'month-view-event-box-"+EventSelectionArray[i].id+"'" );
var EventBoxes = document.getElementsByAttribute( "name", "month-view-event-box-"+EventSelectionArray[i].id );
//dump( "\nIn Month view, found "+EventBoxes.length+" matches for the selected event." );
for ( j = 0; j < EventBoxes.length; j++ )
{
EventBoxes[j].setAttribute( "eventselected", "true" );
}
}
//dump( "\nAll Done in Selection for Month View" );
}
else
{
//select the proper day
gCalendarWindow.monthView.hiliteSelectedDate();
}
}
}
calendarWindow.EventSelection.addObserver( monthViewEventSelectionObserver );
this.showingLastDay = false;
// set up month day box's and day number text items, see notes above
this.dayNumberItemArray = new Array();
this.dayBoxItemArray = new Array();
this.weekNumberItemArray = new Array();
this.kungFooDeathGripOnEventBoxes = new Array();
this.firstDateOfView = new Date();
this.lastDateOfView = new Date();
var dayItemIndex = 0;
for( var weekIndex = 1; weekIndex <= 6; ++weekIndex )
{
var weekNumberItem = document.getElementById( "month-week-" + weekIndex + "-left" );
this.weekNumberItemArray[ weekIndex ] = weekNumberItem;
for( var dayIndex = 1; dayIndex <= 7; ++dayIndex )
{
// add the day text item to an array[0..41]
var dayNumberItem = document.getElementById( "month-week-" + weekIndex + "-day-" + dayIndex );
this.dayNumberItemArray[ dayItemIndex ] = dayNumberItem;
// add the day box to an array[0..41]
var dayBoxItem = document.getElementById( "month-week-" + weekIndex + "-day-" + dayIndex + "-box" );
this.dayBoxItemArray[ dayItemIndex ] = dayBoxItem;
// set on click of day boxes
dayBoxItem.setAttribute( "onclick", "gCalendarWindow.monthView.clickDay( event )" );
dayBoxItem.setAttribute( "oncontextmenu", "gCalendarWindow.monthView.contextClickDay( event )" );
//set the drop
dayBoxItem.setAttribute( "ondragdrop", "nsDragAndDrop.drop(event,monthViewEventDragAndDropObserver)" );
dayBoxItem.setAttribute( "ondragover", "nsDragAndDrop.dragOver(event,monthViewEventDragAndDropObserver)" );
//set the double click of day boxes
dayBoxItem.setAttribute( "ondblclick", "gCalendarWindow.monthView.doubleClickDay( event )" );
// array index
++dayItemIndex;
}
}
}
/** PUBLIC
*
* Redraw the events for the current month
*
* We create XUL boxes dynamically and insert them into the XUL.
* To refresh the display we remove all the old boxes and make new ones.
*/
MonthView.prototype.refreshEvents = function monthView_refreshEvents( )
{
// Set the numberOfEventsToShow
if( this.numberOfEventsToShow == false )
this.setNumberOfEventsToShow();
// get this month's events and display them
var monthEventList = gEventSource.getEventsDisplayForRange( this.firstDateOfView,this.lastDateOfView );
// remove old event boxes
var eventBoxList = document.getElementsByAttribute( "eventbox", "monthview" );
var eventBox = null;
for( var eventBoxIndex = 0; eventBoxIndex < eventBoxList.length; ++eventBoxIndex )
{
eventBox = eventBoxList[ eventBoxIndex ];
eventBox.parentNode.removeChild( eventBox );
}
// clear calendarEvent counts. This controls how many events are shown full, and then the rest are shown as dots.
// count them by adding a property numEvents to the dayItem, which is zeroed here
for( var dayItemIndex = 0; dayItemIndex < this.dayBoxItemArray.length; ++dayItemIndex )
{
var dayItem = this.dayBoxItemArray[ dayItemIndex ];
dayItem.numEvents = 0;
}
this.kungFooDeathGripOnEventBoxes = new Array();
//instead of making a bunch of new date objects, make one here and modify in the for loop
var DisplayDate = new Date( );
var eventDayInView;
var dayBoxItem;
var calendarEventDisplay;
var calIndex;
var calNumber;
// add each calendarEvent
for( var eventIndex = 0; eventIndex < monthEventList.length; ++eventIndex )
{
calendarEventDisplay = monthEventList[ eventIndex ];
// get the day box for the calendarEvent's day
DisplayDate.setTime( calendarEventDisplay.displayDate );
eventDayInView = this.indexOfDate(DisplayDate);
dayBoxItem = this.dayBoxItemArray[ eventDayInView ];
if( !dayBoxItem )
break;
// Display no more than three, show dots for the events > this.numberOfEventsToShow
dayBoxItem.numEvents += 1;
if( dayBoxItem.numEvents <= this.numberOfEventsToShow )
{
// Make a box item to hold the event
eventBox = document.createElement( "box" );
eventBox.setAttribute( "id", "month-view-event-box-"+calendarEventDisplay.event.id );
eventBox.setAttribute( "name", "month-view-event-box-"+calendarEventDisplay.event.id );
eventBox.setAttribute( "event"+calendarEventDisplay.event.id, true );
// start calendar color change by CofC
var containerName = gCalendarWindow.calendarManager.getCalendarByName(
calendarEventDisplay.event.parent.server ).subject.split(":")[2];
// set the event box to be of class week-view-event-class and the appropriate calendar-color class
eventBox.setAttribute("class", "month-day-event-box-class " + containerName );
// end calendar color change by CofC
if( calendarEventDisplay.event.categories && calendarEventDisplay.event.categories != "" )
{
eventBox.setAttribute( calendarEventDisplay.event.categories, "true" );
}
eventBox.setAttribute( "eventbox", "monthview" );
eventBox.setAttribute( "onclick", "monthEventBoxClickEvent( this, event )" );
eventBox.setAttribute( "ondblclick", "monthEventBoxDoubleClickEvent( this, event )" );
eventBox.setAttribute( "onmouseover", "gCalendarWindow.changeMouseOverInfo( calendarEventDisplay, event )" );
eventBox.setAttribute( "tooltip", "eventTooltip" );
eventBox.setAttribute( "ondraggesture", "nsDragAndDrop.startDrag(event,monthViewEventDragAndDropObserver);" );
// add a property to the event box that holds the calendarEvent that the
// box represents
eventBox.calendarEventDisplay = calendarEventDisplay;
this.kungFooDeathGripOnEventBoxes.push( eventBox );
// Make a text item to show the event title
var eventBoxText = document.createElement( "label" );
eventBoxText.setAttribute( "crop", "end" );
eventBoxText.setAttribute( "class", "month-day-event-text-class" );
if ( calendarEventDisplay.event.allDay == true )
{
eventBoxText.setAttribute( "value", calendarEventDisplay.event.title );
// Create an image
newImage = document.createElement("image");
newImage.setAttribute( "class", "all-day-event-class" );
eventBox.appendChild( newImage );
}
else
{
// To format the starting time of the event
var eventStartTime = new Date( calendarEventDisplay.event.start.getTime() ) ;
var StartFormattedTime = this.calendarWindow.dateFormater.getFormatedTime( eventStartTime );
// display as "12:15 titleevent"
eventBoxText.setAttribute( "value", StartFormattedTime+' '+calendarEventDisplay.event.title);
}
//you need this flex in order for text to crop
eventBoxText.setAttribute( "flex", "1" );
eventBoxText.setAttribute( "ondraggesture", "nsDragAndDrop.startDrag(event,monthViewEventDragAndDropObserver);" );
// add the text to the event box and the event box to the day box
eventBox.appendChild( eventBoxText );
dayBoxItem.appendChild( eventBox );
}
else
{
//if there is not a box to hold the little dots for this day...
if ( !document.getElementById( "dotboxholder"+eventDayInView ) )
{
//make one
dotBoxHolder = document.createElement( "hbox" );
dotBoxHolder.setAttribute( "id", "dotboxholder"+eventDayInView );
dotBoxHolder.setAttribute( "eventbox", "monthview" );
//add the box to the day.
dayBoxItem.appendChild( dotBoxHolder );
}
else
{
//otherwise, get the box
dotBoxHolder = document.getElementById( "dotboxholder"+eventDayInView );
}
if( dotBoxHolder.childNodes.length < kMAX_NUMBER_OF_DOTS_IN_MONTH_VIEW )
{
eventDotBox = document.createElement( "box" );
eventDotBox.setAttribute( "eventbox", "monthview" );
//show a dot representing an event.
//NOTE: This variable is named eventBox because it needs the same name as
// the regular boxes, for the next part of the function!
eventBox = document.createElement( "image" );
eventBox.setAttribute( "class", "month-view-event-dot-class" );
eventBox.setAttribute( "id", "month-view-event-box-"+calendarEventDisplay.event.id );
eventBox.setAttribute( "name", "month-view-event-box-"+calendarEventDisplay.event.id );
eventBox.calendarEventDisplay = calendarEventDisplay;
eventBox.setAttribute( "onmouseover", "gCalendarWindow.changeMouseOverInfo( calendarEventDisplay, event )" );
eventBox.setAttribute( "onclick", "monthEventBoxClickEvent( this, event )" );
eventBox.setAttribute( "ondblclick", "monthEventBoxDoubleClickEvent( this, event )" );
eventBox.setAttribute( "tooltip", "eventTooltip" );
this.kungFooDeathGripOnEventBoxes.push( eventBox );
//add the dot to the extra box.
eventDotBox.appendChild( eventBox );
dotBoxHolder.appendChild( eventDotBox );
}
}
// mark the box as selected, if the event is
if( this.calendarWindow.EventSelection.isSelectedEvent( calendarEventDisplay.event ) )
{
this.selectBoxForEvent( calendarEventDisplay.event );
}
}
}
/** PUBLIC
*
* Called when the user switches to a different view
*/
MonthView.prototype.switchFrom = function monthView_switchFrom( )
{
document.getElementById( "only-workday-checkbox-1" ).setAttribute( "disabled", "true" );
document.getElementById( "only-workday-checkbox-2" ).setAttribute( "disabled", "true" );
}
/** PUBLIC
*
* Called when the user switches to the month view
*/
MonthView.prototype.switchTo = function monthView_switchTo( )
{
// see showingLastDay notes above
this.showingLastDay = false;
// disable/enable view switching buttons
var weekViewButton = document.getElementById( "week_view_command" );
var monthViewButton = document.getElementById( "month_view_command" );
var dayViewButton = document.getElementById( "day_view_command" );
monthViewButton.setAttribute( "disabled", "true" );
weekViewButton.removeAttribute( "disabled" );
dayViewButton.removeAttribute( "disabled" );
//Enable menu options
document.getElementById( "only-workday-checkbox-1" ).removeAttribute( "disabled" );
document.getElementById( "only-workday-checkbox-2" ).removeAttribute( "disabled" );
// switch views in the deck
var calendarDeckItem = document.getElementById( "calendar-deck" );
calendarDeckItem.selectedIndex = 0;
}
/** PUBLIC
*
* Redraw the display, but not the events
*/
MonthView.prototype.refreshDisplay = function monthView_refreshDisplay( )
{
// set the month/year in the header
var selectedDate = this.calendarWindow.getSelectedDate();
var newMonth = selectedDate.getMonth();
var newYear = selectedDate.getFullYear();
var titleMonthArray = new Array();
var titleYearArray = new Array();
var toDebug = "";
for (var i=-2; i < 3; i++){
titleMonthArray[i] = newMonth + i;
titleMonthArray[i] = (titleMonthArray[i] >= 0)? titleMonthArray[i] % 12 : titleMonthArray[i] + 12;
titleMonthArray[i] = this.calendarWindow.dateFormater.getMonthName( titleMonthArray[i] );
var idName = i + "-month-title";
document.getElementById( idName ).setAttribute( "value" , titleMonthArray[i] );
}
document.getElementById( "0-month-title" ).setAttribute( "value" , titleMonthArray[0] + " " + newYear );
var categoriesStringBundle = srGetStrBundle("chrome://calendar/locale/calendar.properties");
var defaultWeekStart = categoriesStringBundle.GetStringFromName("defaultWeekStart" );
var Offset = getIntPref(this.calendarWindow.calendarPreferences.calendarPref, "week.start", defaultWeekStart );
var NewArrayOfDayNames = new Array();
for( i = 0; i < ArrayOfDayNames.length; i++ )
{
NewArrayOfDayNames[i] = ArrayOfDayNames[i];
}
for( i = 0; i < Offset; i++ )
{
var FirstElement = NewArrayOfDayNames.shift();
NewArrayOfDayNames.push( FirstElement );
}
//set the day names
for( i = 1; i <= 7; i++ )
{
document.getElementById( "month-view-header-day-"+i ).value = NewArrayOfDayNames[ (i-1) ];
document.getElementById( "month-view-column-"+i ).removeAttribute( "collapsed" );
}
// Write in all the day numbers
// figure out first and last days of the month, first and last date of view
var firstDate = new Date( newYear, newMonth, 1 );
var firstDayOfWeek = firstDate.getDay() - Offset;
if( firstDayOfWeek < 0 )
firstDayOfWeek+=7;
this.firstDayOfWeek = firstDayOfWeek;
var lastDayOfMonth = DateUtils.getLastDayOfMonth( newYear, newMonth );
this.firstDateOfView = new Date( newYear, newMonth, 1 - firstDayOfWeek, 0, 0, 0 );
this.lastDateOfView = new Date( newYear, newMonth, 42 - firstDayOfWeek, 23, 59, 59 );
var Checked = gOnlyWorkdayChecked ;
for( var i = - Offset; i <= 1 - Offset; i++ ){
//ni = i - Offset ;
var ni = (i >0)? i : i + 7;
if( Checked === "true" )
document.getElementById( "month-view-column-"+ni ).setAttribute( "collapsed", "true" );
else
document.getElementById( "month-view-column-"+ ni).removeAttribute( "collapsed");
}
if( Checked === "true" && Offset <= 1 && firstDayOfWeek >= 6-Offset) {
document.getElementById( "month-week-1-row" ).setAttribute( "collapsed", "true" );
}
else
{
document.getElementById( "month-week-1-row" ).removeAttribute( "collapsed" );
}
if(this.dayNumberItemArray.length-firstDayOfWeek-lastDayOfMonth >= 7)
{
document.getElementById( "month-week-6-row" ).setAttribute( "collapsed", "true" );
}
else
{
document.getElementById( "month-week-6-row" ).removeAttribute( "collapsed" );
}
// To Set Week Number
var weekNumberItem;
var weekNumber ;
var mondayDate ;
var newoffset = (Offset >= 5) ? 8 -Offset : 1 - Offset ;
for( var weekIndex = 0; weekIndex < 6; ++weekIndex )
{
weekNumberItem = this.weekNumberItemArray[ weekIndex+1 ] ;
mondayDate = new Date( this.firstDateOfView.getFullYear(),
this.firstDateOfView.getMonth(),
this.firstDateOfView.getDate()+newoffset+7*weekIndex );
weekNumber=DateUtils.getWeekNumber(mondayDate);
weekNumberItem.setAttribute( "value" , weekNumber );
}
// loop through all the day boxes
var dayNumber = 1;
for( var dayIndex = 0; dayIndex < this.dayNumberItemArray.length; ++dayIndex )
{
var dayNumberItem = this.dayNumberItemArray[ dayIndex ];
var dayBoxItem = this.dayBoxItemArray[ dayIndex ];
var thisDate = new Date( newYear, newMonth, 1-(firstDayOfWeek - dayIndex ) );
dayBoxItem.date = thisDate;
dayNumberItem.setAttribute( "value" , thisDate.getDate() );
if( dayIndex < firstDayOfWeek || dayNumber > lastDayOfMonth )
{
// this day box is NOT in the month,
dayBoxItem.dayNumber = null;
dayBoxItem.setAttribute( "empty" , "true" );
dayBoxItem.removeAttribute( "weekend" );
}
else
{
dayBoxItem.removeAttribute( "empty" );
if( thisDate.getDay() == 0 | thisDate.getDay() == 6 )
{
dayBoxItem.setAttribute( "weekend", "true" );
}
else
dayBoxItem.removeAttribute( "weekend" );
dayBoxItem.dayNumber = dayNumber;
++dayNumber;
}
}
// if we aren't showing an event, highlite the selected date.
if ( this.calendarWindow.EventSelection.selectedEvents.length < 1 )
{
this.hiliteSelectedDate( );
}
//always highlight today's date.
this.hiliteTodaysDate( );
}
/** PRIVATE
*
* Return the Index in the view of the given Date
*/
MonthView.prototype.indexOfDate = function monthView_indexOfDate(TheDate )
{
var msOffset = ( this.firstDateOfView.getTimezoneOffset() - TheDate.getTimezoneOffset() ) * msPerMin;
var IndexInView = Math.floor( ((TheDate.getTime()+msOffset) - this.firstDateOfView.getTime() ) / msPerDay ) ;
return(IndexInView);
}
/** PRIVATE
*
* Mark the selected date, also unmark the old selection if there was one
*/
MonthView.prototype.hiliteSelectedDate = function monthView_hiliteSelectedDate( )
{
// Clear the old selection if there was one
this.clearSelectedDate();
this.clearSelectedBoxes();
// Set the background for selection
var IndexInView = this.indexOfDate(this.calendarWindow.getSelectedDate());
var ThisBox = this.dayBoxItemArray[ IndexInView ];
if( ThisBox )
ThisBox.setAttribute( "monthselected" , "true" );
}
/** PUBLIC
*
* Unmark the selected date if there is one.
*/
MonthView.prototype.clearSelectedDate = function monthView_clearSelectedDate( )
{
var SelectedBoxes = document.getElementsByAttribute( "monthselected", "true" );
for( var i = 0; i < SelectedBoxes.length; i++ )
{
SelectedBoxes[i].removeAttribute( "monthselected" );
}
}
/** PUBLIC
*
* Unmark the selected date if there is one.
*/
MonthView.prototype.clearSelectedBoxes = function monthView_clearSelectedBoxes( )
{
var SelectedBoxes = document.getElementsByAttribute( "eventselected", "true" );
for( var i = 0; i < SelectedBoxes.length; i++ )
{
SelectedBoxes[i].removeAttribute( "eventselected" );
}
}
/** PRIVATE
*
* Mark today as selected, also unmark the old today if there was one.
*/
MonthView.prototype.hiliteTodaysDate = function monthView_hiliteTodaysDate( )
{
// Clear the old selection if there was one
var TodayBox = document.getElementsByAttribute( "today", "true" );
for( var i = 0; i < TodayBox.length; i++ )
{
TodayBox[i].removeAttribute( "today" );
}
//highlight today.
var Today = new Date( );
var todayInView = this.indexOfDate(Today) ;
if ( todayInView >= 0 && todayInView < 42 )
{
var ThisBox = this.dayBoxItemArray[ todayInView ];
if( ThisBox )
ThisBox.setAttribute( "today", "true" );
}
}
/** PUBLIC
*
* This is called when we are about the make a new event
* and we want to know what the default start date should be for the event.
*/
MonthView.prototype.getNewEventDate = function monthView_getNewEventDate( )
{
// use the selected year, month and day
// and the current hours and minutes
var now = new Date();
var start = new Date( this.calendarWindow.getSelectedDate() );
start.setHours( now.getHours() );
start.setMinutes( Math.ceil( now.getMinutes() / 5 ) * 5 );
start.setSeconds( 0 );
return start;
}
/** PUBLIC
*
* Moves goMonths months in the future, goes to next month if no argument.
*/
MonthView.prototype.goToNext = function monthView_goToNext( goMonths )
{
var nextMonth;
if(goMonths){
nextMonth = new Date( this.calendarWindow.selectedDate.getFullYear(), this.calendarWindow.selectedDate.getMonth() + goMonths, 1 );
this.adjustNewMonth( nextMonth );
this.goToDay( nextMonth );
}else{
nextMonth = new Date( this.calendarWindow.selectedDate.getFullYear(), this.calendarWindow.selectedDate.getMonth() + 1, 1 );
this.adjustNewMonth( nextMonth );
this.goToDay( nextMonth );
}
}
/** PUBLIC
*
* Goes goMonths months into the past, goes to the previous month if no argument.
*/
MonthView.prototype.goToPrevious = function monthView_goToPrevious( goMonths )
{
var prevMonth;
if(goMonths){
prevMonth = new Date( this.calendarWindow.selectedDate.getFullYear(), this.calendarWindow.selectedDate.getMonth() - goMonths, 1 );
this.adjustNewMonth( prevMonth );
this.goToDay( prevMonth );
}else{
prevMonth = new Date( this.calendarWindow.selectedDate.getFullYear(), this.calendarWindow.selectedDate.getMonth() - 1, 1 );
this.adjustNewMonth( prevMonth );
this.goToDay( prevMonth );
}
}
/** PRIVATE
*
* Helper function for goToNext and goToPrevious
*
* When the user changes to a new month the new month may not have the selected day in it.
* ( i.e. 31 was selected and the new month has only 30 days ).
* In that case our addition, or subtraction, in goToNext or goToPrevious will cause the
* date to jump a month. ( Say the date starts at May 31, we add 1 to the month, Now the
* date would be June 31, but the Date object knows there is no June 31, so it sets itself
* to July 1. )
*
* In goToNext or goToPrevious we set the date to be 1, so the month will be correct. Here
* we set the date to be the selected date, making adjustments if the selected date is not in the month.
*/
MonthView.prototype.adjustNewMonth = function monthView_adjustNewMonth( newMonth )
{
// Don't let a date beyond the end of the month make us jump
// too many or too few months
var lastDayOfMonth = DateUtils.getLastDayOfMonth( newMonth.getFullYear(), newMonth.getMonth() );
if( this.calendarWindow.selectedDate.getDate() > lastDayOfMonth )
{
// The selected date is NOT in the month
// set it to the last day of the month and turn on showingLastDay, see notes in MonthView class
newMonth.setDate( lastDayOfMonth )
this.showingLastDay = true;
}
else if( this.showingLastDay )
{
// showingLastDay is on so select the last day of the month, see notes in MonthView class
newMonth.setDate( lastDayOfMonth )
}
else
{
// date is NOT beyond the last.
newMonth.setDate( this.calendarWindow.selectedDate.getDate() )
}
}
/** PUBLIC -- monthview only
*
* Called when a day box item is single clicked
*/
MonthView.prototype.clickDay = function monthView_clickDay( event )
{
if( event.button > 0 )
return;
var dayBoxItem = event.currentTarget;
if( dayBoxItem.dayNumber != null && event.detail == 1 )
{
// turn off showingLastDay - see notes in MonthView class
this.showingLastDay = false;
// change the selected date and redraw it
this.calendarWindow.setSelectedDate( dayBoxItem.date );
//changing the selection will redraw the day as selected (colored blue) in the month view.
//therefor, this has to happen after setSelectedDate
gCalendarWindow.EventSelection.emptySelection();
}
}
/** PUBLIC -- monthview only
*
* Called when a day box item is single clicked
*/
MonthView.prototype.contextClickDay = function monthView_contextClickDay( event )
{
if( event.currentTarget.dayNumber != null )
{
// turn off showingLastDay - see notes in MonthView class
this.showingLastDay = false;
// change the selected date and redraw it
gNewDateVariable = gCalendarWindow.getSelectedDate();
gNewDateVariable.setDate( event.currentTarget.dayNumber );
}
}
/*
** Don't forget that clickDay gets called before double click day gets called
*/
MonthView.prototype.doubleClickDay = function monthView_doubleClickDay( event )
{
if( event.button > 0 )
return;
if ( event.currentTarget.dayNumber != null )
{
// change the selected date and redraw it
newEvent( this.getNewEventDate(), false );
}
else
{
newEvent( event.currentTarget.date, false );
}
}
MonthView.prototype.clearSelectedEvent = function monthView_clearSelectedEvent( )
{
var ArrayOfBoxes = document.getElementsByAttribute( "eventselected", "true" );
for( i = 0; i < ArrayOfBoxes.length; i++ )
{
ArrayOfBoxes[i].removeAttribute( "eventselected" );
}
}
MonthView.prototype.getVisibleEvent = function monthView_getVisibleEvent( calendarEvent )
{
var eventBox = document.getElementById( "month-view-event-box-"+calendarEvent.id );
if ( eventBox )
{
return eventBox;
}
else
return false;
}
MonthView.prototype.selectBoxForEvent = function monthView_selectBoxForEvent( calendarEvent )
{
var EventBoxes = document.getElementsByAttribute( "name", "month-view-event-box-"+calendarEvent.id );
for ( j = 0; j < EventBoxes.length; j++ )
{
EventBoxes[j].setAttribute( "eventselected", "true" );
}
}
/*Just calls setCalendarSize, it's here so it can be implemented on the other two views without difficulty.*/
MonthView.prototype.doResize = function monthView_doResize( )
{
this.setCalendarSize(this.getViewHeight());
this.setNumberOfEventsToShow();
}
/*Takes in a height, sets the calendar's container box to that height, the grid expands and contracts to fit it.*/
MonthView.prototype.setCalendarSize = function monthView_setCalendarSize( height )
{
var offset = document.defaultView.getComputedStyle(document.getElementById("month-controls-box"), "").getPropertyValue("height");
offset = parseInt( offset );
height = (height-offset)+"px";
document.getElementById( "month-content-box" ).setAttribute( "height", height );
}
/*returns the height of the current view in pixels*/
MonthView.prototype.getViewHeight = function monthView_getViewHeight( )
{
var toReturn = document.defaultView.getComputedStyle(document.getElementById("month-view-box"), "").getPropertyValue("height");
toReturn = parseInt( toReturn ); //strip off the px at the end
return toReturn;
}
MonthView.prototype.setNumberOfEventsToShow = function monthView_setNumberOfEventsToShow( )
{
this.setFictitiousEvents() ;
//get the style height of the month view box.
var MonthViewBoxHeight = document.defaultView.getComputedStyle(this.dayBoxItemArray[24],"").getPropertyValue("height");
MonthViewBoxHeight = parseFloat( MonthViewBoxHeight ); //strip off the px at the end
//get the style height of the label of the month view box.
var MonthViewLabelHeight = document.defaultView.getComputedStyle(document.getElementById("month-week-4-day-4"), "").getPropertyValue("height");
MonthViewLabelHeight = parseFloat( MonthViewLabelHeight ); //strip off the px at the end
//get the height of an event box.
var eventBox = document.getElementById( "month-view-event-box-fictitious" );
//get the height of the event dot box holder.
var dotBox = document.getElementById( "dotboxholder-fictitious" );
if( !dotBox || !eventBox)
return;
var EventBoxHeight = document.defaultView.getComputedStyle( eventBox, "" ).getPropertyValue( "height" );
EventBoxHeight = parseFloat( EventBoxHeight ); //strip off the px at the end
// BUG ? : the following computation doesnot return the height of dotBoxHolder has expected
// Could someone has a good idea why ?
// To overcome, I put a value of 11px for the Height
// I had also a margin of 3px
var EventDotBoxHeight = document.defaultView.getComputedStyle( dotBox, "" ).getPropertyValue( "height" );
EventDotBoxHeight = parseFloat( EventDotBoxHeight ); //strip off the px at the end
//calculate the number of events to show.
var numberOfEventsToShow = parseInt( ( MonthViewBoxHeight - MonthViewLabelHeight - 14) / EventBoxHeight )
// dump( "\nNactual"+( MonthViewBoxHeight - MonthViewLabelHeight ) / EventBoxHeight );
// dump( "\nM MonthViewBoxHeight: "+MonthViewBoxHeight );
// dump( "\nM MonthViewLabelHeight: "+MonthViewLabelHeight );
// dump( "\nM EventBoxHeight"+EventBoxHeight );
// dump( "\nM EventDotBoxHeight"+ EventDotBoxHeight );
// dump( "\nNnew : "+ numberOfEventsToShow) ;
this.numberOfEventsToShow = numberOfEventsToShow ;
// remove created event boxes
var Element = document.getElementById( "month-view-event-box-fictitious-dot") ;
Element.parentNode.removeChild(Element);
eventBox.parentNode.removeChild( eventBox );
dotBox.parentNode.removeChild( dotBox );
}
/* Draw a event and a dotboxholder for evaluation of the sizes */
MonthView.prototype.setFictitiousEvents = function monthView_setFictitiousEvents( )
{
var dayBoxItem = this.dayBoxItemArray[ 24 ];
if( !dayBoxItem )
return false;
// Make a box item to hold the event
var eventBox = document.createElement( "box" );
eventBox.setAttribute( "id", "month-view-event-box-fictitious" );
eventBox.setAttribute( "class", "month-day-event-box-class" );
eventBox.setAttribute( "eventbox", "monthview" );
// Make a text item to show the event title
var eventBoxText = document.createElement( "label" );
eventBoxText.setAttribute( "crop", "end" );
eventBoxText.setAttribute( "class", "month-day-event-text-class" );
// To format the starting time of the event display as "12:15 titleevent"
eventBoxText.setAttribute( "value", "12:15 fictitious event");
//you need this flex in order for text to crop
eventBoxText.setAttribute( "flex", "1" );
// add the text to the event box and the event box to the day box
eventBox.appendChild( eventBoxText );
dayBoxItem.appendChild( eventBox );
//make one dot box holder
var dotBoxHolder = document.createElement( "hbox" );
dotBoxHolder.setAttribute( "id", "dotboxholder-fictitious" );
dotBoxHolder.setAttribute( "dotboxholder", "monthview" );
//add the box to the day.
dayBoxItem.appendChild( dotBoxHolder );
//make the dot box
var eventDotBox = document.createElement( "box" );
eventDotBox.setAttribute( "eventdotbox", "monthview" );
eventBox = document.createElement( "image" );
eventBox.setAttribute( "class", "month-view-event-dot-class" );
eventBox.setAttribute( "id", "month-view-event-box-fictitious-dot" );
eventDotBox.appendChild( eventBox );
dotBoxHolder.appendChild( eventDotBox );
}
/*
drag and drop stuff
*/
var gEventBeingDragged = false;
var gBoxBeingDroppedOn = false;
var monthViewEventDragAndDropObserver = {
onDragStart: function (evt, transferData, action){
if( evt.target.calendarEventDisplay )
gEventBeingDragged = evt.target.calendarEventDisplay.event;
else {
if( evt.target.parentNode.calendarEventDisplay )
gEventBeingDragged = evt.target.parentNode.calendarEventDisplay.event;
else if(evt.target.calendarToDo || evt.target.parentNode.calendarToDo) {
dump("\n ToDo Drag not supported yet");
gEventBeingDragged = null ;
return;
}
}
//dump( "\nEvent being dragged is "+gEventBeingDragged );
transferData.data=new TransferData();
transferData.data.addDataForFlavour("text/unicode",0);
},
getSupportedFlavours : function () {
var weekflavours = new FlavourSet();
weekflavours.appendFlavour("text/unicode");
return weekflavours;
},
onDragOver: function (evt,flavour,session){
//dump( "on dragged over "+evt.target.getAttribute( "id" )+"\n" );
gBoxBeingDroppedOn = document.getElementById( evt.target.getAttribute( "id" ) );
//dump( evt.target.getAttribute( "id" ) );
},
onDrop: function (evt,dropdata,session){
//get the date of the current event box.
//dump( "\n\nDROP EVNET->\n"+gEventBeingDragged.start );
if( gBoxBeingDroppedOn.date == null )
return;
var newDay = new Date(gBoxBeingDroppedOn.date) ;
var oldStartDate = new Date( gEventBeingDragged.start.getTime() );
var oldEndDate = new Date( gEventBeingDragged.end.getTime() );
var newStartDate = new Date( oldStartDate.getTime() ) ;
newStartDate.setFullYear( newDay.getFullYear());
//call setMonth() twice necessary, because of a bug ? observed in Mozilla 1.2.1. :
// - the bug consequence is that an event drag from month 0 (Jan.) to month 1 (Feb)
// is set by a single call to month 2 (Mar).
newStartDate.setMonth( newDay.getMonth() );
newStartDate.setMonth( newDay.getMonth() );
newStartDate.setDate( newDay.getDate());
var Difference = newStartDate.getTime() - oldStartDate.getTime();
var newEndDate = oldEndDate.getTime() + Difference;
//shift the days from their old days to their new days.
//Coupled with the shift below : Does this work ?
if( Difference < 0 )
Difference += 7;
//edit the event being dragged to change its start and end date
//don't change the start and end time though.
if( evt.ctrlKey == true )
{
var eventToCopy = gEventBeingDragged.clone();
eventToCopy.id = null; //set the id to null so that it generates a new one
eventToCopy.start.setTime( newStartDate.getTime() );
eventToCopy.end.setTime( newEndDate );
if( eventToCopy.recurWeekdays > 0 )
{
eventToCopy.recurWeekdays = eventToCopy.recurWeekdays << Difference;
}
gICalLib.addEvent( eventToCopy, gEventBeingDragged.parent.server );
}
else
{
gEventBeingDragged.start.setTime( newStartDate.getTime() );
gEventBeingDragged.end.setTime( newEndDate );
if( gEventBeingDragged.recurWeekdays > 0 )
{
gEventBeingDragged.recurWeekdays = gEventBeingDragged.recurWeekdays << Difference;
}
gICalLib.modifyEvent( gEventBeingDragged, gEventBeingDragged.parent.server );
}
}
};