1 <?xml version=
"1.0" encoding=
"UTF-8"?>
2 <!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns=
"http://www.w3.org/1999/xhtml">
6 <title>Coming Next
</title>
8 <style type=
"text/css">
9 /* The following classes can be modified by widget settings */
10 .background { color:#ffffff; background-color:#
000000 }
11 .backgroundFullscreen { color:#ffffff; background-color:#
000000 }
14 .today { color:#ff0000 }
15 .tomorrow { color:#
0000ff }
17 .now { color:#ff00ff }
19 .icon { width:
15px; height:
15px }
20 .overdue { color:#ffff00 }
21 .calendar1 { background-color:#
0757cf }
22 .calendar2 { background-color:#
579f37 }
23 .calendar3 { background-color:#ff9f07 }
24 .calendar4 { background-color:#af8fef }
25 .calendar5 { background-color:#
57afbf }
26 .calendar6 { background-color:#
9fdf57 }
29 <script type=
"text/javascript" src=
"localizedTextStrings.js" charset=
"utf-8" />
32 // valid types for the config object are 'Int', 'Bool', 'String', 'Enum', 'UID', 'Array'
34 monthRange: { Type: 'Int', Default:
2, Value:
2,},
35 includeTodos: { Type: 'Bool', Default: true, Value: true,},
36 useBackgroundImage: { Type: 'Bool', Default: true, Value: true,},
37 backgroundImageLocation: { Type: 'Enum', Default: 'internal', Value: 'internal', ValidValues: ['internal', 'external']},
38 showCombinedDateTime: { Type: 'Bool', Default: false, Value: false,},
39 showLocation: { Type: 'Bool', Default: true, Value: true,},
40 showTodayAsText: { Type: 'Bool', Default: true, Value: true,},
41 todayText: { Type: 'String', Default: getLocalizedText('settings.default.todayText'), Value: getLocalizedText('settings.default.todayText'),},
42 tomorrowText: { Type: 'String', Default: getLocalizedText('settings.default.tomorrowText'), Value: getLocalizedText('settings.default.tomorrowText'),},
43 showNowAsText: { Type: 'Bool', Default: true, Value: true,},
44 nowText: { Type: 'String', Default: getLocalizedText('settings.default.nowText'), Value: getLocalizedText('settings.default.nowText'),},
45 markOverdueTodos: { Type: 'Bool', Default: true, Value: true,},
46 overdueText: {Type: 'String', Default: getLocalizedText('settings.default.overdueText'), Value: getLocalizedText('settings.default.overdueText'),},
47 dateSeparator: { Type: 'String', Default: getLocalizedText('settings.default.dateSeparator'), Value: getLocalizedText('settings.default.dateSeparator'),},
48 dateFormat: { Type: 'Enum', Default: 'auto', Value: 'auto', ValidValues: ['auto', 'DDMM', 'MMDD'],},
49 weekDayLength: { Type: 'Int', Default:
2, Value:
2,},
50 updateDataInterval: { Type: 'Int', Default:
5, Value:
5,},
51 calendarApp: { Type: 'UID', Default:
0x10005901, Value:
0x10005901,},
52 eventsPerWidget: { Type: 'Int', Default:
4, Value:
4,},
53 showNothingText: { Type: 'Bool', Default: true, Value: true,},
54 nothingText: { Type: 'String', Default: getLocalizedText('settings.default.nothingText'), Value: getLocalizedText('settings.default.nothingText'),},
55 enableDaylightSaving: { Type: 'Bool', Default: true, Value: true,},
56 daylightSavingOffset: { Type: 'Int', Default:
1, Value:
1,},
57 hideWidgetOnCalendarOpen: { Type: 'Bool', Default: false, Value: false,},
58 showCalendarIndicator: { Type: 'Bool', Default: true, Value: true,},
59 excludedCalendars: { Type: 'Array', Default: [], Value: [],},
60 enableLogging: { Type: 'Bool', Default: false, Value: false,},
61 cssStyle_background: { Type: 'String', Default: 'color:#ffffff; background-color:#
000000', Value: 'color:#ffffff; background-color:#
000000',},
62 cssStyle_backgroundFullscreen: { Type: 'String', Default: 'color:#ffffff; background-color:#
000000', Value: 'color:#ffffff; background-color:#
000000',},
63 cssStyle_weekDay: { Type: 'String', Default: '', Value: '',},
64 cssStyle_date: { Type: 'String', Default: '', Value: '',},
65 cssStyle_today: { Type: 'String', Default: 'color:#ff0000', Value: 'color:#ff0000',},
66 cssStyle_tomorrow: { Type: 'String', Default: 'color:#
0000ff', Value: 'color:#
0000ff',},
67 cssStyle_time: { Type: 'String', Default: '', Value: '',},
68 cssStyle_now: { Type: 'String', Default: 'color:#ff00ff', Value: 'color:#ff00ff',},
69 cssStyle_description: { Type: 'String', Default: '', Value: '',},
70 cssStyle_icon: { Type: 'String', Default: 'width:
15px; height:
15px', Value: 'width:
15px; height:
15px',},
71 cssStyle_overdue: { Type: 'String', Default: 'color:#ffff00', Value: 'color:#ffff00',},
72 cssStyle_calendar1: { Type: 'String', Default: 'background-color:#
0757cf', Value: 'background-color:#
0757cf',},
73 cssStyle_calendar2: { Type: 'String', Default: 'background-color:#
579f37', Value: 'background-color:#
579f37',},
74 cssStyle_calendar3: { Type: 'String', Default: 'background-color:#ff9f07', Value: 'background-color:#ff9f07',},
75 cssStyle_calendar4: { Type: 'String', Default: 'background-color:#af8fef', Value: 'background-color:#af8fef',},
76 cssStyle_calendar5: { Type: 'String', Default: 'background-color:#
57afbf', Value: 'background-color:#
57afbf',},
77 cssStyle_calendar6: { Type: 'String', Default: 'background-color:#
9fdf57', Value: 'background-color:#
9fdf57',},
82 //-------------------------------------------------------
83 // Nothing of interest from here on...
84 //-------------------------------------------------------
85 var panelNum =
0; // use
1 for second panel
87 var versionURL =
"http://comingnext.sourceforge.net/version.xml";
88 var calendarService = null;
89 var cacheEntriesHtml = [];
90 var months_translated = [];
93 var mode =
0; //
0 = homescreen,
1 = fullscreen,
2 = settings,
3 = about,
4 = check for update
95 var settingsCalEntryId = null;
96 var settingsCache = null;
97 var notificationRequests = new Array();
98 var calendarList = [];
99 var calendarColors = [];
100 var updateTimer = null;
101 var screenRotationTimer = null;
102 var lastUpdateTime = now; // last time we updated the display
103 var lastReloadTime = null; // last time we fetched calendar data
104 var reloadInterval =
6 *
60 *
60 *
1000; // =
6 hours; time interval for reloading calendar data
105 var errorOccured = false;
106 var entryLists = null; // stores all fetched calendar entries until data is refreshed
108 // vars for daylight saving time
109 var summertime = false; // true, if current date is in summer, false if in winter
110 var daylightSavingDates = new Object(); // caches calculated DST winter and summer time shift dates
112 // this is a list of data fields a calendar event can have
126 function isLeapYear( year ) {
127 if (( year %
4 ==
0 && year %
100 !=
0 ) || year %
400 ==
0 )
133 function calcLeapYear(year, days)
135 if (isLeapYear(year))
141 function subToSunday(myDate, year, days, prevMonthDays)
143 for (i = myDate.getDay(); i
> 0 ;i--)
145 days -= prevMonthDays;
146 days = isLeapYear(year) ? --days : days;
150 function isSummertime(curDate)
155 // if we already calculated DST summer and winter time dates for this year, use cached values
156 var dst = daylightSavingDates[curDate.getFullYear()];
158 var thisYearS = new Date(curDate.getFullYear(),
3,
0,
0,
0,
0 );
159 var thisYearW = new Date(curDate.getFullYear(),
10,
0,
0,
0,
0 );
160 var nextYearS = new Date(curDate.getFullYear() +
1,
3,
0,
0,
0,
0 );
161 var nextYearW = new Date(curDate.getFullYear() +
1,
10,
0,
0,
0,
0 );
163 thisYearSDays = nextYearSDays =
90;
164 thisYearWDays = nextYearWDays =
304;
166 thisYearSDays = calcLeapYear(curDate.getFullYear(), thisYearSDays);
167 thisYearWDays = calcLeapYear(curDate.getFullYear(), thisYearWDays);
168 nextYearSDays = calcLeapYear(curDate.getFullYear() +
1, nextYearSDays);
169 nextYearWDays = calcLeapYear(curDate.getFullYear() +
1, nextYearWDays);
171 thisYearSDays = subToSunday(thisYearS, curDate.getFullYear(), thisYearSDays,
59);
172 thisYearWDays = subToSunday(thisYearW, curDate.getFullYear(), thisYearWDays,
273);
173 nextYearSDays = subToSunday(nextYearS, curDate.getFullYear() +
1, nextYearSDays,
59);
174 nextYearWDays = subToSunday(nextYearW, curDate.getFullYear() +
1, nextYearWDays,
273);
177 Summer: new Date (curDate.getFullYear(),
03-
1, thisYearSDays,
2,
0,
0),
178 Winter: new Date (curDate.getFullYear(),
10-
1, thisYearWDays,
2,
0,
0),
180 daylightSavingDates[curDate.getFullYear()] = dst;
183 if (dst.Summer < curDate)
185 if (dst.Winter < curDate)
187 if (summer && !winter)
193 function error(message)
195 console.info('Error: ' + message);
196 document.getElementById(
"calendarList").innerHTML = 'Error: ' + message;
197 document.getElementById(
"fullscreenCalendarList").innerHTML = 'Error: ' + message;
199 document.onclick = null;
202 function areDatesEqual(date1, date2)
204 return (date1.getFullYear() == date2.getFullYear() &&
205 date1.getMonth() == date2.getMonth() &&
206 date1.getDate() == date2.getDate());
209 function isTomorrow(date)
211 // tommorow = now +
1 day
212 // ToDo: some days can be shorter as
24 hours(daylight saving change day)
213 return areDatesEqual(date, new Date (now.getTime() +
24*
60*
60*
1000));
216 function isToday(date)
218 return areDatesEqual(date, now);
221 function collectLocales()
223 var tmpyear =
2000 + panelNum;
226 if (months_translated.length
> 0)
228 for (month =
0; month <
12; month++) {
229 var startDate = new Date(tmpyear, month,
15);
231 var item = new Object();
232 item.Type =
"DayEvent";
233 item.StartTime = startDate;
234 item.Summary =
"__temp" + month;
236 var criteria = new Object();
237 criteria.Type =
"CalendarEntry";
238 criteria.Item = item;
241 var result = calendarService.IDataSource.Add(criteria);
242 if (result.ErrorCode)
243 error(result.ErrorMessage);
245 error(
"collectLocales: " + e + ', line ' + e.line);
249 var startTime = new Date(tmpyear,
0,
1);
250 var endTime = new Date(tmpyear,
11,
31);
251 var listFiltering = {
252 Type:'CalendarEntry',
254 StartRange: startTime,
256 SearchText: '__temp',
260 var result = calendarService.IDataSource.GetList(listFiltering);
261 if (result.ErrorCode)
262 throw(result.ErrorMessage);
263 var list = result.ReturnValue;
265 error(e + ', line ' + e.line);
268 var ids = new Array();
274 while (list && (entry = list.getNext()) != undefined) {
275 dateArr = (entry.StartTime + '').replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
276 var day = dateArr[
1];
277 var month = dateArr[
2];
278 var year = dateArr[
3];
280 // make sure month is set properly
281 if (isNaN(parseInt(day))) {
285 } else if (isNaN(parseInt(year))) {
291 log(entry.StartTime + ' -
> ' + month + ' ' + counter);
292 ids[counter] = entry.id;
293 months_translated[month] = counter +
1;
297 error(e + ', line ' + e.line);
302 var criteria = new Object();
303 criteria.Type =
"CalendarEntry";
308 var result = calendarService.IDataSource.Delete(criteria);
309 if (result.ErrorCode)
310 throw(result.ErrorMessage);
312 error('deleting temp calendar entries:' + e + ', line ' + e.line);
317 function requestNotification()
319 var criteria = new Object();
320 criteria.Type =
"CalendarEntry";
321 criteria.Filter = new Object();
322 for(var i=
0; i < calendarList.length; i++) {
323 criteria.Filter.CalendarName = calendarList[i];
325 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria, callback);
326 if (notificationRequest.ErrorCode)
327 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
328 notificationRequests.push(notificationRequest);
330 error(
"requestNotification: " + e + ', line ' + e.line);
334 var criteria2 = new Object();
335 criteria2.Type =
"CalendarEntry";
336 criteria2.Filter = new Object();
337 criteria2.Filter.LocalIdList = new Array();
338 criteria2.Filter.LocalIdList[
0] = settingsCalEntryId;
340 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria2, settingsCallback);
341 if (notificationRequest.ErrorCode)
342 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
343 notificationRequests.push(notificationRequest);
345 error(
"requestNotification: " + e + ', line ' + e.line);
349 function cancelNotification()
351 for(var i=
0; i < notificationRequests.length; i++) {
353 var result = calendarService.IDataSource.Cancel(notificationRequests[i]);
354 if (result.ErrorCode)
355 error('cancelNotification failed with error code ' + result.ErrorCode);
357 error(
"cancelNotification: " + e + ', line ' + e.line);
362 function callback(transId, eventCode, result)
364 log(
"callback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
365 lastReloadTime = null; // force calendar data reload on next update
369 function settingsCallback(transId, eventCode, result)
371 log(
"settingsCallback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
375 function parseDate(dateString)
378 Dates my look very differently. Also keep in mind that the names are localized!!! These are the possibilities depending on the users date format setting:
379 Wednesday,
26 August,
2009 24:
00:
00
380 Wednesday,
26 August,
2009 12:
00:
00 am
381 Wednesday, August
26,
2009 12:
00:
00 am
382 Wednesday,
2009 August,
26 12:
00:
00 am
383 Wednesday,
2009 August,
28 8.00.00 pm
384 Wednesday,
2009 August,
28 08:
00:
00 PM
388 if (dateString ==
"" || dateString == null || dateString == undefined)
390 if (dateString instanceof Date) {
391 // we already have a date object, no need to parse string here
395 var dateArr = (dateString + '').replace(/,/g, '').replace(/\./g, ':').replace(/ /g, ' ').split(' ');
396 if (dateArr.length !=
5 && dateArr.length !=
6)
400 var weekDay = dateArr[
0];
401 var day = dateArr[
1];
402 var month = dateArr[
2];
403 var year = dateArr[
3];
404 // make sure month is set properly
405 if (isNaN(parseInt(day))) {
411 if (isNaN(parseInt(year))) {
416 // make sure day and year are set properly
417 if (Number(day)
> Number(year)) {
422 month = months_translated[month];
425 var timeArr = dateArr[
4].split(':');
426 if (timeArr.length !=
3)
428 var hours = Number(timeArr[
0]);
429 var minutes = Number(timeArr[
1]);
430 var seconds = Number(timeArr[
2]);
431 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'pm' && hours <
12)
433 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'am' && hours ==
12)
436 result = new Date(year, month -
1, day, hours, minutes, seconds);
439 // take care of daylight saving time
440 if (config['enableDaylightSaving'].Value) {
442 // determine if date is in summer or winter time
443 var dateSummerTime = isSummertime(result);
445 // work around bug in Nokias calendar api resulting in dates within a different DST to be off by
1 hour
446 if (summertime && !dateSummerTime) {
447 result = new Date(result.getTime() -
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // -
1 hour
448 log('parseDate(): fixing time -
1h: ' + result);
450 else if (!summertime && dateSummerTime) {
451 result = new Date(result.getTime() +
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // +
1 hour
452 log('parseDate(): fixing time +
1h: ' + result);
459 // returns a short date as string (
"31.12" or
"12.31") based on the format string which should look like
"Wednesday, 26 August, 2009 12:00:00 am"
460 function formatDate(date, format)
462 var day = date.getDate().toString();
463 var month = (date.getMonth() +
1).toString();
464 while (day.length <
2) { day = '
0' + day; }
465 while (month.length <
2) { month = '
0' + month; }
467 if (config['showTodayAsText'].Value && isToday(date))
468 return '
<span class=
"today">' + config['todayText'].Value + '
</span>';
469 if (config['showTodayAsText'].Value && isTomorrow(date))
470 return '
<span class=
"tomorrow">' + config['tomorrowText'].Value + '
</span>';
472 if (format instanceof Date) {
473 // we don't know how to format this
474 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
475 return day + config['dateSeparator'].Value + month;
477 return month + config['dateSeparator'].Value + day;
479 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
480 if (dateArr.length !=
5 && dateArr.length !=
6) {
481 // we don't know how to format this
482 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
483 return day + config['dateSeparator'].Value + month;
485 return month + config['dateSeparator'].Value + day;
489 if (config['dateFormat'].Value == 'MMDD')
491 else if (config['dateFormat'].Value == 'DDMM')
494 // config['dateFormat'].Value == 'auto', try to detect system setting
496 var day_ = dateArr[
1];
497 var month_ = dateArr[
2];
498 var year_ = dateArr[
3];
499 // make sure month is set properly
500 if (isNaN(parseInt(day_))) {
505 } else if (isNaN(parseInt(year_))) {
511 // make sure day and year are set properly
512 if (Number(day_)
> Number(year_))
517 return day + config['dateSeparator'].Value + month;
519 return month + config['dateSeparator'].Value + day;
522 function formatTime(date)
524 // date is a Date() object
525 date.setSeconds(
0); // we don't care about seconds
526 var time = date.toLocaleTimeString().replace(/[\.:]
00/, ''); // remove seconds from string
527 if (time.replace(/\./, ':').split(':')[
0].length <
2)
529 if (config['showNowAsText'].Value && date.getTime() == now.getTime())
530 time = '
<span class=
"now">' + config['nowText'].Value + '
</span>';
534 function updateData()
541 // check if we got additional or less calendars since our last update
542 var newCalendarList = listCalendars();
543 if (newCalendarList.length != calendarList.length) {
544 calendarList = newCalendarList;
545 updateCalendarColors();
546 cancelNotification();
547 requestNotification();
548 lastReloadTime = null; // force calendar data reload on this update
553 // only reload calendar data every
6 hours, visual updates occure more often
554 if (!lastReloadTime || now.getTime() - lastReloadTime.getTime()
> reloadInterval) {
555 log('updateData(): reloading calendar data');
557 // meetings have time
558 // note: anniveraries have a start time of
12:
00am. So since we want to include them, we have to query the whole day and check if events have passed later
559 summertime = isSummertime(now); // cache summer time info for today
560 var meetingList = [];
561 for(var i=
0; i < calendarList.length; i++) {
562 // ignore excluded calendars
563 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
565 var meetingListFiltering = {
566 Type:'CalendarEntry',
568 CalendarName: calendarList[i],
569 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
570 EndRange: (new Date(now.getFullYear(), now.getMonth() + config['monthRange'].Value, now.getDate(),
0,
0,
0))
573 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
574 if (meetingResult.ErrorCode !=
0)
575 throw(
"Error fetching calendar data: " + meetingResult.ErrorCode + ': ' + meetingResult.ErrorMessage);
576 var list = meetingResult.ReturnValue;
577 meetingList = meetingList.concat(listToArray(list, calendarList[i]));
579 log(
"updateData(): meetingList.sort()");
580 meetingList.sort(sortCalendarEntries);
582 // todos don't, they start on
00:
00 hrs., but should be visible anyway
583 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
584 if (config['includeTodos'].Value) {
585 var todayTodoList = [];
586 for(var i=
0; i < calendarList.length; i++) {
587 // ignore excluded calendars
588 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
590 var todayTodoListFiltering = {
591 Type:'CalendarEntry',
593 CalendarName: calendarList[i],
595 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
596 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
599 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
600 var list = todayTodoResult.ReturnValue;
601 todayTodoList = todayTodoList.concat(listToArray(list, calendarList[i]));
603 log(
"updateData(): todayTodoList.sort()");
604 todayTodoList.sort(sortCalendarEntries);
605 entryLists = [todayTodoList, meetingList];
607 entryLists = [meetingList];
609 lastReloadTime = new Date();
611 error('loading Calendar items list:' + e + ', line ' + e.line);
621 var fontsize = 'normal';
623 if (config['eventsPerWidget'].Value ==
3) {
625 changeCssClass('.icon', 'width:
20px; height:
20px');
627 else if (config['eventsPerWidget'].Value ==
5) {
629 changeCssClass('.icon', 'width:
10px; height:
10px');
631 else if (config['eventsPerWidget'].Value ==
6) {
633 changeCssClass('.icon', 'width:
8px; height:
8px');
637 changeCssClass('.icon', config['cssStyle_icon'].Value);
638 var entriesHtml = '
<table style=
"font-size:' + fontsize + ';">';
642 max = (panelNum +
1) * config['eventsPerWidget'].Value;
644 max =
30; // we can display a lot more events in fullscreen mode
646 if (config['enableLogging'].Value) {
648 for (var i=
0; i < entryLists.length; i++) {
649 listinfo = listinfo +
" " + entryLists[i].length;
650 var entrieslist =
"";
651 for (var j=
0; j < entryLists[i].length; j++) {
652 entrieslist += entryLists[i][j].Summary +
", ";
654 log(
"updateData(): entrieslist: " + entrieslist);
656 log(
"updateData(): inner loop, " + entryLists.length +
" lists, [" + listinfo +
"] entries");
659 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
660 for (var i=
0; counter < max && i < entryLists.length; i++) {
661 for (var j=
0; (counter < max) && (j < entryLists[i].length); j++) {
662 entry = entryLists[i][j];
665 // output event info for debugging
666 var entryInfo =
"event: ";
667 for(var k=
0; k < entryFields.length; ++k) {
668 if (entry[entryFields[k]] != undefined) {
669 entryInfo += entryFields[k] +
"=" + entry[entryFields[k]] +
",";
674 // we don't want ToDos when includeTodos == false or when they are completed
675 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !config['includeTodos'].Value)) {
676 log('skipping ' + entry.id );
681 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
682 if (eventIds[entry.id] ==
1 && entry.Type == 'ToDo') {
683 log('skipped (already included) ' + entry.id);
687 eventIds[entry.id] =
1;
689 // summary can be undefined!
690 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
691 if (entry.Location != '' && entry.Location != undefined && config['showLocation'].Value)
692 Summary += ', ' + entry.Location;
694 // fix by yves: determine start and end dates/times
695 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
696 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
698 // there can be ToDos that have no date at all!
699 if (entry.Type == 'ToDo' && entry.EndTime == null)
700 entryDate =
""; // this will cause parseDate(entryDate) to return null;
702 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
704 // Convert date/time string to Date object
705 var date = parseDate(entryDate);
706 log('date: ' + date);
707 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
708 log('endDate: ' + endDate);
710 // check if meeting event has already passed
711 if (entry.Type == 'Meeting') {
712 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
713 if (now.getTime()
> compareTime) {
714 log('skipping Meeting (already passed) ' + entry.id);
716 eventIds[entry.id] =
0;
721 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
722 if (entry.Type == 'Anniversary') {
723 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
724 if (date.getTime() < tmp.getTime()) {
725 log('skipping Anniversary (already passed) ' + entry.id);
727 eventIds[entry.id] =
0;
732 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
733 if (entry.Type == 'DayEvent' && endDate != null) {
734 endDate.setMinutes(endDate.getMinutes() -
1);
735 log('fixing DayEvent endDate: ' + endDate);
736 if (now.getTime()
> endDate.getTime()) {
737 log('event already passed ' + entry.id);
739 eventIds[entry.id] =
0;
744 // check if the event is currently taking place
745 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
746 // check if we are between start and endtime
747 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
748 date = now; // change appointment date/time to now
749 log('event is currently taking place: ' + date);
753 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
754 if (mode ==
0 && panelNum
> 0 && counter < panelNum * config['eventsPerWidget'].Value +
1) {
755 log('skipping (already in first widget) ' + entry.id);
759 // mark overdue todos
761 if (entry.Type == 'ToDo' && date != null) {
762 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
0,
0,
0);
763 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
764 if (tmp1.getTime() < tmp2.getTime()) {
769 // generate html output
770 entriesHtml += '
<tr>';
771 if (config['showCalendarIndicator'].Value && calendarList.length - config['excludedCalendars'].Value.length
> 1) {
772 entriesHtml += '
<td><span class=
"calendar' + calendarColors[entry.CalendarName] + '"> </span></td>';
774 entriesHtml += '
<td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
776 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
777 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
779 var weekDay = date.toLocaleDateString().substr(
0,config['weekDayLength'].Value);
780 var time = formatTime(date);
781 var dateStr = formatDate(date, entryDate);
782 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
783 dateStr = '
<span class=
"overdue">' + config['overdueText'].Value + '
</span>';
784 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
785 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
786 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
787 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
789 entriesHtml += '
<td class=
"weekDay" width=
"1px">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
790 } else if (entry.Type == 'Meeting') {
791 if (config['showCombinedDateTime'].Value) {
793 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
794 else if (isTomorrow(date))
795 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
797 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
799 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
800 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
802 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
806 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
809 entriesHtml += '
</table>';
810 if (config['showNothingText'].Value && entriesHtml == '
<table></table>') {
811 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
812 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '
</div>';
814 if (cacheEntriesHtml != entriesHtml) {
816 document.getElementById('calendarList').innerHTML = entriesHtml;
818 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
819 cacheEntriesHtml = entriesHtml;
822 lastUpdateTime = new Date();
824 error('displaying list:' + e + ', line ' + e.line);
829 // called by handleOnShow() and onResize events
830 function updateScreen()
832 log('updateScreen()');
834 // check if opening fullscreen
835 if( window.innerHeight
> 91 && mode ==
0) {
837 cacheEntriesHtml = '';
838 document.getElementById('body').style.backgroundImage =
"";
841 else if (window.innerHeight <=
91 && mode !=
0) {
843 cacheEntriesHtml = '';
848 updateHomescreen(); // check for screen rotation
853 function handleOnShow()
857 var time = new Date();
858 if (time.getTime() - lastUpdateTime.getTime()
> config['updateDataInterval'].Value *
60 *
1000) {
859 log('updateScreen(): force updateData() because last update was too long ago (' + (time.getTime() - lastUpdateTime.getTime()) /
1000 + 's)');
862 setUpdateTimer(); // reinitialize update timer
866 function launchCalendar()
869 widget.openApplication(config['calendarApp'].Value,
"");
870 if (config['hideWidgetOnCalendarOpen'].Value)
873 error('starting Calendar App');
880 log('New widget instance starting up...');
883 // call calendar service
884 if (device !=
"undefined")
885 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
887 throw('device object does not exist');
889 error('loading Calendar service: ' + e + ', line ' + e.line + '
<br /><a onclick=
"widget.openURL(\'http://comingnext.sf.net/help\'); return false;" href=
"http://comingnext.sf.net/help">' + getLocalizedText('menu.help') + '
</a>');
893 calendarList = listCalendars();
895 updateCalendarColors();
898 requestNotification();
899 document.getElementById(
"settingsTitle").innerHTML = getLocalizedText('menu.settings');
901 if (window.innerHeight
> 91) {
902 mode =
0; // we're starting fullscreen, we set mode to homescreen in order to let updateScreen() do all the work for us
907 log(
"init(): updateScreen()");
909 if (config['useBackgroundImage'].Value)
910 // check for screen rotation every
1 secs
911 screenRotationTimer = window.setInterval('checkOrientation()',
1000 *
1);
913 // call updateScreen() when widget changes from background to forground
914 window.widget.onshow = handleOnShow;
916 log(
"init(): finished...");
919 function checkOrientation()
923 updateHomescreen(); // check for screen rotation
926 function setUpdateTimer()
928 updateTimer = window.setInterval('updateTimerCallback()',
1000 *
60 * config['updateDataInterval'].Value);
931 function clearUpdateTimer()
933 window.clearInterval(updateTimer);
936 function updateTimerCallback()
938 log(
"updateTimerCallback()");
942 function createMenu()
944 window.menu.setLeftSoftkeyLabel(
"",null);
945 window.menu.setRightSoftkeyLabel(
"",null);
947 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
948 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
949 var menuHelp = new MenuItem(getLocalizedText('menu.help'), id++);
950 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
951 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
952 menuSettings.onSelect = showSettings;
953 menuAbout.onSelect = showAbout;
954 menuCallApp.onSelect = launchCalendar;
955 menuUpdate.onSelect = showUpdate;
956 menuHelp.onSelect = showHelp;
958 window.menu.append(menuCallApp);
959 window.menu.append(menuSettings);
960 window.menu.append(menuHelp);
961 window.menu.append(menuUpdate);
962 window.menu.append(menuAbout);
965 function showSettings()
969 document.getElementById(
"settingsView").style.display =
"block";
970 document.onclick = null;
972 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
974 for (var key in config) {
975 if (config[key].Type == 'String')
976 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
977 else if (config[key].Type == 'Int') {
978 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
979 if (config[key].Value <
0 || isNaN(config[key].Value))
980 config[key].Value = config[key].Default;
982 else if (config[key].Type == 'Bool')
983 config[key].Value = document.forms[
0].elements[
"settings." + key].checked;
984 else if (config[key].Type == 'UID') {
985 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
986 if (isNaN(config[key].Value))
987 config[key].Value = config[key].Default;
989 else if (config[key].Type == 'Enum') {
990 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
991 if (config[key].ValidValues.indexOf(config[key].Value) == -
1)
992 config[key].Value = config[key].Default;
994 else if (config[key].Type == 'Array') {
995 if (key == 'excludedCalendars') {
996 config[key].Value = new Array();
997 for(var i=
0; i < calendarList.length; i++) {
998 var element = document.forms[
0].elements[
"settings." + key +
"." + calendarList[i]];
999 if (element != null && element.checked == false)
1000 config[key].Value.push(calendarList[i]);
1013 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
1019 var settingsHtml = '
<form>';
1020 for (var key in config) {
1021 if (config[key].Type == 'String') {
1023 if (key.substring(
0,
9) ==
"cssStyle_")
1024 prefix = getLocalizedText('settings.cssStyle_prefix');
1025 settingsHtml += '
<table><tr><td>' + prefix + getLocalizedText('settings.name.' + key) + '
<br /><input class=
"textInput" name=
"settings.' + key + '" type=
"text" value=
"' + config[key].Value + '" /></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1027 else if (config[key].Type == 'Int')
1028 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><input class=
"textInput" name=
"settings.' + key + '" type=
"text" value=
"' + config[key].Value + '" /></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1029 else if (config[key].Type == 'Bool')
1030 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><input name=
"settings.' + key + '" type=
"checkbox" value=
"true" ' + (config[key].Value ? '
checked=
"checked"' : '') + '
/></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1031 else if (config[key].Type == 'UID')
1032 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><input class=
"textInput" name=
"settings.' + key + '" type=
"text" value=
"0x' + config[key].Value.toString(16) + '" /></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1033 else if (config[key].Type == 'Enum') {
1034 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><select name=
"settings.' + key + '" size=
"1">';
1035 for(var i =
0; i < config[key].ValidValues.length; i++)
1036 settingsHtml += '
<option value=
"' + config[key].ValidValues[i] + '"' + (config[key].Value == config[key].ValidValues[i] ? '
selected=
"selected"' : '') + '
>' + getLocalizedText('settings.validValues.' + key + '.' + config[key].ValidValues[i]) + '
</option>';
1037 settingsHtml += '
</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1039 else if (config[key].Type == 'Array') {
1040 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br />';
1041 if (key == 'excludedCalendars') {
1042 for(var i=
0; i < calendarList.length; i++) {
1043 var checked = '
checked=
"checked"';
1044 if (config[key].Value.indexOf(calendarList[i]) != -
1)
1046 settingsHtml += '
<input name=
"settings.' + key + '.' + calendarList[i] + '" type=
"checkbox" value=
"' + calendarList[i] + '" ' + checked + '
/> ' + calendarList[i] + '
<br />';
1049 settingsHtml += '
</td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1052 settingsHtml += '
<input name=
"reset" type=
"button" value=
"' + getLocalizedText('settings.restoreDefaults') + '" onclick=
"javascript:restoreDefaultSettings();showSettings();" />';
1053 settingsHtml += '
</form>';
1054 document.getElementById(
"settingsList").innerHTML = settingsHtml;
1057 function changeCssClass(classname, properties)
1059 for(var i =
0; i < document.styleSheets[
0]['cssRules'].length; i++)
1061 if (document.styleSheets[
0]['cssRules'][i].selectorText == classname) {
1062 document.styleSheets[
0].deleteRule(i);
1063 document.styleSheets[
0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[
0]['cssRules'].length);
1069 function updateCssClasses()
1071 for(var key in config) {
1072 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
1076 function getSettingsCalEntryId()
1078 if (settingsCalEntryId == null) {
1079 // check if entry already exists
1080 var listFiltering = {
1081 Type:'CalendarEntry',
1083 StartRange: new Date(
1999,
11,
30), // note: due to Nokia's buggy calendar API, the settings event can be on
01.01.2000 AND on
31.12.1999, depending on when the calendar entry was created (in summer or winter). It is not even possible to narrow the search down to these two days (probably because of DST offsets). So we're looking for an event between
30.12.1999 and
02.01.2000!
1084 EndRange: new Date(
2000,
0,
2),
1085 SearchText: 'ComingNext Settings|',
1089 var result = calendarService.IDataSource.GetList(listFiltering);
1090 if (result.ErrorCode) {
1091 error(result.ErrorMessage);
1094 var list = result.ReturnValue;
1095 var entry = list.getNext();
1096 if (entry != undefined) {
1097 settingsCalEntryId = entry.LocalId;
1098 log(
"settingsCalEntryId=" + settingsCalEntryId);
1100 else { // create settings item
1101 var item = new Object();
1102 item.Type =
"DayEvent";
1103 item.StartTime = new Date(
2000,
0,
1);
1104 item.Summary =
"ComingNext Settings|";
1106 var criteria = new Object();
1107 criteria.Type =
"CalendarEntry";
1108 criteria.Item = item;
1111 var result = calendarService.IDataSource.Add(criteria);
1112 if (result.ErrorCode)
1113 error(result.ErrorMessage);
1115 error(
"getSettingsCalEntryId: " + e + ', line ' + e.line);
1118 getSettingsCalEntryId();
1123 function restoreDefaultSettings()
1125 for (var key in config)
1126 config[key].Value = config[key].Default;
1129 function loadSettings()
1131 getSettingsCalEntryId();
1132 var listFiltering = {
1133 Type:'CalendarEntry',
1135 LocalId: settingsCalEntryId
1138 var result = calendarService.IDataSource.GetList(listFiltering);
1139 if (result.ErrorCode) {
1140 error(result.ErrorMessage);
1143 var entry = result.ReturnValue.getNext();
1144 if (entry != undefined) {
1145 log(
"Loading Settings...");
1146 // only reload settings if they chanced since the last reload
1147 if (settingsCache != entry.Summary)
1149 restoreDefaultSettings();
1150 var stringlist = entry.Summary.split(
"|");
1151 // skip the first two entries, those contain header and version info
1152 for(var i =
2; i < stringlist.length -
1; i++) {
1153 var pair = stringlist[i].split('=');
1155 var value = pair[
1];
1156 if (key == null || value == null || config[key] == null) {
1157 log('Warning: unknown or invalid setting: ' + stringlist[i]);
1160 log('stringlist: ' + key + '=\'' + value + '\'');
1161 if (config[key].Type == 'Int') {
1162 config[key].Value = Number(value);
1163 if (isNaN(config[key].Value))
1164 config[key].Value = config[key].Default;
1166 else if (config[key].Type == 'String')
1167 config[key].Value = value;
1168 else if (config[key].Type == 'Bool')
1169 config[key].Value = (value == 'true')
1170 else if (config[key].Type == 'Enum')
1171 config[key].Value = value;
1172 else if (config[key].Type == 'UID') {
1173 config[key].Value = Number(value);
1174 if (isNaN(config[key].Value))
1175 config[key].Value = config[key].Default;
1177 else if (config[key].Type == 'Array') {
1178 config[key].Value = value.split(
"^");
1179 if (config[key].Value.length ==
1 && config[key].Value[
0] ==
"") {
1180 config[key].Value = [];
1184 settingsCache = entry.Summary;
1188 log(
"Settings already cached and did not change");
1192 error(
"Failed to load settings, calendar entry could not be found");
1196 function saveSettings()
1198 getSettingsCalEntryId();
1199 var item = new Object();
1200 item.Type =
"DayEvent";
1201 item.StartTime = new Date(
2000,
0,
1);
1202 item.LocalId = settingsCalEntryId;
1203 item.Summary =
"ComingNext Settings|" + version +
"|";
1205 for (var key in config) {
1206 if (config[key].Type == 'Int')
1207 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1208 else if (config[key].Type == 'String')
1209 item.Summary += key +
"=" + config[key].Value +
"|";
1210 else if (config[key].Type == 'Bool')
1211 item.Summary += key +
"=" + (config[key].Value ? 'true' : 'false') +
"|";
1212 else if (config[key].Type == 'Enum')
1213 item.Summary += key +
"=" + config[key].Value +
"|";
1214 else if (config[key].Type == 'UID')
1215 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1216 else if (config[key].Type == 'Array')
1217 item.Summary += key +
"=" + config[key].Value.join(
"^") +
"|";
1219 settingsCache = item.Summary;
1221 var criteria = new Object();
1222 criteria.Type =
"CalendarEntry";
1223 criteria.Item = item;
1225 log(
"Saving settings to calendar entry: " + item.Summary);
1227 var result = calendarService.IDataSource.Add(criteria);
1228 if (result.ErrorCode)
1229 error(result.ErrorMessage);
1231 error(
"saveSettings: " + e + ', line ' + e.line);
1234 lastReloadTime = null; // force calendar data reload on next update
1239 function toggleVisibility(elementId)
1241 if (document.getElementById(elementId).style.display ==
"none")
1242 document.getElementById(elementId).style.display =
"block";
1244 document.getElementById(elementId).style.display =
"none";
1248 function printHintBox(text)
1251 return '
<td width=
"1%" align=
"right" onclick=
"javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '
</td></tr></table>'+
1252 '
<div class=
"settingsInfo" id=
"info' + uniqueId + '">' + text + '
</div>';
1255 function showAbout()
1259 document.getElementById(
"aboutView").style.display =
"block";
1260 document.onclick = null;
1262 window.menu.setLeftSoftkeyLabel(
" ", function(){});
1263 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1269 //document.getElementById(
"aboutView").innerHTML = 'aboutView';
1270 document.getElementById(
"name").innerHTML =
"Coming Next " + version;
1273 function showHelp() {
1274 widget.openURL('http://comingnext.sf.net/help');
1277 function updateFullscreen()
1281 function showFullscreen()
1283 log(
"showFullscreen()");
1285 document.getElementById(
"fullscreenView").style.display =
"block";
1286 document.getElementById('body').className =
"backgroundFullscreen";
1288 document.onclick = launchCalendar;
1293 function getBackgroundImage()
1298 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[
0]) // internal
1299 bgImage = 'background_' + orientation + '.png';
1301 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
1305 function updateHomescreen()
1307 if (config['useBackgroundImage'].Value) {
1308 // check if we have a completely unknown screen resolution
1309 var screenHeight = screen.height;
1310 var screenWidth = screen.width;
1311 if (screenHeight !=
640 && screenHeight !=
480 && screenHeight !=
360)
1312 screenHeight =
360; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1313 if (screenWidth !=
640 && screenWidth !=
480 && screenWidth !=
360)
1314 screenWidth =
640; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1316 // check for screen rotation
1317 if (orientation != 'portrait' && ((screenWidth ==
360 && screenHeight ==
640) || (screenWidth ==
640 && screenHeight ==
480))) {
1318 window.widget.prepareForTransition(
"fade");
1319 orientation = 'portrait';
1320 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1321 document.getElementById('body').style.backgroundColor = 'none';
1322 window.widget.performTransition();
1323 } else if (orientation != 'landscape' && ((screenWidth ==
640 && screenHeight ==
360) || (screenWidth ==
480 && screenHeight ==
640))) {
1324 window.widget.prepareForTransition(
"fade");
1325 orientation = 'landscape';
1326 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1327 document.getElementById('body').style.backgroundColor = 'none';
1328 window.widget.performTransition();
1330 else if (document.getElementById('body').style.backgroundImage ==
"")
1332 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1337 function showHomescreen()
1339 log(
"showHomescreen()");
1341 document.getElementById(
"homescreenView").style.display =
"block";
1342 document.getElementById('body').className =
"background";
1343 document.onclick = null;
1347 function getLocalizedText(p_Txt)
1349 if (localizedText[p_Txt])
1350 return localizedText[p_Txt];
1352 return 'ERROR: missing translation for ' + p_Txt;
1355 function showUpdate()
1359 document.getElementById(
"updateView").style.display =
"block";
1360 document.onclick = null;
1362 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1365 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1371 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
1375 function checkForUpdate()
1377 // asynch XHR to server url
1378 reqV = new XMLHttpRequest();
1379 reqV.onreadystatechange = checkForUpdateCallback;
1380 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
1381 reqV.open(
"GET", versionURL, true);
1382 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1386 function checkForUpdateCallback()
1388 if (reqV.readyState ==
4) {
1389 if (reqV.status ==
200) {
1390 var resultXml = reqV.responseText;
1392 var div = document.getElementById(
"tmp");
1393 div.innerHTML = resultXml;
1394 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
1395 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
1397 if (version != newVersion) {
1398 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1401 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1406 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1411 function hideViews()
1413 document.getElementById(
"homescreenView").style.display =
"none";
1414 document.getElementById(
"fullscreenView").style.display =
"none";
1415 document.getElementById(
"aboutView").style.display =
"none";
1416 document.getElementById(
"settingsView").style.display =
"none";
1417 document.getElementById(
"updateView").style.display =
"none";
1420 function listCalendars()
1430 DefaultCalendar: false
1434 var calendarsResult = calendarService.IDataSource.GetList(criteria);
1435 if (calendarsResult.ErrorCode !=
0)
1436 throw(
"Error fetching list of calendars: " + calendarsResult.ErrorCode + ': ' + calendarsResult.ErrorMessage);
1437 var calendarListIterator = calendarsResult.ReturnValue;
1442 while (( item = calendarListIterator.getNext()) != undefined ) {
1443 calendars[count++] = item;
1445 log(
"Available Calendars: " + calendars.join(
", "));
1448 error('listing calendars:' + e + ', line ' + e.line);
1453 // Copies all objects and their properties to an array. Data is copied so nothing gets lost when the reference is removed
1454 // Note: this will also set the
"CalendarName" property of every entry to the name specified by the calendarName parameter if it has not been defined already
1455 function listToArray(list, calendarName)
1457 var array = new Array();
1460 while (( item = list.getNext()) != undefined ) {
1461 var itemCopy = new Object();
1462 for(var i=
0; i < entryFields.length; i++) {
1463 itemCopy[entryFields[i]] = item[entryFields[i]];
1465 // for some reason, the CalendarName property is never correctly queried, so we assign it manually here
1466 if (!itemCopy['CalendarName']) {
1467 itemCopy['CalendarName'] = calendarName;
1469 array.push(itemCopy);
1470 txt += array[array.length -
1].Summary +
", ";
1472 log(
"listToArray(): " + txt);
1476 function sortCalendarEntries(a, b)
1479 log(
"sortCalendarEntries(" + a.Summary +
"," + b.Summary +
")");
1481 if (a.InstanceStartTime != null) {
1482 atime = a.InstanceStartTime;
1484 else if (a.StartTime != null) {
1485 atime = a.StartTime;
1487 else if (a.InstanceEndTime != null) {
1488 atime = a.InstanceEndTime;
1490 else if (a.EndTime != null) {
1494 if (b.InstanceStartTime != null) {
1495 btime = b.InstanceStartTime;
1497 else if (b.StartTime != null) {
1498 btime = b.StartTime;
1500 else if (b.InstanceEndTime != null) {
1501 btime = b.InstanceEndTime;
1503 else if (b.EndTime != null) {
1507 if (atime && btime) {
1509 atime = parseDate(atime);
1510 btime = parseDate(btime);
1512 // sort by date & time
1513 if (atime < btime) {
1516 else if (atime
> btime) {
1520 else if (a.Type != b.Type) {
1521 if (a.Type < b.Type) {
1524 else if (a.Type
> b.Type) {
1528 // sort by description
1529 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1530 if (a.Summary < b.Summary) {
1533 else if (a.Summary
> b.Summary) {
1538 // NOTE: events my have no date information at all. In that case, we list events without date first
1539 else if (atime && !btime) {
1542 else if (!atime && btime) {
1545 else if (!atime && !btime) {
1547 if (a.Type != b.Type) {
1548 if (a.Type < b.Type) {
1551 else if (a.Type
> b.Type) {
1555 // sort by description
1556 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1557 if (a.Summary < b.Summary) {
1560 else if (a.Summary
> b.Summary) {
1569 function updateCalendarColors()
1572 calendarColors = [];
1573 if (calendarList.length
> maxColors) {
1574 log(
"updateCalendarColors(): Warning: more calendars than available indicator colors");
1576 for(var i=
0; i < calendarList.length; i++) {
1577 calendarColors[calendarList[i]] = (i % maxColors) +
1;
1581 function log(message)
1583 if (config['enableLogging'].Value) {
1584 console.info(message);
1590 <style type=
"text/css">
1592 table { margin:
0px; padding:
0px; border-spacing:
0px; }
1593 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
1594 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1595 .settingsInfo { display:none; font-style:italic; }
1596 .title { font-weight:bold; font-size:
14pt; }
1597 .textInput { width:
90%; }
1598 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1599 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
1600 #calendarList { position:absolute; left:
5px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
1601 #name { text-align:center; }
1602 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1603 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1608 <body onload=
"javascript:setTimeout('init()', 10)" onresize=
"javascript:updateScreen()" id=
"body" class=
"background">
1609 <div id=
"homescreenView">
1610 <div id=
"calendarList">loading...
</div>
1612 <div id=
"fullscreenView" style=
"display:none;">
1613 <img src=
"Icon.png" id=
"smallappicon">
1614 <h1 class=
"title">Coming Next
</h1>
1616 <div id=
"fullscreenCalendarList">loading...
</div>
1618 <div id=
"settingsView" style=
"display:none">
1619 <img src=
"Icon.png" id=
"smallappicon">
1620 <h1 id=
"settingsTitle" class=
"title">Settings
</h1>
1622 <div id=
"settingsList"></div>
1624 <div id=
"aboutView" style=
"display:none">
1625 <img src=
"Icon.png" id=
"appicon">
1626 <h1 id=
"name">Coming Next
</h1>
1628 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1629 <p>Contributions:
</p>
1630 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1631 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1632 <p class=
"credits">Christophe Milsent (translation support & french translation)
</p>
1633 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation)
</p>
1634 <p class=
"credits">Tokeda (russian translation)
</p>
1635 <p class=
"credits">Marcella Ferrari (italian translation)
</p>
1636 <p class=
"credits">Venos (italian translation)
</p>
1637 <p>This software is open source and licensed under the GPLv3.
</p>
1638 <p>Visit
<a onclick=
"widget.openURL('http://comingnext.sf.net/'); return false;" href=
"http://comingnext.sf.net/">comingnext.sf.net
</a> for free updates.
</p>
1641 <div id=
"updateView" style=
"display:none">
1642 <img src=
"Icon.png" id=
"smallappicon">
1643 <h1 class=
"title">Check for update
</h1>
1645 <div id=
"currentVersion">Coming Next ??
</div>
1646 <div id=
"updateDiv"></div>
1647 <div id=
"tmp" style=
"display:none;"></div>