зеркало из https://github.com/mozilla/gecko-dev.git
Many small bug fixes, mostly with preferences.
This commit is contained in:
Родитель
778bb89663
Коммит
5d261082cf
|
@ -78,7 +78,7 @@ h1 {
|
|||
|
||||
<td id="mozver">
|
||||
<h1>
|
||||
<a id="mozlink" href="http://www.mozilla.org/projects/calendar/" target="_new">Mozilla Calendar 2002082311-cal</a>
|
||||
<a id="mozlink" href="http://www.mozilla.org/projects/calendar/" target="_new">Mozilla Calendar 2002082610-cal</a>
|
||||
</h1>
|
||||
<script type="application/x-javascript">
|
||||
// using try..catch to handle empty useragents and other cases where the regex fails to apply
|
||||
|
|
|
@ -289,15 +289,6 @@
|
|||
</menupopup>
|
||||
</menulist>
|
||||
</row>
|
||||
|
||||
<!-- Cancelled -->
|
||||
<row align="center">
|
||||
<spacer />
|
||||
<checkbox id="cancelled-checkbox" checked="false" label="&newevent.cancelled.label;"/>
|
||||
</row>
|
||||
|
||||
|
||||
|
||||
</rows>
|
||||
</grid>
|
||||
</tabpanel>
|
||||
|
|
|
@ -124,7 +124,7 @@ function loadEventsFromFile()
|
|||
|
||||
var buttonPressed =
|
||||
promptService.confirmEx(window,
|
||||
"Import", "About to import " + calendarEventArray.length + " item(s). Do you want to open all items to import before importing?",
|
||||
"Import", "About to import " + calendarEventArray.length + " event(s). Do you want to open all events to import before importing?",
|
||||
(promptService.BUTTON_TITLE_YES * promptService.BUTTON_POS_0) +
|
||||
(promptService.BUTTON_TITLE_NO * promptService.BUTTON_POS_1) +
|
||||
(promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_2),
|
||||
|
@ -169,69 +169,29 @@ function createUniqueID()
|
|||
|
||||
function addEventsToCalendar( calendarEventArray, silent )
|
||||
{
|
||||
var defaultServer = gCalendarWindow.calendarManager.calendars[0];
|
||||
for(var i = 0; i < calendarEventArray.length; i++)
|
||||
{
|
||||
if( isEvent( calendarEventArray[i] ) )
|
||||
{
|
||||
var calendarEvent = calendarEventArray[i];
|
||||
calendarEvent = calendarEventArray[i]
|
||||
|
||||
// Check if event with same ID already in Calendar. If so, import event with new ID.
|
||||
if( gICalLib.fetchEvent( calendarEvent.id ) != null ) {
|
||||
calendarEvent.id = createUniqueID( );
|
||||
}
|
||||
|
||||
// the start time is in zulu time, need to convert to current time
|
||||
if(calendarEvent.allDay != true)
|
||||
convertZuluToLocal( calendarEvent );
|
||||
|
||||
// open the event dialog with the event to add
|
||||
if( silent )
|
||||
gICalLib.addEvent( calendarEvent, defaultServer.path );
|
||||
else
|
||||
editNewEvent( calendarEvent );
|
||||
}
|
||||
else if( isToDo( calendarEventArray[i] ) )
|
||||
{
|
||||
//
|
||||
calendarTodo = calendarEventArray[i];
|
||||
|
||||
// Check if task with same ID already in Calendar. If so, import task with new ID.
|
||||
if( gICalLib.fetchTodo( calendarTodo.id ) != null ) {
|
||||
calendarTodo.id = createUniqueID( );
|
||||
}
|
||||
|
||||
// open the todo dialog with the task to add
|
||||
if( silent ){alert(defaultServer.path);
|
||||
gICalLib.addTodo( calendarTodo, defaultServer.path );}
|
||||
else
|
||||
gICalLib.addTodo( calendarTodo, defaultServer.path );
|
||||
// XXX TODO: add support to add todo using dialog
|
||||
// editToDo( calendarTodo );
|
||||
// Check if event with same ID already in Calendar. If so, import event with new ID.
|
||||
if( gICalLib.fetchEvent( calendarEvent.id ) != null ) {
|
||||
calendarEvent.id = createUniqueID( );
|
||||
}
|
||||
|
||||
// the start time is in zulu time, need to convert to current time
|
||||
if(calendarEvent.allDay != true)
|
||||
convertZuluToLocal( calendarEvent );
|
||||
|
||||
// open the event dialog with the event to add
|
||||
if( silent )
|
||||
gICalLib.addEvent( calendarEvent );
|
||||
else
|
||||
editNewEvent( calendarEvent );
|
||||
}
|
||||
}
|
||||
|
||||
const ZULU_OFFSET_MILLIS = new Date().getTimezoneOffset() * 60 * 1000;
|
||||
|
||||
function convertToUTC( aLocalTime )
|
||||
{
|
||||
if( calendarEvent.start.utc == false )
|
||||
{
|
||||
aLocalTime.setTime( aLocalTime.getTime() + ZULU_OFFSET_MILLIS );
|
||||
aLocalTime.utc = true;
|
||||
}
|
||||
}
|
||||
|
||||
function convertFromUTC( aUtcTime )
|
||||
{
|
||||
if( aUtcTime.utc == true )
|
||||
{
|
||||
aUtcTime.setTime( aUtcTime.getTime() - ZULU_OFFSET_MILLIS );
|
||||
aUtcTime.utc = false;
|
||||
}
|
||||
}
|
||||
|
||||
function convertZuluToLocal( calendarEvent )
|
||||
{
|
||||
if( calendarEvent.start.utc == true )
|
||||
|
@ -318,20 +278,19 @@ function initCalendarEvent( calendarEvent )
|
|||
* Parses those events and returns an array of calendarEvents.
|
||||
*/
|
||||
|
||||
function parseIcalData( icalendarString )
|
||||
function parseIcalData( icalStr )
|
||||
{
|
||||
var calendarEventArray = new Array();
|
||||
|
||||
var i,j;
|
||||
var icalStr = icalendarString;
|
||||
while( icalStr.indexOf("BEGIN:VEVENT") != -1 )
|
||||
{
|
||||
// try to find the begin and end of an event. ParseIcalString does not support VCALENDAR
|
||||
i = icalStr.indexOf("BEGIN:VEVENT");
|
||||
j = icalStr.indexOf("END:VEVENT") + 10;
|
||||
var eventData = icalStr.substring(i, j);
|
||||
eventData = icalStr.substring(i, j);
|
||||
|
||||
var calendarEvent = createEvent();
|
||||
calendarEvent = createEvent();
|
||||
|
||||
// if parsing import iCalendar failed, add date as description
|
||||
if ( !calendarEvent.parseIcalString(eventData) )
|
||||
|
@ -347,29 +306,7 @@ function parseIcalData( icalendarString )
|
|||
// remove the parsed VEVENT from the calendar data to parse
|
||||
icalStr = icalStr.substring(j+1);
|
||||
}
|
||||
|
||||
icalStr = icalendarString;
|
||||
while( icalStr.indexOf("BEGIN:VTODO") != -1 )
|
||||
{
|
||||
// try to find the begin and end of an task. ParseIcalString does not support VCALENDAR
|
||||
i = icalStr.indexOf("BEGIN:VTODO");
|
||||
j = icalStr.indexOf("END:VTODO") + 9;
|
||||
var todoData = icalStr.substring(i, j);
|
||||
|
||||
var calendarTodo = createToDo();
|
||||
|
||||
// if parsing import iCalendar failed, add date as description
|
||||
if ( !calendarTodo.parseTodoIcalString(todoData) )
|
||||
{
|
||||
// Save the parsed text as description.
|
||||
calendarTodo.description = icalStr;
|
||||
}
|
||||
|
||||
calendarEventArray[ calendarEventArray.length ] = calendarTodo;
|
||||
// remove the parsed VTODO from the calendar data to parse
|
||||
icalStr = icalStr.substring(j+1);
|
||||
}
|
||||
|
||||
|
||||
return calendarEventArray;
|
||||
}
|
||||
|
||||
|
@ -407,18 +344,18 @@ function readDataFromFile( aFilePath, charset )
|
|||
var scriptableInputStream;
|
||||
var tmp; // not sure what the use is for this
|
||||
|
||||
localFileInstance = Components.classes[LOCALFILE_CTRID].createInstance( nsILocalFile );
|
||||
localFileInstance.initWithPath( aFilePath );
|
||||
LocalFileInstance = Components.classes[LOCALFILE_CTRID].createInstance( nsILocalFile );
|
||||
LocalFileInstance.initWithPath( aFilePath );
|
||||
|
||||
inputStream = Components.classes[FILEIN_CTRID].createInstance( nsIFileInputStream );
|
||||
try
|
||||
{
|
||||
inputStream.init( localFileInstance, MODE_RDONLY, 0444, tmp );
|
||||
inputStream.init( LocalFileInstance, MODE_RDONLY, 0444, tmp );
|
||||
|
||||
scriptableInputStream = Components.classes[SCRIPTSTREAM_CTRID].createInstance( nsIScriptableInputStream);
|
||||
scriptableInputStream.init( inputStream );
|
||||
|
||||
var aDataStream = scriptableInputStream.read( -1 );
|
||||
aDataStream = scriptableInputStream.read( -1 );
|
||||
scriptableInputStream.close();
|
||||
inputStream.close();
|
||||
|
||||
|
@ -536,27 +473,22 @@ function eventArrayToICalString( calendarEventArray, doPatchForExport )
|
|||
var sTextiCalendar = "";
|
||||
for( var eventArrayIndex = 0; eventArrayIndex < calendarEventArray.length; ++eventArrayIndex )
|
||||
{
|
||||
var calendarObject = calendarEventArray[ eventArrayIndex ].clone();
|
||||
var calendarEvent = calendarEventArray[ eventArrayIndex ].clone();
|
||||
|
||||
// convert time to represent local to produce correct DTSTART and DTEND
|
||||
if( isEvent(calendarObject) && calendarObject.allDay != true )
|
||||
convertLocalToZulu( calendarObject );
|
||||
if(calendarEvent.allDay != true)
|
||||
convertLocalToZulu( calendarEvent );
|
||||
|
||||
// check if all required properties are available
|
||||
if( calendarObject.method == 0 )
|
||||
calendarObject.method = calendarObject.ICAL_METHOD_PUBLISH;
|
||||
if( calendarObject.stamp.year == 0 )
|
||||
calendarObject.stamp.setTime( new Date() );
|
||||
if( calendarEvent.method == 0 )
|
||||
calendarEvent.method = calendarEvent.ICAL_METHOD_PUBLISH;
|
||||
if( calendarEvent.stamp.year == 0 )
|
||||
calendarEvent.stamp.setTime( new Date() );
|
||||
|
||||
if ( isEvent(calendarObject) && doPatchForExport )
|
||||
sTextiCalendar += patchICalStringForExport( calendarObject.getIcalString() );
|
||||
if ( doPatchForExport )
|
||||
sTextiCalendar += patchICalStringForExport( calendarEvent.getIcalString() );
|
||||
else
|
||||
{
|
||||
if( isEvent(calendarObject) )
|
||||
sTextiCalendar += calendarObject.getIcalString();
|
||||
else
|
||||
sTextiCalendar += calendarObject.getTodoIcalString();
|
||||
}
|
||||
sTextiCalendar += calendarEvent.getIcalString() ;
|
||||
}
|
||||
|
||||
return sTextiCalendar;
|
||||
|
@ -593,11 +525,11 @@ function patchICalStringForExport( sTextiCalendar )
|
|||
|
||||
function eventArrayToHTML( calendarEventArray )
|
||||
{
|
||||
const sHTMLHeader =
|
||||
sHTMLHeader =
|
||||
"<html>\n" + "<head>\n" + "<title>Mozilla Calendar</title>\n" +
|
||||
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n" +
|
||||
"</head>\n"+ "<body bgcolor=\"#FFFFFF\" text=\"#000000\">\n";
|
||||
const sHTMLFooter =
|
||||
sHTMLFooter =
|
||||
"\n</body>\n</html>\n";
|
||||
|
||||
var sHTMLText = sHTMLHeader;
|
||||
|
@ -707,7 +639,6 @@ function eventArrayToXCS( calendarEventArray )
|
|||
|
||||
// XXX MAJOR UGLY HACK!! Serializer doesn't insert XML Declaration
|
||||
// http://bugzilla.mozilla.org/show_bug.cgi?id=63558
|
||||
// Fixed in Mozilla 1.2
|
||||
var serialDocument = serializer.serializeToString ( xcsDoc );
|
||||
|
||||
if( serialDocument.indexOf( "<?xml" ) == -1 )
|
||||
|
@ -730,10 +661,11 @@ function saveDataToFile(aFilePath, aDataStream, charset)
|
|||
const nsILocalFile = Components.interfaces.nsILocalFile;
|
||||
const nsIFileOutputStream = Components.interfaces.nsIFileOutputStream;
|
||||
|
||||
var localFileInstance;
|
||||
var outputStream;
|
||||
|
||||
var localFileInstance = Components.classes[LOCALFILE_CTRID].createInstance(nsILocalFile);
|
||||
localFileInstance.initWithPath(aFilePath);
|
||||
var LocalFileInstance = Components.classes[LOCALFILE_CTRID].createInstance(nsILocalFile);
|
||||
LocalFileInstance.initWithPath(aFilePath);
|
||||
|
||||
outputStream = Components.classes[FILEOUT_CTRID].createInstance(nsIFileOutputStream);
|
||||
try
|
||||
|
@ -741,7 +673,7 @@ function saveDataToFile(aFilePath, aDataStream, charset)
|
|||
if(charset)
|
||||
aDataStream = convertFromUnicode( charset, aDataStream );
|
||||
|
||||
outputStream.init(localFileInstance, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, 0664, 0);
|
||||
outputStream.init(LocalFileInstance, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, 0664, 0);
|
||||
outputStream.write(aDataStream, aDataStream.length);
|
||||
// outputStream.flush();
|
||||
outputStream.close();
|
||||
|
@ -1096,14 +1028,6 @@ function makeXmlNode( xmlDocument, calendarEvent )
|
|||
addPropertyNode( xmlDocument, eventNode, "UID", calendarEvent.id );
|
||||
addPropertyNode( xmlDocument, eventNode, "SUMMARY", checkString( calendarEvent.title ) );
|
||||
addPropertyNode( xmlDocument, eventNode, "DTSTAMP", checkDate( calendarEvent.stamp ) );
|
||||
|
||||
if( isToDo( calendarEvent ) )
|
||||
{
|
||||
addPropertyNode( xmlDocument, eventNode, "DUE", checkDate( calendarEvent.due ) );
|
||||
addPropertyNode( xmlDocument, eventNode, "COMPLETED", checkDate( calendarEvent.completed ) );
|
||||
addPropertyNode( xmlDocument, eventNode, "PERCENT-COMPLETE", checkBoolean( calendarEvent.percent ) );
|
||||
}
|
||||
|
||||
if( calendarEvent.allDay )
|
||||
addPropertyNode( xmlDocument, eventNode, "DTSTART", checkDate( calendarEvent.start, true ), "DATE" );
|
||||
else
|
||||
|
|
|
@ -197,7 +197,17 @@ calendarManager.prototype.getAllCalendars = function()
|
|||
var thisCalendar = new CalendarObject;
|
||||
thisCalendar.name = "Default";
|
||||
thisCalendar.path = profileFile.path;
|
||||
thisCalendar.active = this.CalendarWindow.calendarPreferences.calendarPref.getBoolPref( "server0.active" );;
|
||||
try {
|
||||
var active = this.CalendarWindow.calendarPreferences.calendarPref.getBoolPref( "server0.active" );
|
||||
}
|
||||
catch( e )
|
||||
{
|
||||
this.CalendarWindow.calendarPreferences.calendarPref.setBoolPref( "server0.active", true );
|
||||
|
||||
var active = this.CalendarWindow.calendarPreferences.calendarPref.getBoolPref( "server0.active" );
|
||||
}
|
||||
|
||||
thisCalendar.active = active;
|
||||
thisCalendar.remote = false;
|
||||
this.calendars[ this.calendars.length ] = thisCalendar;
|
||||
|
||||
|
@ -340,6 +350,4 @@ function removeCalendar( event )
|
|||
refreshEventTree( eventTable );
|
||||
|
||||
gCalendarWindow.currentView.refreshEvents();
|
||||
|
||||
toDoUnifinderRefesh();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,820 @@
|
|||
/* ***** 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>
|
||||
* Colin Phillips <colinp@oeone.com>
|
||||
* Chris Charabaruk <ccharabaruk@meldstar.com>
|
||||
* ArentJan Banck <ajbanck@planet.nl>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Enable/Disable Repeat items
|
||||
*/
|
||||
|
||||
function updateRepeatItemEnabled()
|
||||
{
|
||||
var exceptionsDateButton = document.getElementById( "exception-dates-button" );
|
||||
var exceptionsDateText = document.getElementById( "exception-dates-text" );
|
||||
|
||||
var repeatCheckBox = document.getElementById( "repeat-checkbox" );
|
||||
|
||||
var repeatDisableList = document.getElementsByAttribute( "disable-controller", "repeat" );
|
||||
|
||||
if( repeatCheckBox.checked )
|
||||
{
|
||||
exceptionsDateButton.setAttribute( "popup", "oe-date-picker-popup" );
|
||||
exceptionsDateText.setAttribute( "popup", "oe-date-picker-popup" );
|
||||
|
||||
// call remove attribute beacuse some widget code checks for the presense of a
|
||||
// disabled attribute, not the value.
|
||||
for( var i = 0; i < repeatDisableList.length; ++i )
|
||||
{
|
||||
if( repeatDisableList[i].getAttribute( "today" ) != "true" )
|
||||
repeatDisableList[i].removeAttribute( "disabled" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
exceptionsDateButton.removeAttribute( "popup" );
|
||||
exceptionsDateText.removeAttribute( "popup" );
|
||||
|
||||
for( var j = 0; j < repeatDisableList.length; ++j )
|
||||
{
|
||||
repeatDisableList[j].setAttribute( "disabled", "true" );
|
||||
}
|
||||
}
|
||||
|
||||
// udpate plural/singular
|
||||
|
||||
updateRepeatPlural();
|
||||
|
||||
updateAlarmPlural();
|
||||
|
||||
// update until items whenever repeat changes
|
||||
|
||||
updateUntilItemEnabled();
|
||||
|
||||
// extra interface depending on units
|
||||
|
||||
updateRepeatUnitExtensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update plural singular menu items
|
||||
*/
|
||||
|
||||
function updateRepeatPlural()
|
||||
{
|
||||
updateMenuPlural( "repeat-length-field", "repeat-length-units" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update plural singular menu items
|
||||
*/
|
||||
|
||||
function updateAlarmPlural()
|
||||
{
|
||||
updateMenuPlural( "alarm-length-field", "alarm-length-units" );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update plural singular menu items
|
||||
*/
|
||||
|
||||
function updateMenuPlural( lengthFieldId, menuId )
|
||||
{
|
||||
var field = document.getElementById( lengthFieldId );
|
||||
var menu = document.getElementById( menuId );
|
||||
|
||||
// figure out whether we should use singular or plural
|
||||
|
||||
var length = field.value;
|
||||
|
||||
var newLabelNumber;
|
||||
|
||||
if( Number( length ) > 1 )
|
||||
{
|
||||
newLabelNumber = "labelplural"
|
||||
}
|
||||
else
|
||||
{
|
||||
newLabelNumber = "labelsingular"
|
||||
}
|
||||
|
||||
// see what we currently show and change it if required
|
||||
|
||||
var oldLabelNumber = menu.getAttribute( "labelnumber" );
|
||||
|
||||
if( newLabelNumber != oldLabelNumber )
|
||||
{
|
||||
// remember what we are showing now
|
||||
|
||||
menu.setAttribute( "labelnumber", newLabelNumber );
|
||||
|
||||
// update the menu items
|
||||
|
||||
var items = menu.getElementsByTagName( "menuitem" );
|
||||
|
||||
for( var i = 0; i < items.length; ++i )
|
||||
{
|
||||
var menuItem = items[i];
|
||||
var newLabel = menuItem.getAttribute( newLabelNumber );
|
||||
menuItem.label = newLabel;
|
||||
menuItem.setAttribute( "label", newLabel );
|
||||
|
||||
}
|
||||
|
||||
// force the menu selection to redraw
|
||||
|
||||
var saveSelectedIndex = menu.selectedIndex;
|
||||
menu.selectedIndex = -1;
|
||||
menu.selectedIndex = saveSelectedIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/Disable Until items
|
||||
*/
|
||||
|
||||
function updateUntilItemEnabled()
|
||||
{
|
||||
var repeatUntilRadio = document.getElementById( "repeat-until-radio" );
|
||||
var repeatCheckBox = document.getElementById( "repeat-checkbox" );
|
||||
|
||||
var repeatEndText = document.getElementById( "repeat-end-date-text" );
|
||||
var repeatEndPicker = document.getElementById( "repeat-end-date-button" );
|
||||
|
||||
if( repeatCheckBox.checked && repeatUntilRadio.selected )
|
||||
{
|
||||
repeatEndText.removeAttribute( "disabled" );
|
||||
repeatEndText.setAttribute( "popup", "oe-date-picker-popup" );
|
||||
repeatEndPicker.removeAttribute( "disabled" );
|
||||
repeatEndPicker.setAttribute( "popup", "oe-date-picker-popup" );
|
||||
}
|
||||
else
|
||||
{
|
||||
repeatEndText.setAttribute( "disabled", "true" );
|
||||
repeatEndText.removeAttribute( "popup" );
|
||||
repeatEndPicker.setAttribute( "disabled", "true" );
|
||||
repeatEndPicker.removeAttribute( "popup" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function updateRepeatUnitExtensions( )
|
||||
{
|
||||
var repeatMenu = document.getElementById( "repeat-length-units" );
|
||||
var weekExtensions = document.getElementById( "repeat-extenstions-week" );
|
||||
var monthExtensions = document.getElementById( "repeat-extenstions-month" );
|
||||
|
||||
//FIX ME! WHEN THE WINDOW LOADS, THIS DOESN'T EXIST
|
||||
if( repeatMenu.selectedItem )
|
||||
{
|
||||
switch( repeatMenu.selectedItem.value )
|
||||
{
|
||||
case "days":
|
||||
weekExtensions.setAttribute( "collapsed", "true" );
|
||||
monthExtensions.setAttribute( "collapsed", "true" );
|
||||
break;
|
||||
|
||||
case "weeks":
|
||||
weekExtensions.removeAttribute( "collapsed" );
|
||||
monthExtensions.setAttribute( "collapsed", "true" );
|
||||
updateAdvancedWeekRepeat();
|
||||
break;
|
||||
|
||||
case "months":
|
||||
weekExtensions.setAttribute( "collapsed", "true" );
|
||||
monthExtensions.removeAttribute( "collapsed" );
|
||||
updateAdvancedRepeatDayOfMonth();
|
||||
break;
|
||||
|
||||
case "years":
|
||||
weekExtensions.setAttribute( "collapsed", "true" );
|
||||
monthExtensions.setAttribute( "collapsed", "true" );
|
||||
break;
|
||||
|
||||
}
|
||||
sizeToContent();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Enable/Disable Start/End items
|
||||
*/
|
||||
|
||||
function updateStartEndItemEnabled()
|
||||
{
|
||||
var allDayCheckBox = document.getElementById( "all-day-event-checkbox" );
|
||||
|
||||
var startTimeLabel = document.getElementById( "start-time-label" );
|
||||
var startTimePicker = document.getElementById( "start-time-button" );
|
||||
var startTimeText = document.getElementById( "start-time-text" );
|
||||
|
||||
var endTimeLabel = document.getElementById( "end-time-label" );
|
||||
var endTimePicker = document.getElementById( "end-time-button" );
|
||||
var endTimeText = document.getElementById( "end-time-text" );
|
||||
|
||||
if( allDayCheckBox.checked )
|
||||
{
|
||||
// disable popups by removing the popup attribute
|
||||
|
||||
startTimeLabel.setAttribute( "disabled", "true" );
|
||||
startTimeText.setAttribute( "disabled", "true" );
|
||||
startTimeText.removeAttribute( "popup" );
|
||||
startTimePicker.setAttribute( "disabled", "true" );
|
||||
startTimePicker.removeAttribute( "popup" );
|
||||
|
||||
endTimeLabel.setAttribute( "disabled", "true" );
|
||||
endTimeText.setAttribute( "disabled", "true" );
|
||||
endTimeText.removeAttribute( "popup" );
|
||||
endTimePicker.setAttribute( "disabled", "true" );
|
||||
endTimePicker.removeAttribute( "popup" );
|
||||
}
|
||||
else
|
||||
{
|
||||
// enable popups by setting the popup attribute
|
||||
|
||||
startTimeLabel.removeAttribute( "disabled" );
|
||||
startTimeText.removeAttribute( "disabled" );
|
||||
startTimeText.setAttribute( "popup", "oe-time-picker-popup" );
|
||||
startTimePicker.removeAttribute( "disabled" );
|
||||
startTimePicker.setAttribute( "popup", "oe-time-picker-popup" );
|
||||
|
||||
endTimeLabel.removeAttribute( "disabled" );
|
||||
endTimeText.removeAttribute( "disabled" );
|
||||
endTimeText.setAttribute( "popup", "oe-time-picker-popup" );
|
||||
endTimePicker.removeAttribute( "disabled" );
|
||||
endTimePicker.setAttribute( "popup", "oe-time-picker-popup" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Handle key down in repeat field
|
||||
*/
|
||||
|
||||
function repeatLengthKeyDown( repeatField )
|
||||
{
|
||||
updateRepeatPlural();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle key down in alarm field
|
||||
*/
|
||||
|
||||
function alarmLengthKeyDown( repeatField )
|
||||
{
|
||||
updateAlarmPlural();
|
||||
}
|
||||
|
||||
|
||||
function repeatUnitCommand( repeatMenu )
|
||||
{
|
||||
updateRepeatUnitExtensions();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Functions for advanced repeating elements
|
||||
*/
|
||||
|
||||
function setAdvancedWeekRepeat()
|
||||
{
|
||||
var checked = false;
|
||||
|
||||
if( gEvent.recurWeekdays > 0 )
|
||||
{
|
||||
for( var i = 0; i < 7; i++ )
|
||||
{
|
||||
checked = ( ( gEvent.recurWeekdays | eval( "kRepeatDay_"+i ) ) == eval( gEvent.recurWeekdays ) );
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+i, checked, "checked" );
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+i, false, "today" );
|
||||
}
|
||||
}
|
||||
|
||||
//get the day number for today.
|
||||
var startTime = getDateTimeFieldValue( "start-date-text" );
|
||||
|
||||
var dayNumber = startTime.getDay();
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+dayNumber, "true", "checked" );
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+dayNumber, "true", "disabled" );
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+dayNumber, "true", "today" );
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
** Functions for advanced repeating elements
|
||||
*/
|
||||
|
||||
function getAdvancedWeekRepeat()
|
||||
{
|
||||
var Total = 0;
|
||||
|
||||
for( var i = 0; i < 7; i++ )
|
||||
{
|
||||
if( getFieldValue( "advanced-repeat-week-"+i, "checked" ) == true )
|
||||
{
|
||||
Total += eval( "kRepeatDay_"+i );
|
||||
}
|
||||
}
|
||||
return( Total );
|
||||
}
|
||||
|
||||
/*
|
||||
** function to set the menu items text
|
||||
*/
|
||||
function updateAdvancedWeekRepeat()
|
||||
{
|
||||
//get the day number for today.
|
||||
var startTime = getDateTimeFieldValue( "start-date-text" );
|
||||
|
||||
var dayNumber = startTime.getDay();
|
||||
|
||||
//uncheck them all if the repeat checkbox is checked
|
||||
var repeatCheckBox = document.getElementById( "repeat-checkbox" );
|
||||
|
||||
if( repeatCheckBox.checked )
|
||||
{
|
||||
//uncheck them all
|
||||
for( var i = 0; i < 7; i++ )
|
||||
{
|
||||
setFieldValue( "advanced-repeat-week-"+i, false, "disabled" );
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+i, false, "today" );
|
||||
}
|
||||
}
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+dayNumber, "true", "checked" );
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+dayNumber, "true", "disabled" );
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+dayNumber, "true", "today" );
|
||||
}
|
||||
|
||||
/*
|
||||
** function to set the menu items text
|
||||
*/
|
||||
function updateAdvancedRepeatDayOfMonth()
|
||||
{
|
||||
//get the day number for today.
|
||||
var startTime = getDateTimeFieldValue( "start-date-text" );
|
||||
|
||||
var dayNumber = startTime.getDate();
|
||||
|
||||
var dayExtension = getDayExtension( dayNumber );
|
||||
|
||||
var weekNumber = getWeekNumberOfMonth();
|
||||
|
||||
document.getElementById( "advanced-repeat-dayofmonth" ).setAttribute( "label", "On the "+dayNumber+dayExtension+" of the month" );
|
||||
|
||||
if( weekNumber == 4 && isLastDayOfWeekOfMonth() )
|
||||
{
|
||||
//enable
|
||||
document.getElementById( "advanced-repeat-dayofweek" ).setAttribute( "label", getWeekNumberText( weekNumber )+" "+getDayOfWeek( dayNumber )+" of the month" );
|
||||
|
||||
document.getElementById( "advanced-repeat-dayofweek-last" ).removeAttribute( "collapsed" );
|
||||
|
||||
document.getElementById( "advanced-repeat-dayofweek-last" ).setAttribute( "label", "Last "+getDayOfWeek( dayNumber )+" of the month" );
|
||||
}
|
||||
else if( weekNumber == 4 && !isLastDayOfWeekOfMonth() )
|
||||
{
|
||||
document.getElementById( "advanced-repeat-dayofweek" ).setAttribute( "label", getWeekNumberText( weekNumber )+" "+getDayOfWeek( dayNumber )+" of the month" );
|
||||
|
||||
document.getElementById( "advanced-repeat-dayofweek-last" ).setAttribute( "collapsed", "true" );
|
||||
}
|
||||
else
|
||||
{
|
||||
//disable
|
||||
document.getElementById( "advanced-repeat-dayofweek" ).setAttribute( "collapsed", "true" );
|
||||
|
||||
document.getElementById( "advanced-repeat-dayofweek-last" ).setAttribute( "label", "Last "+getDayOfWeek( dayNumber )+" of the month" );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
** function to enable or disable the add exception button
|
||||
*/
|
||||
function updateAddExceptionButton()
|
||||
{
|
||||
//get the date from the picker
|
||||
var datePickerValue = getDateTimeFieldValue( "exception-dates-text" );
|
||||
|
||||
if( isAlreadyException( datePickerValue ) || document.getElementById( "repeat-checkbox" ).getAttribute( "checked" ) != "true" )
|
||||
{
|
||||
document.getElementById( "exception-add-button" ).setAttribute( "disabled", "true" );
|
||||
}
|
||||
else
|
||||
{
|
||||
document.getElementById( "exception-add-button" ).removeAttribute( "disabled" );
|
||||
}
|
||||
}
|
||||
|
||||
function removeSelectedExceptionDate()
|
||||
{
|
||||
var Listbox = document.getElementById( "exception-dates-listbox" );
|
||||
|
||||
var SelectedItem = Listbox.selectedItem;
|
||||
|
||||
if( SelectedItem )
|
||||
Listbox.removeChild( SelectedItem );
|
||||
}
|
||||
|
||||
function addException( dateToAdd )
|
||||
{
|
||||
if( !dateToAdd )
|
||||
{
|
||||
//get the date from the date and time box.
|
||||
//returns a date object
|
||||
var dateToAdd = getDateTimeFieldValue( "exception-dates-text" );
|
||||
}
|
||||
|
||||
if( isAlreadyException( dateToAdd ) )
|
||||
return;
|
||||
|
||||
var DateLabel = formatDate( dateToAdd );
|
||||
|
||||
//add a row to the listbox
|
||||
document.getElementById( "exception-dates-listbox" ).appendItem( DateLabel, dateToAdd.getTime() );
|
||||
|
||||
sizeToContent();
|
||||
}
|
||||
|
||||
function isAlreadyException( dateObj )
|
||||
{
|
||||
//check to make sure that the date is not already added.
|
||||
var listbox = document.getElementById( "exception-dates-listbox" );
|
||||
|
||||
for( var i = 0; i < listbox.childNodes.length; i++ )
|
||||
{
|
||||
var dateToMatch = new Date( );
|
||||
|
||||
dateToMatch.setTime( listbox.childNodes[i].value );
|
||||
if( dateToMatch.getMonth() == dateObj.getMonth() && dateToMatch.getFullYear() == dateObj.getFullYear() && dateToMatch.getDate() == dateObj.getDate() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getDayExtension( dayNumber )
|
||||
{
|
||||
switch( dayNumber )
|
||||
{
|
||||
case 1:
|
||||
case 21:
|
||||
case 31:
|
||||
return( "st" );
|
||||
case 2:
|
||||
case 22:
|
||||
return( "nd" );
|
||||
case 3:
|
||||
case 23:
|
||||
return( "rd" );
|
||||
default:
|
||||
return( "th" );
|
||||
}
|
||||
}
|
||||
|
||||
function getDayOfWeek( )
|
||||
{
|
||||
//get the day number for today.
|
||||
var startTime = getDateTimeFieldValue( "start-date-text" );
|
||||
|
||||
var dayNumber = startTime.getDay();
|
||||
|
||||
var dateStringBundle = srGetStrBundle("chrome://calendar/locale/dateFormat.properties");
|
||||
|
||||
//add one to the dayNumber because in the above prop. file, it starts at day1, but JS starts at 0
|
||||
var oneBasedDayNumber = parseInt( dayNumber ) + 1;
|
||||
|
||||
return( dateStringBundle.GetStringFromName( "day."+oneBasedDayNumber+".name" ) );
|
||||
|
||||
}
|
||||
|
||||
function getWeekNumberOfMonth()
|
||||
{
|
||||
//get the day number for today.
|
||||
var startTime = getDateTimeFieldValue( "start-date-text" );
|
||||
|
||||
var oldStartTime = startTime;
|
||||
|
||||
var thisMonth = startTime.getMonth();
|
||||
|
||||
var monthToCompare = thisMonth;
|
||||
|
||||
var weekNumber = 0;
|
||||
|
||||
while( monthToCompare == thisMonth )
|
||||
{
|
||||
startTime = new Date( startTime.getTime() - ( 1000 * 60 * 60 * 24 * 7 ) );
|
||||
|
||||
monthToCompare = startTime.getMonth();
|
||||
|
||||
weekNumber++;
|
||||
}
|
||||
|
||||
return( weekNumber );
|
||||
}
|
||||
|
||||
function isLastDayOfWeekOfMonth()
|
||||
{
|
||||
//get the day number for today.
|
||||
var startTime = getDateTimeFieldValue( "start-date-text" );
|
||||
|
||||
var oldStartTime = startTime;
|
||||
|
||||
var thisMonth = startTime.getMonth();
|
||||
|
||||
var monthToCompare = thisMonth;
|
||||
|
||||
var weekNumber = 0;
|
||||
|
||||
while( monthToCompare == thisMonth )
|
||||
{
|
||||
startTime = new Date( startTime.getTime() - ( 1000 * 60 * 60 * 24 * 7 ) );
|
||||
|
||||
monthToCompare = startTime.getMonth();
|
||||
|
||||
weekNumber++;
|
||||
}
|
||||
|
||||
if( weekNumber > 3 )
|
||||
{
|
||||
var nextWeek = new Date( oldStartTime.getTime() + ( 1000 * 60 * 60 * 24 * 7 ) );
|
||||
|
||||
if( nextWeek.getMonth() != thisMonth )
|
||||
{
|
||||
//its the last week of the month
|
||||
return( true );
|
||||
}
|
||||
}
|
||||
|
||||
return( false );
|
||||
}
|
||||
|
||||
/* FILE ATTACHMENTS */
|
||||
|
||||
function removeSelectedAttachment()
|
||||
{
|
||||
var Listbox = document.getElementById( "attachmentBucket" );
|
||||
|
||||
var SelectedItem = Listbox.selectedItem;
|
||||
|
||||
if( SelectedItem )
|
||||
Listbox.removeChild( SelectedItem );
|
||||
}
|
||||
|
||||
function addAttachment( attachmentToAdd )
|
||||
{
|
||||
if( !attachmentToAdd )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//add a row to the listbox
|
||||
document.getElementById( "attachmentBucket" ).appendItem( attachmentToAdd.url, attachmentToAdd.url );
|
||||
|
||||
sizeToContent();
|
||||
}
|
||||
|
||||
|
||||
function getWeekNumberText( weekNumber )
|
||||
{
|
||||
switch( weekNumber )
|
||||
{
|
||||
case 1:
|
||||
return( "First" );
|
||||
case 2:
|
||||
return( "Second" );
|
||||
case 3:
|
||||
return( "Third" );
|
||||
case 4:
|
||||
return( "Fourth" );
|
||||
case 5:
|
||||
return( "Last" );
|
||||
default:
|
||||
return( false );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* URL */
|
||||
function launchBrowser()
|
||||
{
|
||||
//get the URL from the text box
|
||||
var UrlToGoTo = document.getElementById( "uri-field" ).value;
|
||||
|
||||
//launch the browser to that URL
|
||||
opener.open( UrlToGoTo, "calendar-opened-window" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for filling the form, set the value of a property of a XUL element
|
||||
*
|
||||
* PARAMETERS
|
||||
* elementId - ID of XUL element to set
|
||||
* newValue - value to set property to ( if undefined no change is made )
|
||||
* propertyName - OPTIONAL name of property to set, default is "value", use "checked" for
|
||||
* radios & checkboxes, "data" for drop-downs
|
||||
*/
|
||||
|
||||
function setFieldValue( elementId, newValue, propertyName )
|
||||
{
|
||||
var undefined;
|
||||
|
||||
if( newValue !== undefined )
|
||||
{
|
||||
var field = document.getElementById( elementId );
|
||||
|
||||
if( newValue === false )
|
||||
{
|
||||
field.removeAttribute( propertyName );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( propertyName )
|
||||
{
|
||||
field.setAttribute( propertyName, newValue );
|
||||
}
|
||||
else
|
||||
{
|
||||
field.value = newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for getting data from the form,
|
||||
* Get the value of a property of a XUL element
|
||||
*
|
||||
* PARAMETERS
|
||||
* elementId - ID of XUL element to get from
|
||||
* propertyName - OPTIONAL name of property to set, default is "value", use "checked" for
|
||||
* radios & checkboxes, "data" for drop-downs
|
||||
* RETURN
|
||||
* newValue - value of property
|
||||
*/
|
||||
|
||||
function getFieldValue( elementId, propertyName )
|
||||
{
|
||||
var field = document.getElementById( elementId );
|
||||
|
||||
if( propertyName )
|
||||
{
|
||||
return field[ propertyName ];
|
||||
}
|
||||
else
|
||||
{
|
||||
return field.value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for getting a date/time from the form.
|
||||
* The element must have been set up with setDateFieldValue or setTimeFieldValue.
|
||||
*
|
||||
* PARAMETERS
|
||||
* elementId - ID of XUL element to get from
|
||||
* RETURN
|
||||
* newValue - Date value of element
|
||||
*/
|
||||
|
||||
|
||||
function getDateTimeFieldValue( elementId )
|
||||
{
|
||||
var field = document.getElementById( elementId );
|
||||
return field.editDate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for filling the form, set the value of a date field
|
||||
*
|
||||
* PARAMETERS
|
||||
* elementId - ID of time textbox to set
|
||||
* newDate - Date Object to use
|
||||
*/
|
||||
|
||||
function setDateFieldValue( elementId, newDate )
|
||||
{
|
||||
// set the value to a formatted date string
|
||||
|
||||
var field = document.getElementById( elementId );
|
||||
field.value = formatDate( newDate );
|
||||
|
||||
// add an editDate property to the item to hold the Date object
|
||||
// used in onDatePick to update the date from the date picker.
|
||||
// used in getDateTimeFieldValue to get the Date back out.
|
||||
|
||||
// we clone the date object so changes made in place do not propagte
|
||||
|
||||
field.editDate = new Date( newDate );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for filling the form, set the value of a time field
|
||||
*
|
||||
* PARAMETERS
|
||||
* elementId - ID of time textbox to set
|
||||
* newDate - Date Object to use
|
||||
*/
|
||||
|
||||
function setTimeFieldValue( elementId, newDate )
|
||||
{
|
||||
// set the value to a formatted time string
|
||||
|
||||
var field = document.getElementById( elementId );
|
||||
field.value = formatTime( newDate );
|
||||
|
||||
// add an editDate property to the item to hold the Date object
|
||||
// used in onTimePick to update the date from the time picker.
|
||||
// used in getDateTimeFieldValue to get the Date back out.
|
||||
|
||||
// we clone the date object so changes made in place do not propagte
|
||||
|
||||
field.editDate = new Date( newDate );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Take a Date object and return a displayable date string i.e.: May 5, 1959
|
||||
* :TODO: This should be moved into DateFormater and made to use some kind of
|
||||
* locale or user date format preference.
|
||||
*/
|
||||
|
||||
function formatDate( date )
|
||||
{
|
||||
return( opener.gCalendarWindow.dateFormater.getFormatedDate( date ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Take a Date object and return a displayable time string i.e.: 12:30 PM
|
||||
*/
|
||||
|
||||
function formatTime( time )
|
||||
{
|
||||
var timeString = opener.gCalendarWindow.dateFormater.getFormatedTime( time );
|
||||
return timeString;
|
||||
}
|
||||
|
||||
|
||||
function debug( Text )
|
||||
{
|
||||
dump( "\n"+ Text + "\n");
|
||||
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- ***** 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): Mike Potter <mikep@oeone.com>
|
||||
-
|
||||
- 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 LGPL or the GPL. 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 ***** -->
|
||||
|
||||
<!-- DTD File with all strings specific to the calendar -->
|
||||
<!DOCTYPE window
|
||||
[
|
||||
<!ENTITY % dtd1 SYSTEM "chrome://calendar/locale/calendar.dtd" > %dtd1;
|
||||
]>
|
||||
|
||||
|
||||
<!-- This is the overlay that addes repeating information to the event and task dialogs. -->
|
||||
|
||||
<overlay id="calendarRepeatOverlay"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<!-- Repeat -->
|
||||
<vbox id="repeat-outer-box">
|
||||
<hbox id="repeat-box" align="center">
|
||||
<checkbox id="repeat-checkbox" class="proper-align" label="&newevent.repeat.label;" checked="false" oncommand="commandRepeat()"/>
|
||||
<textbox id="repeat-length-field" class="cursor-pointer" disable-controller="repeat" value="1" oninput="repeatLengthKeyDown( this )"/>
|
||||
|
||||
<menulist crop="none" oncommand="repeatUnitCommand( this )" labelnumber="labelplural" id="repeat-length-units" disable-controller="repeat">
|
||||
<menupopup>
|
||||
<menuitem label="&repeat.units.days;" labelplural="&repeat.units.days;" labelsingular="&repeat.units.days.singular;" id="repeat-length-days" value="days" />
|
||||
<menuitem label="&repeat.units.weeks;" labelplural="&repeat.units.weeks;" labelsingular="&repeat.units.weeks.singular;" id="repeat-length-weeks" value="weeks"/>
|
||||
<menuitem label="&repeat.units.months;" labelplural="&repeat.units.months;" labelsingular="&repeat.units.months.singular;" id="repeat-length-months" value="months"/>
|
||||
<menuitem label="&repeat.units.years;" labelplural="&repeat.units.years;" labelsingular="&repeat.units.years.singular;" id="repeat-length-years" value="years" />
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</hbox>
|
||||
|
||||
|
||||
<hbox id="repeat-extenstions-week" disabled="true" disable-controller="repeat" collapsed="false" align="center">
|
||||
<checkbox disable-controller="repeat" class="repeat-day-class" label="Sun" id="advanced-repeat-week-0" value="0" checked="false" />
|
||||
<checkbox disable-controller="repeat" class="repeat-day-class" label="Mon" id="advanced-repeat-week-1" value="1" checked="false" />
|
||||
<checkbox disable-controller="repeat" class="repeat-day-class" label="Tue" id="advanced-repeat-week-2" value="2" checked="false" />
|
||||
<checkbox disable-controller="repeat" class="repeat-day-class" label="Wed" id="advanced-repeat-week-3" value="3" checked="false" />
|
||||
<checkbox disable-controller="repeat" class="repeat-day-class" label="Thu" id="advanced-repeat-week-4" value="4" checked="false" />
|
||||
<checkbox disable-controller="repeat" class="repeat-day-class" label="Fri" id="advanced-repeat-week-5" value="5" checked="false" />
|
||||
<checkbox disable-controller="repeat" class="repeat-day-class" label="Sat" id="advanced-repeat-week-6" value="6" checked="false" />
|
||||
</hbox>
|
||||
|
||||
|
||||
<hbox id="repeat-extenstions-month" diabled="true" collapsed="true" align="center">
|
||||
<vbox align="center">
|
||||
<radiogroup id="advanced-repeat-month" disable-controller="repeat">
|
||||
<radio disable-controller="repeat" id="advanced-repeat-dayofmonth" label="On the xth day of the month" selected="true"/>
|
||||
<radio disable-controller="repeat" id="advanced-repeat-dayofweek" label="4th Tuesday of the month"/>
|
||||
<radio disable-controller="repeat" id="advanced-repeat-dayofweek-last" label="Last Tuesday of the month" disabled="true"/>
|
||||
</radiogroup>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
<spacer height="10" />
|
||||
|
||||
<hbox align="center">
|
||||
<spacer class="repeat-left-spacer" />
|
||||
<radiogroup id="repeat-until-group" disable-controller="repeat">
|
||||
<radio id="repeat-forever-radio" disable-controller="repeat" label="&newevent.forever.label;" oncommand="commandUntil()"/>
|
||||
<hbox id="repeat-end-box" align="center">
|
||||
<vbox>
|
||||
<hbox>
|
||||
<radio id="repeat-until-radio" disable-controller="repeat" label="&newevent.until.label;" oncommand="commandUntil()"/>
|
||||
<spacer id="until-spacer"/>
|
||||
<textbox id="repeat-end-date-text" readonly="true" value="" onmousedown="prepareDatePicker('repeat-end-date-text')" popup="oe-date-picker-popup" position="before_start"/>
|
||||
<image class="event-date-button-class" id="repeat-end-date-button" onmousedown="prepareDatePicker('repeat-end-date-text')" popup="oe-date-picker-popup" position="before_start"/>
|
||||
</hbox>
|
||||
<label id="repeat-time-warning" class="warning-text-class" value="&newevent.recurend.warning;" collapsed="true"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</radiogroup>
|
||||
</hbox>
|
||||
|
||||
<hbox align="center">
|
||||
<spacer class="repeat-left-spacer" />
|
||||
<groupbox>
|
||||
<caption label="&newevent.exceptions.caption;"/>
|
||||
<grid>
|
||||
<columns>
|
||||
<column flex="1"/>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<hbox align="center">
|
||||
<textbox id="exception-dates-text" disable-controller="repeat" readonly="true" value="" onmousedown="prepareDatePicker('exception-dates-text')" popup="oe-date-picker-popup" position="before_start"/>
|
||||
<image class="event-date-button-class" disable-controller="repeat" id="exception-dates-button" onmousedown="prepareDatePicker('exception-dates-text')" popup="oe-date-picker-popup" position="before_start"/>
|
||||
</hbox>
|
||||
<button id="exception-add-button" label="&newevent.addexceptions.label;" disable-controller="repeat" oncommand="addException()"/>
|
||||
</row>
|
||||
<row>
|
||||
<listbox id="exception-dates-listbox" disable-controller="repeat" rows="4"/>
|
||||
<vbox>
|
||||
<button label="&newevent.deleteexceptions.label;" disable-controller="repeat" oncommand="removeSelectedExceptionDate()"/>
|
||||
</vbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</groupbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
<!-- /Repeat -->
|
||||
|
||||
</overlay>
|
|
@ -289,15 +289,6 @@
|
|||
</menupopup>
|
||||
</menulist>
|
||||
</row>
|
||||
|
||||
<!-- Cancelled -->
|
||||
<row align="center">
|
||||
<spacer />
|
||||
<checkbox id="cancelled-checkbox" checked="false" label="&newevent.cancelled.label;"/>
|
||||
</row>
|
||||
|
||||
|
||||
|
||||
</rows>
|
||||
</grid>
|
||||
</tabpanel>
|
||||
|
|
|
@ -124,7 +124,7 @@ function loadEventsFromFile()
|
|||
|
||||
var buttonPressed =
|
||||
promptService.confirmEx(window,
|
||||
"Import", "About to import " + calendarEventArray.length + " item(s). Do you want to open all items to import before importing?",
|
||||
"Import", "About to import " + calendarEventArray.length + " event(s). Do you want to open all events to import before importing?",
|
||||
(promptService.BUTTON_TITLE_YES * promptService.BUTTON_POS_0) +
|
||||
(promptService.BUTTON_TITLE_NO * promptService.BUTTON_POS_1) +
|
||||
(promptService.BUTTON_TITLE_CANCEL * promptService.BUTTON_POS_2),
|
||||
|
@ -169,69 +169,29 @@ function createUniqueID()
|
|||
|
||||
function addEventsToCalendar( calendarEventArray, silent )
|
||||
{
|
||||
var defaultServer = gCalendarWindow.calendarManager.calendars[0];
|
||||
for(var i = 0; i < calendarEventArray.length; i++)
|
||||
{
|
||||
if( isEvent( calendarEventArray[i] ) )
|
||||
{
|
||||
var calendarEvent = calendarEventArray[i];
|
||||
calendarEvent = calendarEventArray[i]
|
||||
|
||||
// Check if event with same ID already in Calendar. If so, import event with new ID.
|
||||
if( gICalLib.fetchEvent( calendarEvent.id ) != null ) {
|
||||
calendarEvent.id = createUniqueID( );
|
||||
}
|
||||
|
||||
// the start time is in zulu time, need to convert to current time
|
||||
if(calendarEvent.allDay != true)
|
||||
convertZuluToLocal( calendarEvent );
|
||||
|
||||
// open the event dialog with the event to add
|
||||
if( silent )
|
||||
gICalLib.addEvent( calendarEvent, defaultServer.path );
|
||||
else
|
||||
editNewEvent( calendarEvent );
|
||||
}
|
||||
else if( isToDo( calendarEventArray[i] ) )
|
||||
{
|
||||
//
|
||||
calendarTodo = calendarEventArray[i];
|
||||
|
||||
// Check if task with same ID already in Calendar. If so, import task with new ID.
|
||||
if( gICalLib.fetchTodo( calendarTodo.id ) != null ) {
|
||||
calendarTodo.id = createUniqueID( );
|
||||
}
|
||||
|
||||
// open the todo dialog with the task to add
|
||||
if( silent ){alert(defaultServer.path);
|
||||
gICalLib.addTodo( calendarTodo, defaultServer.path );}
|
||||
else
|
||||
gICalLib.addTodo( calendarTodo, defaultServer.path );
|
||||
// XXX TODO: add support to add todo using dialog
|
||||
// editToDo( calendarTodo );
|
||||
// Check if event with same ID already in Calendar. If so, import event with new ID.
|
||||
if( gICalLib.fetchEvent( calendarEvent.id ) != null ) {
|
||||
calendarEvent.id = createUniqueID( );
|
||||
}
|
||||
|
||||
// the start time is in zulu time, need to convert to current time
|
||||
if(calendarEvent.allDay != true)
|
||||
convertZuluToLocal( calendarEvent );
|
||||
|
||||
// open the event dialog with the event to add
|
||||
if( silent )
|
||||
gICalLib.addEvent( calendarEvent );
|
||||
else
|
||||
editNewEvent( calendarEvent );
|
||||
}
|
||||
}
|
||||
|
||||
const ZULU_OFFSET_MILLIS = new Date().getTimezoneOffset() * 60 * 1000;
|
||||
|
||||
function convertToUTC( aLocalTime )
|
||||
{
|
||||
if( calendarEvent.start.utc == false )
|
||||
{
|
||||
aLocalTime.setTime( aLocalTime.getTime() + ZULU_OFFSET_MILLIS );
|
||||
aLocalTime.utc = true;
|
||||
}
|
||||
}
|
||||
|
||||
function convertFromUTC( aUtcTime )
|
||||
{
|
||||
if( aUtcTime.utc == true )
|
||||
{
|
||||
aUtcTime.setTime( aUtcTime.getTime() - ZULU_OFFSET_MILLIS );
|
||||
aUtcTime.utc = false;
|
||||
}
|
||||
}
|
||||
|
||||
function convertZuluToLocal( calendarEvent )
|
||||
{
|
||||
if( calendarEvent.start.utc == true )
|
||||
|
@ -318,20 +278,19 @@ function initCalendarEvent( calendarEvent )
|
|||
* Parses those events and returns an array of calendarEvents.
|
||||
*/
|
||||
|
||||
function parseIcalData( icalendarString )
|
||||
function parseIcalData( icalStr )
|
||||
{
|
||||
var calendarEventArray = new Array();
|
||||
|
||||
var i,j;
|
||||
var icalStr = icalendarString;
|
||||
while( icalStr.indexOf("BEGIN:VEVENT") != -1 )
|
||||
{
|
||||
// try to find the begin and end of an event. ParseIcalString does not support VCALENDAR
|
||||
i = icalStr.indexOf("BEGIN:VEVENT");
|
||||
j = icalStr.indexOf("END:VEVENT") + 10;
|
||||
var eventData = icalStr.substring(i, j);
|
||||
eventData = icalStr.substring(i, j);
|
||||
|
||||
var calendarEvent = createEvent();
|
||||
calendarEvent = createEvent();
|
||||
|
||||
// if parsing import iCalendar failed, add date as description
|
||||
if ( !calendarEvent.parseIcalString(eventData) )
|
||||
|
@ -347,29 +306,7 @@ function parseIcalData( icalendarString )
|
|||
// remove the parsed VEVENT from the calendar data to parse
|
||||
icalStr = icalStr.substring(j+1);
|
||||
}
|
||||
|
||||
icalStr = icalendarString;
|
||||
while( icalStr.indexOf("BEGIN:VTODO") != -1 )
|
||||
{
|
||||
// try to find the begin and end of an task. ParseIcalString does not support VCALENDAR
|
||||
i = icalStr.indexOf("BEGIN:VTODO");
|
||||
j = icalStr.indexOf("END:VTODO") + 9;
|
||||
var todoData = icalStr.substring(i, j);
|
||||
|
||||
var calendarTodo = createToDo();
|
||||
|
||||
// if parsing import iCalendar failed, add date as description
|
||||
if ( !calendarTodo.parseTodoIcalString(todoData) )
|
||||
{
|
||||
// Save the parsed text as description.
|
||||
calendarTodo.description = icalStr;
|
||||
}
|
||||
|
||||
calendarEventArray[ calendarEventArray.length ] = calendarTodo;
|
||||
// remove the parsed VTODO from the calendar data to parse
|
||||
icalStr = icalStr.substring(j+1);
|
||||
}
|
||||
|
||||
|
||||
return calendarEventArray;
|
||||
}
|
||||
|
||||
|
@ -407,18 +344,18 @@ function readDataFromFile( aFilePath, charset )
|
|||
var scriptableInputStream;
|
||||
var tmp; // not sure what the use is for this
|
||||
|
||||
localFileInstance = Components.classes[LOCALFILE_CTRID].createInstance( nsILocalFile );
|
||||
localFileInstance.initWithPath( aFilePath );
|
||||
LocalFileInstance = Components.classes[LOCALFILE_CTRID].createInstance( nsILocalFile );
|
||||
LocalFileInstance.initWithPath( aFilePath );
|
||||
|
||||
inputStream = Components.classes[FILEIN_CTRID].createInstance( nsIFileInputStream );
|
||||
try
|
||||
{
|
||||
inputStream.init( localFileInstance, MODE_RDONLY, 0444, tmp );
|
||||
inputStream.init( LocalFileInstance, MODE_RDONLY, 0444, tmp );
|
||||
|
||||
scriptableInputStream = Components.classes[SCRIPTSTREAM_CTRID].createInstance( nsIScriptableInputStream);
|
||||
scriptableInputStream.init( inputStream );
|
||||
|
||||
var aDataStream = scriptableInputStream.read( -1 );
|
||||
aDataStream = scriptableInputStream.read( -1 );
|
||||
scriptableInputStream.close();
|
||||
inputStream.close();
|
||||
|
||||
|
@ -536,27 +473,22 @@ function eventArrayToICalString( calendarEventArray, doPatchForExport )
|
|||
var sTextiCalendar = "";
|
||||
for( var eventArrayIndex = 0; eventArrayIndex < calendarEventArray.length; ++eventArrayIndex )
|
||||
{
|
||||
var calendarObject = calendarEventArray[ eventArrayIndex ].clone();
|
||||
var calendarEvent = calendarEventArray[ eventArrayIndex ].clone();
|
||||
|
||||
// convert time to represent local to produce correct DTSTART and DTEND
|
||||
if( isEvent(calendarObject) && calendarObject.allDay != true )
|
||||
convertLocalToZulu( calendarObject );
|
||||
if(calendarEvent.allDay != true)
|
||||
convertLocalToZulu( calendarEvent );
|
||||
|
||||
// check if all required properties are available
|
||||
if( calendarObject.method == 0 )
|
||||
calendarObject.method = calendarObject.ICAL_METHOD_PUBLISH;
|
||||
if( calendarObject.stamp.year == 0 )
|
||||
calendarObject.stamp.setTime( new Date() );
|
||||
if( calendarEvent.method == 0 )
|
||||
calendarEvent.method = calendarEvent.ICAL_METHOD_PUBLISH;
|
||||
if( calendarEvent.stamp.year == 0 )
|
||||
calendarEvent.stamp.setTime( new Date() );
|
||||
|
||||
if ( isEvent(calendarObject) && doPatchForExport )
|
||||
sTextiCalendar += patchICalStringForExport( calendarObject.getIcalString() );
|
||||
if ( doPatchForExport )
|
||||
sTextiCalendar += patchICalStringForExport( calendarEvent.getIcalString() );
|
||||
else
|
||||
{
|
||||
if( isEvent(calendarObject) )
|
||||
sTextiCalendar += calendarObject.getIcalString();
|
||||
else
|
||||
sTextiCalendar += calendarObject.getTodoIcalString();
|
||||
}
|
||||
sTextiCalendar += calendarEvent.getIcalString() ;
|
||||
}
|
||||
|
||||
return sTextiCalendar;
|
||||
|
@ -593,11 +525,11 @@ function patchICalStringForExport( sTextiCalendar )
|
|||
|
||||
function eventArrayToHTML( calendarEventArray )
|
||||
{
|
||||
const sHTMLHeader =
|
||||
sHTMLHeader =
|
||||
"<html>\n" + "<head>\n" + "<title>Mozilla Calendar</title>\n" +
|
||||
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n" +
|
||||
"</head>\n"+ "<body bgcolor=\"#FFFFFF\" text=\"#000000\">\n";
|
||||
const sHTMLFooter =
|
||||
sHTMLFooter =
|
||||
"\n</body>\n</html>\n";
|
||||
|
||||
var sHTMLText = sHTMLHeader;
|
||||
|
@ -707,7 +639,6 @@ function eventArrayToXCS( calendarEventArray )
|
|||
|
||||
// XXX MAJOR UGLY HACK!! Serializer doesn't insert XML Declaration
|
||||
// http://bugzilla.mozilla.org/show_bug.cgi?id=63558
|
||||
// Fixed in Mozilla 1.2
|
||||
var serialDocument = serializer.serializeToString ( xcsDoc );
|
||||
|
||||
if( serialDocument.indexOf( "<?xml" ) == -1 )
|
||||
|
@ -730,10 +661,11 @@ function saveDataToFile(aFilePath, aDataStream, charset)
|
|||
const nsILocalFile = Components.interfaces.nsILocalFile;
|
||||
const nsIFileOutputStream = Components.interfaces.nsIFileOutputStream;
|
||||
|
||||
var localFileInstance;
|
||||
var outputStream;
|
||||
|
||||
var localFileInstance = Components.classes[LOCALFILE_CTRID].createInstance(nsILocalFile);
|
||||
localFileInstance.initWithPath(aFilePath);
|
||||
var LocalFileInstance = Components.classes[LOCALFILE_CTRID].createInstance(nsILocalFile);
|
||||
LocalFileInstance.initWithPath(aFilePath);
|
||||
|
||||
outputStream = Components.classes[FILEOUT_CTRID].createInstance(nsIFileOutputStream);
|
||||
try
|
||||
|
@ -741,7 +673,7 @@ function saveDataToFile(aFilePath, aDataStream, charset)
|
|||
if(charset)
|
||||
aDataStream = convertFromUnicode( charset, aDataStream );
|
||||
|
||||
outputStream.init(localFileInstance, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, 0664, 0);
|
||||
outputStream.init(LocalFileInstance, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, 0664, 0);
|
||||
outputStream.write(aDataStream, aDataStream.length);
|
||||
// outputStream.flush();
|
||||
outputStream.close();
|
||||
|
@ -1096,14 +1028,6 @@ function makeXmlNode( xmlDocument, calendarEvent )
|
|||
addPropertyNode( xmlDocument, eventNode, "UID", calendarEvent.id );
|
||||
addPropertyNode( xmlDocument, eventNode, "SUMMARY", checkString( calendarEvent.title ) );
|
||||
addPropertyNode( xmlDocument, eventNode, "DTSTAMP", checkDate( calendarEvent.stamp ) );
|
||||
|
||||
if( isToDo( calendarEvent ) )
|
||||
{
|
||||
addPropertyNode( xmlDocument, eventNode, "DUE", checkDate( calendarEvent.due ) );
|
||||
addPropertyNode( xmlDocument, eventNode, "COMPLETED", checkDate( calendarEvent.completed ) );
|
||||
addPropertyNode( xmlDocument, eventNode, "PERCENT-COMPLETE", checkBoolean( calendarEvent.percent ) );
|
||||
}
|
||||
|
||||
if( calendarEvent.allDay )
|
||||
addPropertyNode( xmlDocument, eventNode, "DTSTART", checkDate( calendarEvent.start, true ), "DATE" );
|
||||
else
|
||||
|
|
|
@ -0,0 +1,820 @@
|
|||
/* ***** 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>
|
||||
* Colin Phillips <colinp@oeone.com>
|
||||
* Chris Charabaruk <ccharabaruk@meldstar.com>
|
||||
* ArentJan Banck <ajbanck@planet.nl>
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Enable/Disable Repeat items
|
||||
*/
|
||||
|
||||
function updateRepeatItemEnabled()
|
||||
{
|
||||
var exceptionsDateButton = document.getElementById( "exception-dates-button" );
|
||||
var exceptionsDateText = document.getElementById( "exception-dates-text" );
|
||||
|
||||
var repeatCheckBox = document.getElementById( "repeat-checkbox" );
|
||||
|
||||
var repeatDisableList = document.getElementsByAttribute( "disable-controller", "repeat" );
|
||||
|
||||
if( repeatCheckBox.checked )
|
||||
{
|
||||
exceptionsDateButton.setAttribute( "popup", "oe-date-picker-popup" );
|
||||
exceptionsDateText.setAttribute( "popup", "oe-date-picker-popup" );
|
||||
|
||||
// call remove attribute beacuse some widget code checks for the presense of a
|
||||
// disabled attribute, not the value.
|
||||
for( var i = 0; i < repeatDisableList.length; ++i )
|
||||
{
|
||||
if( repeatDisableList[i].getAttribute( "today" ) != "true" )
|
||||
repeatDisableList[i].removeAttribute( "disabled" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
exceptionsDateButton.removeAttribute( "popup" );
|
||||
exceptionsDateText.removeAttribute( "popup" );
|
||||
|
||||
for( var j = 0; j < repeatDisableList.length; ++j )
|
||||
{
|
||||
repeatDisableList[j].setAttribute( "disabled", "true" );
|
||||
}
|
||||
}
|
||||
|
||||
// udpate plural/singular
|
||||
|
||||
updateRepeatPlural();
|
||||
|
||||
updateAlarmPlural();
|
||||
|
||||
// update until items whenever repeat changes
|
||||
|
||||
updateUntilItemEnabled();
|
||||
|
||||
// extra interface depending on units
|
||||
|
||||
updateRepeatUnitExtensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update plural singular menu items
|
||||
*/
|
||||
|
||||
function updateRepeatPlural()
|
||||
{
|
||||
updateMenuPlural( "repeat-length-field", "repeat-length-units" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update plural singular menu items
|
||||
*/
|
||||
|
||||
function updateAlarmPlural()
|
||||
{
|
||||
updateMenuPlural( "alarm-length-field", "alarm-length-units" );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update plural singular menu items
|
||||
*/
|
||||
|
||||
function updateMenuPlural( lengthFieldId, menuId )
|
||||
{
|
||||
var field = document.getElementById( lengthFieldId );
|
||||
var menu = document.getElementById( menuId );
|
||||
|
||||
// figure out whether we should use singular or plural
|
||||
|
||||
var length = field.value;
|
||||
|
||||
var newLabelNumber;
|
||||
|
||||
if( Number( length ) > 1 )
|
||||
{
|
||||
newLabelNumber = "labelplural"
|
||||
}
|
||||
else
|
||||
{
|
||||
newLabelNumber = "labelsingular"
|
||||
}
|
||||
|
||||
// see what we currently show and change it if required
|
||||
|
||||
var oldLabelNumber = menu.getAttribute( "labelnumber" );
|
||||
|
||||
if( newLabelNumber != oldLabelNumber )
|
||||
{
|
||||
// remember what we are showing now
|
||||
|
||||
menu.setAttribute( "labelnumber", newLabelNumber );
|
||||
|
||||
// update the menu items
|
||||
|
||||
var items = menu.getElementsByTagName( "menuitem" );
|
||||
|
||||
for( var i = 0; i < items.length; ++i )
|
||||
{
|
||||
var menuItem = items[i];
|
||||
var newLabel = menuItem.getAttribute( newLabelNumber );
|
||||
menuItem.label = newLabel;
|
||||
menuItem.setAttribute( "label", newLabel );
|
||||
|
||||
}
|
||||
|
||||
// force the menu selection to redraw
|
||||
|
||||
var saveSelectedIndex = menu.selectedIndex;
|
||||
menu.selectedIndex = -1;
|
||||
menu.selectedIndex = saveSelectedIndex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable/Disable Until items
|
||||
*/
|
||||
|
||||
function updateUntilItemEnabled()
|
||||
{
|
||||
var repeatUntilRadio = document.getElementById( "repeat-until-radio" );
|
||||
var repeatCheckBox = document.getElementById( "repeat-checkbox" );
|
||||
|
||||
var repeatEndText = document.getElementById( "repeat-end-date-text" );
|
||||
var repeatEndPicker = document.getElementById( "repeat-end-date-button" );
|
||||
|
||||
if( repeatCheckBox.checked && repeatUntilRadio.selected )
|
||||
{
|
||||
repeatEndText.removeAttribute( "disabled" );
|
||||
repeatEndText.setAttribute( "popup", "oe-date-picker-popup" );
|
||||
repeatEndPicker.removeAttribute( "disabled" );
|
||||
repeatEndPicker.setAttribute( "popup", "oe-date-picker-popup" );
|
||||
}
|
||||
else
|
||||
{
|
||||
repeatEndText.setAttribute( "disabled", "true" );
|
||||
repeatEndText.removeAttribute( "popup" );
|
||||
repeatEndPicker.setAttribute( "disabled", "true" );
|
||||
repeatEndPicker.removeAttribute( "popup" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function updateRepeatUnitExtensions( )
|
||||
{
|
||||
var repeatMenu = document.getElementById( "repeat-length-units" );
|
||||
var weekExtensions = document.getElementById( "repeat-extenstions-week" );
|
||||
var monthExtensions = document.getElementById( "repeat-extenstions-month" );
|
||||
|
||||
//FIX ME! WHEN THE WINDOW LOADS, THIS DOESN'T EXIST
|
||||
if( repeatMenu.selectedItem )
|
||||
{
|
||||
switch( repeatMenu.selectedItem.value )
|
||||
{
|
||||
case "days":
|
||||
weekExtensions.setAttribute( "collapsed", "true" );
|
||||
monthExtensions.setAttribute( "collapsed", "true" );
|
||||
break;
|
||||
|
||||
case "weeks":
|
||||
weekExtensions.removeAttribute( "collapsed" );
|
||||
monthExtensions.setAttribute( "collapsed", "true" );
|
||||
updateAdvancedWeekRepeat();
|
||||
break;
|
||||
|
||||
case "months":
|
||||
weekExtensions.setAttribute( "collapsed", "true" );
|
||||
monthExtensions.removeAttribute( "collapsed" );
|
||||
updateAdvancedRepeatDayOfMonth();
|
||||
break;
|
||||
|
||||
case "years":
|
||||
weekExtensions.setAttribute( "collapsed", "true" );
|
||||
monthExtensions.setAttribute( "collapsed", "true" );
|
||||
break;
|
||||
|
||||
}
|
||||
sizeToContent();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Enable/Disable Start/End items
|
||||
*/
|
||||
|
||||
function updateStartEndItemEnabled()
|
||||
{
|
||||
var allDayCheckBox = document.getElementById( "all-day-event-checkbox" );
|
||||
|
||||
var startTimeLabel = document.getElementById( "start-time-label" );
|
||||
var startTimePicker = document.getElementById( "start-time-button" );
|
||||
var startTimeText = document.getElementById( "start-time-text" );
|
||||
|
||||
var endTimeLabel = document.getElementById( "end-time-label" );
|
||||
var endTimePicker = document.getElementById( "end-time-button" );
|
||||
var endTimeText = document.getElementById( "end-time-text" );
|
||||
|
||||
if( allDayCheckBox.checked )
|
||||
{
|
||||
// disable popups by removing the popup attribute
|
||||
|
||||
startTimeLabel.setAttribute( "disabled", "true" );
|
||||
startTimeText.setAttribute( "disabled", "true" );
|
||||
startTimeText.removeAttribute( "popup" );
|
||||
startTimePicker.setAttribute( "disabled", "true" );
|
||||
startTimePicker.removeAttribute( "popup" );
|
||||
|
||||
endTimeLabel.setAttribute( "disabled", "true" );
|
||||
endTimeText.setAttribute( "disabled", "true" );
|
||||
endTimeText.removeAttribute( "popup" );
|
||||
endTimePicker.setAttribute( "disabled", "true" );
|
||||
endTimePicker.removeAttribute( "popup" );
|
||||
}
|
||||
else
|
||||
{
|
||||
// enable popups by setting the popup attribute
|
||||
|
||||
startTimeLabel.removeAttribute( "disabled" );
|
||||
startTimeText.removeAttribute( "disabled" );
|
||||
startTimeText.setAttribute( "popup", "oe-time-picker-popup" );
|
||||
startTimePicker.removeAttribute( "disabled" );
|
||||
startTimePicker.setAttribute( "popup", "oe-time-picker-popup" );
|
||||
|
||||
endTimeLabel.removeAttribute( "disabled" );
|
||||
endTimeText.removeAttribute( "disabled" );
|
||||
endTimeText.setAttribute( "popup", "oe-time-picker-popup" );
|
||||
endTimePicker.removeAttribute( "disabled" );
|
||||
endTimePicker.setAttribute( "popup", "oe-time-picker-popup" );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Handle key down in repeat field
|
||||
*/
|
||||
|
||||
function repeatLengthKeyDown( repeatField )
|
||||
{
|
||||
updateRepeatPlural();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle key down in alarm field
|
||||
*/
|
||||
|
||||
function alarmLengthKeyDown( repeatField )
|
||||
{
|
||||
updateAlarmPlural();
|
||||
}
|
||||
|
||||
|
||||
function repeatUnitCommand( repeatMenu )
|
||||
{
|
||||
updateRepeatUnitExtensions();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** Functions for advanced repeating elements
|
||||
*/
|
||||
|
||||
function setAdvancedWeekRepeat()
|
||||
{
|
||||
var checked = false;
|
||||
|
||||
if( gEvent.recurWeekdays > 0 )
|
||||
{
|
||||
for( var i = 0; i < 7; i++ )
|
||||
{
|
||||
checked = ( ( gEvent.recurWeekdays | eval( "kRepeatDay_"+i ) ) == eval( gEvent.recurWeekdays ) );
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+i, checked, "checked" );
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+i, false, "today" );
|
||||
}
|
||||
}
|
||||
|
||||
//get the day number for today.
|
||||
var startTime = getDateTimeFieldValue( "start-date-text" );
|
||||
|
||||
var dayNumber = startTime.getDay();
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+dayNumber, "true", "checked" );
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+dayNumber, "true", "disabled" );
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+dayNumber, "true", "today" );
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
** Functions for advanced repeating elements
|
||||
*/
|
||||
|
||||
function getAdvancedWeekRepeat()
|
||||
{
|
||||
var Total = 0;
|
||||
|
||||
for( var i = 0; i < 7; i++ )
|
||||
{
|
||||
if( getFieldValue( "advanced-repeat-week-"+i, "checked" ) == true )
|
||||
{
|
||||
Total += eval( "kRepeatDay_"+i );
|
||||
}
|
||||
}
|
||||
return( Total );
|
||||
}
|
||||
|
||||
/*
|
||||
** function to set the menu items text
|
||||
*/
|
||||
function updateAdvancedWeekRepeat()
|
||||
{
|
||||
//get the day number for today.
|
||||
var startTime = getDateTimeFieldValue( "start-date-text" );
|
||||
|
||||
var dayNumber = startTime.getDay();
|
||||
|
||||
//uncheck them all if the repeat checkbox is checked
|
||||
var repeatCheckBox = document.getElementById( "repeat-checkbox" );
|
||||
|
||||
if( repeatCheckBox.checked )
|
||||
{
|
||||
//uncheck them all
|
||||
for( var i = 0; i < 7; i++ )
|
||||
{
|
||||
setFieldValue( "advanced-repeat-week-"+i, false, "disabled" );
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+i, false, "today" );
|
||||
}
|
||||
}
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+dayNumber, "true", "checked" );
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+dayNumber, "true", "disabled" );
|
||||
|
||||
setFieldValue( "advanced-repeat-week-"+dayNumber, "true", "today" );
|
||||
}
|
||||
|
||||
/*
|
||||
** function to set the menu items text
|
||||
*/
|
||||
function updateAdvancedRepeatDayOfMonth()
|
||||
{
|
||||
//get the day number for today.
|
||||
var startTime = getDateTimeFieldValue( "start-date-text" );
|
||||
|
||||
var dayNumber = startTime.getDate();
|
||||
|
||||
var dayExtension = getDayExtension( dayNumber );
|
||||
|
||||
var weekNumber = getWeekNumberOfMonth();
|
||||
|
||||
document.getElementById( "advanced-repeat-dayofmonth" ).setAttribute( "label", "On the "+dayNumber+dayExtension+" of the month" );
|
||||
|
||||
if( weekNumber == 4 && isLastDayOfWeekOfMonth() )
|
||||
{
|
||||
//enable
|
||||
document.getElementById( "advanced-repeat-dayofweek" ).setAttribute( "label", getWeekNumberText( weekNumber )+" "+getDayOfWeek( dayNumber )+" of the month" );
|
||||
|
||||
document.getElementById( "advanced-repeat-dayofweek-last" ).removeAttribute( "collapsed" );
|
||||
|
||||
document.getElementById( "advanced-repeat-dayofweek-last" ).setAttribute( "label", "Last "+getDayOfWeek( dayNumber )+" of the month" );
|
||||
}
|
||||
else if( weekNumber == 4 && !isLastDayOfWeekOfMonth() )
|
||||
{
|
||||
document.getElementById( "advanced-repeat-dayofweek" ).setAttribute( "label", getWeekNumberText( weekNumber )+" "+getDayOfWeek( dayNumber )+" of the month" );
|
||||
|
||||
document.getElementById( "advanced-repeat-dayofweek-last" ).setAttribute( "collapsed", "true" );
|
||||
}
|
||||
else
|
||||
{
|
||||
//disable
|
||||
document.getElementById( "advanced-repeat-dayofweek" ).setAttribute( "collapsed", "true" );
|
||||
|
||||
document.getElementById( "advanced-repeat-dayofweek-last" ).setAttribute( "label", "Last "+getDayOfWeek( dayNumber )+" of the month" );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
** function to enable or disable the add exception button
|
||||
*/
|
||||
function updateAddExceptionButton()
|
||||
{
|
||||
//get the date from the picker
|
||||
var datePickerValue = getDateTimeFieldValue( "exception-dates-text" );
|
||||
|
||||
if( isAlreadyException( datePickerValue ) || document.getElementById( "repeat-checkbox" ).getAttribute( "checked" ) != "true" )
|
||||
{
|
||||
document.getElementById( "exception-add-button" ).setAttribute( "disabled", "true" );
|
||||
}
|
||||
else
|
||||
{
|
||||
document.getElementById( "exception-add-button" ).removeAttribute( "disabled" );
|
||||
}
|
||||
}
|
||||
|
||||
function removeSelectedExceptionDate()
|
||||
{
|
||||
var Listbox = document.getElementById( "exception-dates-listbox" );
|
||||
|
||||
var SelectedItem = Listbox.selectedItem;
|
||||
|
||||
if( SelectedItem )
|
||||
Listbox.removeChild( SelectedItem );
|
||||
}
|
||||
|
||||
function addException( dateToAdd )
|
||||
{
|
||||
if( !dateToAdd )
|
||||
{
|
||||
//get the date from the date and time box.
|
||||
//returns a date object
|
||||
var dateToAdd = getDateTimeFieldValue( "exception-dates-text" );
|
||||
}
|
||||
|
||||
if( isAlreadyException( dateToAdd ) )
|
||||
return;
|
||||
|
||||
var DateLabel = formatDate( dateToAdd );
|
||||
|
||||
//add a row to the listbox
|
||||
document.getElementById( "exception-dates-listbox" ).appendItem( DateLabel, dateToAdd.getTime() );
|
||||
|
||||
sizeToContent();
|
||||
}
|
||||
|
||||
function isAlreadyException( dateObj )
|
||||
{
|
||||
//check to make sure that the date is not already added.
|
||||
var listbox = document.getElementById( "exception-dates-listbox" );
|
||||
|
||||
for( var i = 0; i < listbox.childNodes.length; i++ )
|
||||
{
|
||||
var dateToMatch = new Date( );
|
||||
|
||||
dateToMatch.setTime( listbox.childNodes[i].value );
|
||||
if( dateToMatch.getMonth() == dateObj.getMonth() && dateToMatch.getFullYear() == dateObj.getFullYear() && dateToMatch.getDate() == dateObj.getDate() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getDayExtension( dayNumber )
|
||||
{
|
||||
switch( dayNumber )
|
||||
{
|
||||
case 1:
|
||||
case 21:
|
||||
case 31:
|
||||
return( "st" );
|
||||
case 2:
|
||||
case 22:
|
||||
return( "nd" );
|
||||
case 3:
|
||||
case 23:
|
||||
return( "rd" );
|
||||
default:
|
||||
return( "th" );
|
||||
}
|
||||
}
|
||||
|
||||
function getDayOfWeek( )
|
||||
{
|
||||
//get the day number for today.
|
||||
var startTime = getDateTimeFieldValue( "start-date-text" );
|
||||
|
||||
var dayNumber = startTime.getDay();
|
||||
|
||||
var dateStringBundle = srGetStrBundle("chrome://calendar/locale/dateFormat.properties");
|
||||
|
||||
//add one to the dayNumber because in the above prop. file, it starts at day1, but JS starts at 0
|
||||
var oneBasedDayNumber = parseInt( dayNumber ) + 1;
|
||||
|
||||
return( dateStringBundle.GetStringFromName( "day."+oneBasedDayNumber+".name" ) );
|
||||
|
||||
}
|
||||
|
||||
function getWeekNumberOfMonth()
|
||||
{
|
||||
//get the day number for today.
|
||||
var startTime = getDateTimeFieldValue( "start-date-text" );
|
||||
|
||||
var oldStartTime = startTime;
|
||||
|
||||
var thisMonth = startTime.getMonth();
|
||||
|
||||
var monthToCompare = thisMonth;
|
||||
|
||||
var weekNumber = 0;
|
||||
|
||||
while( monthToCompare == thisMonth )
|
||||
{
|
||||
startTime = new Date( startTime.getTime() - ( 1000 * 60 * 60 * 24 * 7 ) );
|
||||
|
||||
monthToCompare = startTime.getMonth();
|
||||
|
||||
weekNumber++;
|
||||
}
|
||||
|
||||
return( weekNumber );
|
||||
}
|
||||
|
||||
function isLastDayOfWeekOfMonth()
|
||||
{
|
||||
//get the day number for today.
|
||||
var startTime = getDateTimeFieldValue( "start-date-text" );
|
||||
|
||||
var oldStartTime = startTime;
|
||||
|
||||
var thisMonth = startTime.getMonth();
|
||||
|
||||
var monthToCompare = thisMonth;
|
||||
|
||||
var weekNumber = 0;
|
||||
|
||||
while( monthToCompare == thisMonth )
|
||||
{
|
||||
startTime = new Date( startTime.getTime() - ( 1000 * 60 * 60 * 24 * 7 ) );
|
||||
|
||||
monthToCompare = startTime.getMonth();
|
||||
|
||||
weekNumber++;
|
||||
}
|
||||
|
||||
if( weekNumber > 3 )
|
||||
{
|
||||
var nextWeek = new Date( oldStartTime.getTime() + ( 1000 * 60 * 60 * 24 * 7 ) );
|
||||
|
||||
if( nextWeek.getMonth() != thisMonth )
|
||||
{
|
||||
//its the last week of the month
|
||||
return( true );
|
||||
}
|
||||
}
|
||||
|
||||
return( false );
|
||||
}
|
||||
|
||||
/* FILE ATTACHMENTS */
|
||||
|
||||
function removeSelectedAttachment()
|
||||
{
|
||||
var Listbox = document.getElementById( "attachmentBucket" );
|
||||
|
||||
var SelectedItem = Listbox.selectedItem;
|
||||
|
||||
if( SelectedItem )
|
||||
Listbox.removeChild( SelectedItem );
|
||||
}
|
||||
|
||||
function addAttachment( attachmentToAdd )
|
||||
{
|
||||
if( !attachmentToAdd )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//add a row to the listbox
|
||||
document.getElementById( "attachmentBucket" ).appendItem( attachmentToAdd.url, attachmentToAdd.url );
|
||||
|
||||
sizeToContent();
|
||||
}
|
||||
|
||||
|
||||
function getWeekNumberText( weekNumber )
|
||||
{
|
||||
switch( weekNumber )
|
||||
{
|
||||
case 1:
|
||||
return( "First" );
|
||||
case 2:
|
||||
return( "Second" );
|
||||
case 3:
|
||||
return( "Third" );
|
||||
case 4:
|
||||
return( "Fourth" );
|
||||
case 5:
|
||||
return( "Last" );
|
||||
default:
|
||||
return( false );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* URL */
|
||||
function launchBrowser()
|
||||
{
|
||||
//get the URL from the text box
|
||||
var UrlToGoTo = document.getElementById( "uri-field" ).value;
|
||||
|
||||
//launch the browser to that URL
|
||||
opener.open( UrlToGoTo, "calendar-opened-window" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for filling the form, set the value of a property of a XUL element
|
||||
*
|
||||
* PARAMETERS
|
||||
* elementId - ID of XUL element to set
|
||||
* newValue - value to set property to ( if undefined no change is made )
|
||||
* propertyName - OPTIONAL name of property to set, default is "value", use "checked" for
|
||||
* radios & checkboxes, "data" for drop-downs
|
||||
*/
|
||||
|
||||
function setFieldValue( elementId, newValue, propertyName )
|
||||
{
|
||||
var undefined;
|
||||
|
||||
if( newValue !== undefined )
|
||||
{
|
||||
var field = document.getElementById( elementId );
|
||||
|
||||
if( newValue === false )
|
||||
{
|
||||
field.removeAttribute( propertyName );
|
||||
}
|
||||
else
|
||||
{
|
||||
if( propertyName )
|
||||
{
|
||||
field.setAttribute( propertyName, newValue );
|
||||
}
|
||||
else
|
||||
{
|
||||
field.value = newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for getting data from the form,
|
||||
* Get the value of a property of a XUL element
|
||||
*
|
||||
* PARAMETERS
|
||||
* elementId - ID of XUL element to get from
|
||||
* propertyName - OPTIONAL name of property to set, default is "value", use "checked" for
|
||||
* radios & checkboxes, "data" for drop-downs
|
||||
* RETURN
|
||||
* newValue - value of property
|
||||
*/
|
||||
|
||||
function getFieldValue( elementId, propertyName )
|
||||
{
|
||||
var field = document.getElementById( elementId );
|
||||
|
||||
if( propertyName )
|
||||
{
|
||||
return field[ propertyName ];
|
||||
}
|
||||
else
|
||||
{
|
||||
return field.value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for getting a date/time from the form.
|
||||
* The element must have been set up with setDateFieldValue or setTimeFieldValue.
|
||||
*
|
||||
* PARAMETERS
|
||||
* elementId - ID of XUL element to get from
|
||||
* RETURN
|
||||
* newValue - Date value of element
|
||||
*/
|
||||
|
||||
|
||||
function getDateTimeFieldValue( elementId )
|
||||
{
|
||||
var field = document.getElementById( elementId );
|
||||
return field.editDate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for filling the form, set the value of a date field
|
||||
*
|
||||
* PARAMETERS
|
||||
* elementId - ID of time textbox to set
|
||||
* newDate - Date Object to use
|
||||
*/
|
||||
|
||||
function setDateFieldValue( elementId, newDate )
|
||||
{
|
||||
// set the value to a formatted date string
|
||||
|
||||
var field = document.getElementById( elementId );
|
||||
field.value = formatDate( newDate );
|
||||
|
||||
// add an editDate property to the item to hold the Date object
|
||||
// used in onDatePick to update the date from the date picker.
|
||||
// used in getDateTimeFieldValue to get the Date back out.
|
||||
|
||||
// we clone the date object so changes made in place do not propagte
|
||||
|
||||
field.editDate = new Date( newDate );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function for filling the form, set the value of a time field
|
||||
*
|
||||
* PARAMETERS
|
||||
* elementId - ID of time textbox to set
|
||||
* newDate - Date Object to use
|
||||
*/
|
||||
|
||||
function setTimeFieldValue( elementId, newDate )
|
||||
{
|
||||
// set the value to a formatted time string
|
||||
|
||||
var field = document.getElementById( elementId );
|
||||
field.value = formatTime( newDate );
|
||||
|
||||
// add an editDate property to the item to hold the Date object
|
||||
// used in onTimePick to update the date from the time picker.
|
||||
// used in getDateTimeFieldValue to get the Date back out.
|
||||
|
||||
// we clone the date object so changes made in place do not propagte
|
||||
|
||||
field.editDate = new Date( newDate );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Take a Date object and return a displayable date string i.e.: May 5, 1959
|
||||
* :TODO: This should be moved into DateFormater and made to use some kind of
|
||||
* locale or user date format preference.
|
||||
*/
|
||||
|
||||
function formatDate( date )
|
||||
{
|
||||
return( opener.gCalendarWindow.dateFormater.getFormatedDate( date ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Take a Date object and return a displayable time string i.e.: 12:30 PM
|
||||
*/
|
||||
|
||||
function formatTime( time )
|
||||
{
|
||||
var timeString = opener.gCalendarWindow.dateFormater.getFormatedTime( time );
|
||||
return timeString;
|
||||
}
|
||||
|
||||
|
||||
function debug( Text )
|
||||
{
|
||||
dump( "\n"+ Text + "\n");
|
||||
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<!-- ***** 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): Mike Potter <mikep@oeone.com>
|
||||
-
|
||||
- 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 LGPL or the GPL. 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 ***** -->
|
||||
|
||||
<!-- DTD File with all strings specific to the calendar -->
|
||||
<!DOCTYPE window
|
||||
[
|
||||
<!ENTITY % dtd1 SYSTEM "chrome://calendar/locale/calendar.dtd" > %dtd1;
|
||||
]>
|
||||
|
||||
|
||||
<!-- This is the overlay that addes repeating information to the event and task dialogs. -->
|
||||
|
||||
<overlay id="calendarRepeatOverlay"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<!-- Repeat -->
|
||||
<vbox id="repeat-outer-box">
|
||||
<hbox id="repeat-box" align="center">
|
||||
<checkbox id="repeat-checkbox" class="proper-align" label="&newevent.repeat.label;" checked="false" oncommand="commandRepeat()"/>
|
||||
<textbox id="repeat-length-field" class="cursor-pointer" disable-controller="repeat" value="1" oninput="repeatLengthKeyDown( this )"/>
|
||||
|
||||
<menulist crop="none" oncommand="repeatUnitCommand( this )" labelnumber="labelplural" id="repeat-length-units" disable-controller="repeat">
|
||||
<menupopup>
|
||||
<menuitem label="&repeat.units.days;" labelplural="&repeat.units.days;" labelsingular="&repeat.units.days.singular;" id="repeat-length-days" value="days" />
|
||||
<menuitem label="&repeat.units.weeks;" labelplural="&repeat.units.weeks;" labelsingular="&repeat.units.weeks.singular;" id="repeat-length-weeks" value="weeks"/>
|
||||
<menuitem label="&repeat.units.months;" labelplural="&repeat.units.months;" labelsingular="&repeat.units.months.singular;" id="repeat-length-months" value="months"/>
|
||||
<menuitem label="&repeat.units.years;" labelplural="&repeat.units.years;" labelsingular="&repeat.units.years.singular;" id="repeat-length-years" value="years" />
|
||||
</menupopup>
|
||||
</menulist>
|
||||
</hbox>
|
||||
|
||||
|
||||
<hbox id="repeat-extenstions-week" disabled="true" disable-controller="repeat" collapsed="false" align="center">
|
||||
<checkbox disable-controller="repeat" class="repeat-day-class" label="Sun" id="advanced-repeat-week-0" value="0" checked="false" />
|
||||
<checkbox disable-controller="repeat" class="repeat-day-class" label="Mon" id="advanced-repeat-week-1" value="1" checked="false" />
|
||||
<checkbox disable-controller="repeat" class="repeat-day-class" label="Tue" id="advanced-repeat-week-2" value="2" checked="false" />
|
||||
<checkbox disable-controller="repeat" class="repeat-day-class" label="Wed" id="advanced-repeat-week-3" value="3" checked="false" />
|
||||
<checkbox disable-controller="repeat" class="repeat-day-class" label="Thu" id="advanced-repeat-week-4" value="4" checked="false" />
|
||||
<checkbox disable-controller="repeat" class="repeat-day-class" label="Fri" id="advanced-repeat-week-5" value="5" checked="false" />
|
||||
<checkbox disable-controller="repeat" class="repeat-day-class" label="Sat" id="advanced-repeat-week-6" value="6" checked="false" />
|
||||
</hbox>
|
||||
|
||||
|
||||
<hbox id="repeat-extenstions-month" diabled="true" collapsed="true" align="center">
|
||||
<vbox align="center">
|
||||
<radiogroup id="advanced-repeat-month" disable-controller="repeat">
|
||||
<radio disable-controller="repeat" id="advanced-repeat-dayofmonth" label="On the xth day of the month" selected="true"/>
|
||||
<radio disable-controller="repeat" id="advanced-repeat-dayofweek" label="4th Tuesday of the month"/>
|
||||
<radio disable-controller="repeat" id="advanced-repeat-dayofweek-last" label="Last Tuesday of the month" disabled="true"/>
|
||||
</radiogroup>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
<spacer height="10" />
|
||||
|
||||
<hbox align="center">
|
||||
<spacer class="repeat-left-spacer" />
|
||||
<radiogroup id="repeat-until-group" disable-controller="repeat">
|
||||
<radio id="repeat-forever-radio" disable-controller="repeat" label="&newevent.forever.label;" oncommand="commandUntil()"/>
|
||||
<hbox id="repeat-end-box" align="center">
|
||||
<vbox>
|
||||
<hbox>
|
||||
<radio id="repeat-until-radio" disable-controller="repeat" label="&newevent.until.label;" oncommand="commandUntil()"/>
|
||||
<spacer id="until-spacer"/>
|
||||
<textbox id="repeat-end-date-text" readonly="true" value="" onmousedown="prepareDatePicker('repeat-end-date-text')" popup="oe-date-picker-popup" position="before_start"/>
|
||||
<image class="event-date-button-class" id="repeat-end-date-button" onmousedown="prepareDatePicker('repeat-end-date-text')" popup="oe-date-picker-popup" position="before_start"/>
|
||||
</hbox>
|
||||
<label id="repeat-time-warning" class="warning-text-class" value="&newevent.recurend.warning;" collapsed="true"/>
|
||||
</vbox>
|
||||
</hbox>
|
||||
</radiogroup>
|
||||
</hbox>
|
||||
|
||||
<hbox align="center">
|
||||
<spacer class="repeat-left-spacer" />
|
||||
<groupbox>
|
||||
<caption label="&newevent.exceptions.caption;"/>
|
||||
<grid>
|
||||
<columns>
|
||||
<column flex="1"/>
|
||||
<column/>
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<hbox align="center">
|
||||
<textbox id="exception-dates-text" disable-controller="repeat" readonly="true" value="" onmousedown="prepareDatePicker('exception-dates-text')" popup="oe-date-picker-popup" position="before_start"/>
|
||||
<image class="event-date-button-class" disable-controller="repeat" id="exception-dates-button" onmousedown="prepareDatePicker('exception-dates-text')" popup="oe-date-picker-popup" position="before_start"/>
|
||||
</hbox>
|
||||
<button id="exception-add-button" label="&newevent.addexceptions.label;" disable-controller="repeat" oncommand="addException()"/>
|
||||
</row>
|
||||
<row>
|
||||
<listbox id="exception-dates-listbox" disable-controller="repeat" rows="4"/>
|
||||
<vbox>
|
||||
<button label="&newevent.deleteexceptions.label;" disable-controller="repeat" oncommand="removeSelectedExceptionDate()"/>
|
||||
</vbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</groupbox>
|
||||
</hbox>
|
||||
</vbox>
|
||||
<!-- /Repeat -->
|
||||
|
||||
</overlay>
|
|
@ -53,7 +53,48 @@ function calendarUnifinderInit( )
|
|||
{
|
||||
onSelectionChanged : function( EventSelectionArray )
|
||||
{
|
||||
selectSelectedEvents( );
|
||||
/*
|
||||
This no longer works since we moved to a tree
|
||||
*/
|
||||
|
||||
var SearchTree = document.getElementById( "unifinder-search-results-listbox" );
|
||||
|
||||
SearchTree.setAttribute( "suppressonselect", "true" );
|
||||
|
||||
SearchTree.treeBoxObject.selection.select( -1 );
|
||||
|
||||
if( EventSelectionArray.length > 0 )
|
||||
{
|
||||
for( i = 0; i < EventSelectionArray.length; i++ )
|
||||
{
|
||||
var SearchTreeItem = document.getElementById( "search-unifinder-treeitem-"+EventSelectionArray[i].id );
|
||||
|
||||
if( SearchTreeItem )
|
||||
{
|
||||
var Index = SearchTree.contentView.getIndexOfItem( SearchTreeItem );
|
||||
|
||||
SearchTree.treeBoxObject.ensureRowIsVisible( Index );
|
||||
|
||||
SearchTree.treeBoxObject.selection.select( Index );
|
||||
}
|
||||
}
|
||||
}
|
||||
/*SearchTree.clearSelection();
|
||||
|
||||
if( EventSelectionArray.length > 0 )
|
||||
{
|
||||
for( i = 0; i < EventSelectionArray.length; i++ )
|
||||
{
|
||||
var SearchTreeItem = document.getElementById( "search-unifinder-treeitem-"+EventSelectionArray[i].id );
|
||||
|
||||
//you need this for when an event is added. It doesn't yet exist.
|
||||
if( SearchTreeItem )
|
||||
SearchTree.addItemToSelection( SearchTreeItem );
|
||||
}
|
||||
}
|
||||
dump( "\nAllow on select now!" );
|
||||
SearchTree.removeAttribute( "suppressonselect" );
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,8 +132,6 @@ var unifinderEventDataSourceObserver =
|
|||
if( calendarEvent )
|
||||
{
|
||||
unifinderRefesh();
|
||||
|
||||
setTimeout( "selectSelectedEvents()", 1000 );
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -102,8 +141,6 @@ var unifinderEventDataSourceObserver =
|
|||
if( !gICalLib.batchMode )
|
||||
{
|
||||
unifinderRefesh();
|
||||
|
||||
setTimeout( "selectSelectedEvents()", 1000 );
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -112,8 +149,6 @@ var unifinderEventDataSourceObserver =
|
|||
if( !gICalLib.batchMode )
|
||||
{
|
||||
unifinderRefesh();
|
||||
|
||||
setTimeout( "selectSelectedEvents()", 1000 );
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -124,35 +159,7 @@ var unifinderEventDataSourceObserver =
|
|||
|
||||
};
|
||||
|
||||
function selectSelectedEvents( )
|
||||
{
|
||||
EventSelectionArray = gCalendarWindow.EventSelection.selectedEvents;
|
||||
|
||||
var SearchTree = document.getElementById( "unifinder-search-results-listbox" );
|
||||
|
||||
SearchTree.setAttribute( "suppressonselect", "true" );
|
||||
|
||||
SearchTree.treeBoxObject.selection.clearSelection();
|
||||
|
||||
if( EventSelectionArray.length > 0 )
|
||||
{
|
||||
dump( "Selected event is "+EventSelectionArray.length );
|
||||
|
||||
for( i = 0; i < EventSelectionArray.length; i++ )
|
||||
{
|
||||
var SearchTreeItem = document.getElementById( "search-unifinder-treeitem-"+EventSelectionArray[i].id );
|
||||
|
||||
if( SearchTreeItem )
|
||||
{
|
||||
var Index = SearchTree.contentView.getIndexOfItem( SearchTreeItem );
|
||||
|
||||
SearchTree.treeBoxObject.ensureRowIsVisible( Index );
|
||||
|
||||
SearchTree.treeBoxObject.selection.toggleSelect( Index );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Called when the calendar is loaded
|
||||
*/
|
||||
|
@ -244,25 +251,19 @@ function getCalendarEventFromEvent( event )
|
|||
}
|
||||
}
|
||||
|
||||
function unifinderOnSelect( event )
|
||||
{
|
||||
var tree = document.getElementById( UnifinderTreeName );
|
||||
var start = new Object();
|
||||
var end = new Object();
|
||||
var numRanges = tree.view.selection.getRangeCount();
|
||||
var ArrayOfEvents = new Array( );
|
||||
/**
|
||||
* This is attached to the onclik attribute of the events shown in the unifinder
|
||||
*/
|
||||
|
||||
for (var t=0; t<numRanges; t++){
|
||||
tree.view.selection.getRangeAt(t,start,end);
|
||||
for (var v=start.value; v<=end.value; v++){
|
||||
var treeitem = tree.treeBoxObject.view.getItemAtIndex( v );
|
||||
|
||||
var eventId = treeitem.getAttribute("eventId");
|
||||
var ThisEvent = gICalLib.fetchEvent( eventId );
|
||||
if( ThisEvent )
|
||||
ArrayOfEvents[ ArrayOfEvents.length ] = ThisEvent;
|
||||
}
|
||||
}
|
||||
function unifinderClickEvent( event )
|
||||
{
|
||||
// only change checkbox on left mouse-button click
|
||||
if( event.button != 0)
|
||||
return;
|
||||
|
||||
var tree = document.getElementById( UnifinderTreeName );
|
||||
var ThisEvent = getCalendarEventFromEvent( event );
|
||||
var ArrayOfEvents = new Array( ThisEvent );
|
||||
|
||||
gCalendarWindow.EventSelection.setArrayToSelection( ArrayOfEvents );
|
||||
|
||||
|
@ -495,7 +496,7 @@ function setUnifinderEventTreeItem( treeItem, calendarEvent )
|
|||
treeItem.setAttribute( "eventId", calendarEvent.id );
|
||||
treeItem.setAttribute( "onmouseover", "changeToolTipTextForEvent( event )" );
|
||||
treeItem.setAttribute( "ondblclick" , "unifinderDoubleClickEvent(event)" );
|
||||
//treeItem.setAttribute( "onclick" , "unifinderClickEvent(event)" );
|
||||
treeItem.setAttribute( "onclick" , "unifinderClickEvent(event)" );
|
||||
treeItem.setAttribute( "calendarevent", "true" );
|
||||
treeItem.setAttribute( "id", "search-unifinder-treeitem-"+calendarEvent.id );
|
||||
|
||||
|
@ -580,6 +581,109 @@ function refreshEventTree( eventArray )
|
|||
}
|
||||
}
|
||||
|
||||
/* This function is not used */
|
||||
function refreshEventTreeOld( eventArray )
|
||||
{
|
||||
// get the old tree children item and remove it
|
||||
|
||||
var oldTreeChildren = document.getElementById( UnifinderTreeName );
|
||||
|
||||
while( oldTreeChildren.hasChildNodes() )
|
||||
oldTreeChildren.removeChild( oldTreeChildren.lastChild );
|
||||
|
||||
// add: tree item, row, cell, box and text items for every event
|
||||
for( var index = 0; index < eventArray.length; ++index )
|
||||
{
|
||||
var calendarEvent = eventArray[ index ];
|
||||
|
||||
// make the items
|
||||
|
||||
var treeItem = document.createElement( "listitem" );
|
||||
|
||||
treeItem.setAttribute( "id", "search-unifinder-treeitem-"+calendarEvent.id );
|
||||
|
||||
treeItem.event = calendarEvent;
|
||||
|
||||
treeItem.setAttribute( "onmouseover", "changeToolTipTextForEvent( event )" );
|
||||
treeItem.setAttribute( "ondblclick" , "unifinderDoubleClickEvent(" + calendarEvent.id + ")" );
|
||||
//treeItem.setAttribute( "onclick" , "unifinderClickEvent(" + calendarEvent.id + ")" );
|
||||
|
||||
var treeCell = document.createElement( "listcell" );
|
||||
treeCell.setAttribute( "flex" , "1" );
|
||||
treeCell.setAttribute( "crop", "right" );
|
||||
|
||||
var image = document.createElement( "image" );
|
||||
image.setAttribute( "class", "unifinder-calendar-event-icon-class" );
|
||||
|
||||
if ( calendarEvent.alarm )
|
||||
{
|
||||
image.setAttribute( "alarm", "true" );
|
||||
}
|
||||
else if( calendarEvent.recur == true )
|
||||
{
|
||||
image.setAttribute( "recur", "true" );
|
||||
}
|
||||
|
||||
var treeCellHBox = document.createElement( "hbox" );
|
||||
|
||||
treeCellHBox.setAttribute( "flex" , "1" );
|
||||
treeCellHBox.setAttribute( "class", "unifinder-treecell-box-class" );
|
||||
treeCellHBox.setAttribute( "crop", "right" );
|
||||
treeCellHBox.setAttribute( "align", "center" );
|
||||
|
||||
var treeCellVBox = document.createElement( "vbox" );
|
||||
treeCellVBox.setAttribute( "crop", "right" );
|
||||
treeCellVBox.setAttribute( "flex", "1" );
|
||||
|
||||
var text1 = document.createElement( "label" );
|
||||
text1.setAttribute( "crop", "right" );
|
||||
|
||||
var text2 = document.createElement( "label" );
|
||||
text2.setAttribute( "crop", "right" );
|
||||
|
||||
// set up the display and behaviour of the tree items
|
||||
// set the text of the two text items
|
||||
|
||||
text1.setAttribute( "value" , calendarEvent.title );
|
||||
|
||||
var eventStartDate = getNextOrPreviousRecurrence( calendarEvent );
|
||||
var eventEndDate = new Date( calendarEvent.end.getTime() );
|
||||
var startDate = formatUnifinderEventDate( eventStartDate );
|
||||
var startTime = formatUnifinderEventTime( eventStartDate );
|
||||
var endTime = formatUnifinderEventTime( eventEndDate );
|
||||
|
||||
if( calendarEvent.allDay )
|
||||
{
|
||||
text2.setAttribute( "value" , "All day on " + startDate + "" );
|
||||
}
|
||||
else
|
||||
{
|
||||
text2.setAttribute( "value" , startDate + " " + startTime + " - " + endTime );
|
||||
}
|
||||
|
||||
|
||||
// add the items
|
||||
if ( calendarEvent.title )
|
||||
{
|
||||
treeCellVBox.appendChild( text1 );
|
||||
}
|
||||
treeCellVBox.appendChild( text2 );
|
||||
|
||||
treeCellHBox.appendChild( image );
|
||||
treeCellHBox.appendChild( treeCellVBox );
|
||||
|
||||
treeCell.appendChild( treeCellHBox );
|
||||
|
||||
treeItem.appendChild( treeCell );
|
||||
|
||||
oldTreeChildren.appendChild( treeItem );
|
||||
|
||||
//you need this for when an event is added.
|
||||
if( gCalendarWindow.EventSelection.isSelectedEvent( calendarEvent ) )
|
||||
oldTreeChildren.addItemToSelection( treeItem );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function unifinderClearSearchCommand()
|
||||
{
|
||||
|
|
|
@ -440,56 +440,31 @@ function toDoUnifinderItemUpdate( calendarToDo )
|
|||
}
|
||||
|
||||
|
||||
function contextChangeProgress( event, Progress )
|
||||
function contextChangePriority( Priority, event )
|
||||
{
|
||||
var tree = document.getElementById( ToDoUnifinderTreeName );
|
||||
|
||||
if (tree.treeBoxObject.selection.count > 0)
|
||||
{
|
||||
var treeitem = tree.treeBoxObject.view.getItemAtIndex( tree.currentIndex );
|
||||
if(treeitem)
|
||||
{
|
||||
var todoId = treeitem.getAttribute("toDoID");
|
||||
var ToDoItem = gICalLib.fetchTodo( todoId );
|
||||
ToDoItem.percent = Progress;
|
||||
|
||||
if( Progress == 0 )
|
||||
{
|
||||
ToDoItem.completed.clear();
|
||||
ToDoItem.status = ToDoItem.ICAL_STATUS_NEEDSACTION;
|
||||
}
|
||||
else if( Progress > 0 && Progress < 100 )
|
||||
{
|
||||
ToDoItem.completed.clear();
|
||||
ToDoItem.status = ToDoItem.ICAL_STATUS_INPROCESS;
|
||||
}
|
||||
if( Progress == 100 )
|
||||
{
|
||||
var completedDate = new Date();
|
||||
|
||||
ToDoItem.completed.year = completedDate.getYear() + 1900;
|
||||
ToDoItem.completed.month = completedDate.getMonth();
|
||||
ToDoItem.completed.day = completedDate.getDate();
|
||||
ToDoItem.status = ToDoItem.ICAL_STATUS_COMPLETED;
|
||||
}
|
||||
|
||||
gICalLib.modifyTodo( ToDoItem );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function contextChangePriority( event, Priority )
|
||||
{
|
||||
var tree = document.getElementById( ToDoUnifinderTreeName );
|
||||
|
||||
if (tree.treeBoxObject.selection.count > 0)
|
||||
{
|
||||
var treeitem = tree.treeBoxObject.view.getItemAtIndex( tree.currentIndex );
|
||||
if(treeitem)
|
||||
{
|
||||
var todoId = treeitem.getAttribute("toDoID");
|
||||
var ToDoItem = gICalLib.fetchTodo( todoId );
|
||||
var ToDoItem = gICalLib.fetchToDo( todoId );
|
||||
ToDoItem.priority = Priority;
|
||||
gICalLib.modifyTodo( ToDoItem );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function contextChangePriority( Priority, event )
|
||||
{
|
||||
if (tree.treeBoxObject.selection.count > 0)
|
||||
{
|
||||
var treeitem = tree.treeBoxObject.view.getItemAtIndex( tree.currentIndex );
|
||||
if(treeitem)
|
||||
{
|
||||
var todoId = treeitem.getAttribute("toDoID");
|
||||
var ToDoItem = gICalLib.fetchToDo( todoId );
|
||||
ToDoItem.priority = Priority;
|
||||
gICalLib.modifyTodo( ToDoItem );
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче