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
107 var statupSuccessful = false; // indicates if everything started up wihtout errors. If we detect an error after that, it might just be a temporary problem e.g. by a backup process.
109 // vars for daylight saving time
110 var summertime = false; // true, if current date is in summer, false if in winter
111 var daylightSavingDates = new Object(); // caches calculated DST winter and summer time shift dates
113 // this is a list of data fields a calendar event can have
127 function isLeapYear( year ) {
128 if (( year %
4 ==
0 && year %
100 !=
0 ) || year %
400 ==
0 )
134 function calcLeapYear(year, days)
136 if (isLeapYear(year))
142 function subToSunday(myDate, year, days, prevMonthDays)
144 for (i = myDate.getDay(); i
> 0 ;i--)
146 days -= prevMonthDays;
147 days = isLeapYear(year) ? --days : days;
151 function isSummertime(curDate)
156 // if we already calculated DST summer and winter time dates for this year, use cached values
157 var dst = daylightSavingDates[curDate.getFullYear()];
159 var thisYearS = new Date(curDate.getFullYear(),
3,
0,
0,
0,
0 );
160 var thisYearW = new Date(curDate.getFullYear(),
10,
0,
0,
0,
0 );
161 var nextYearS = new Date(curDate.getFullYear() +
1,
3,
0,
0,
0,
0 );
162 var nextYearW = new Date(curDate.getFullYear() +
1,
10,
0,
0,
0,
0 );
164 thisYearSDays = nextYearSDays =
90;
165 thisYearWDays = nextYearWDays =
304;
167 thisYearSDays = calcLeapYear(curDate.getFullYear(), thisYearSDays);
168 thisYearWDays = calcLeapYear(curDate.getFullYear(), thisYearWDays);
169 nextYearSDays = calcLeapYear(curDate.getFullYear() +
1, nextYearSDays);
170 nextYearWDays = calcLeapYear(curDate.getFullYear() +
1, nextYearWDays);
172 thisYearSDays = subToSunday(thisYearS, curDate.getFullYear(), thisYearSDays,
59);
173 thisYearWDays = subToSunday(thisYearW, curDate.getFullYear(), thisYearWDays,
273);
174 nextYearSDays = subToSunday(nextYearS, curDate.getFullYear() +
1, nextYearSDays,
59);
175 nextYearWDays = subToSunday(nextYearW, curDate.getFullYear() +
1, nextYearWDays,
273);
178 Summer: new Date (curDate.getFullYear(),
03-
1, thisYearSDays,
2,
0,
0),
179 Winter: new Date (curDate.getFullYear(),
10-
1, thisYearWDays,
2,
0,
0),
181 daylightSavingDates[curDate.getFullYear()] = dst;
184 if (dst.Summer < curDate)
186 if (dst.Winter < curDate)
188 if (summer && !winter)
194 function error(message)
196 console.info('Error: ' + message);
197 document.getElementById(
"calendarList").innerHTML = 'Error: ' + message;
198 document.getElementById(
"fullscreenCalendarList").innerHTML = 'Error: ' + message;
200 document.onclick = null;
203 function areDatesEqual(date1, date2)
205 return (date1.getFullYear() == date2.getFullYear() &&
206 date1.getMonth() == date2.getMonth() &&
207 date1.getDate() == date2.getDate());
210 function isTomorrow(date)
212 // tommorow = now +
1 day
213 // ToDo: some days can be shorter as
24 hours(daylight saving change day)
214 return areDatesEqual(date, new Date (now.getTime() +
24*
60*
60*
1000));
217 function isToday(date)
219 return areDatesEqual(date, now);
222 function collectLocales()
224 var tmpyear =
2000 + panelNum;
227 if (months_translated.length
> 0)
229 for (month =
0; month <
12; month++) {
230 var startDate = new Date(tmpyear, month,
15);
232 var item = new Object();
233 item.Type =
"DayEvent";
234 item.StartTime = startDate;
235 item.Summary =
"__temp" + month;
237 var criteria = new Object();
238 criteria.Type =
"CalendarEntry";
239 criteria.Item = item;
242 var result = calendarService.IDataSource.Add(criteria);
243 if (result.ErrorCode)
244 throw(result.ErrorMessage);
246 error(
"collectLocales: " + e + ', line ' + e.line);
250 var startTime = new Date(tmpyear,
0,
1);
251 var endTime = new Date(tmpyear,
11,
31);
252 var listFiltering = {
253 Type:'CalendarEntry',
255 StartRange: startTime,
257 SearchText: '__temp',
261 var result = calendarService.IDataSource.GetList(listFiltering);
262 if (result.ErrorCode)
263 throw(result.ErrorMessage);
264 var list = result.ReturnValue;
266 error(
"collectLocales: " + e + ', line ' + e.line);
269 var ids = new Array();
275 while (list && (entry = list.getNext()) != undefined) {
276 dateArr = (entry.StartTime + '').replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
277 var day = dateArr[
1];
278 var month = dateArr[
2];
279 var year = dateArr[
3];
281 // make sure month is set properly
282 if (isNaN(parseInt(day))) {
286 } else if (isNaN(parseInt(year))) {
292 log(entry.StartTime + ' -
> ' + month + ' ' + counter);
293 ids[counter] = entry.id;
294 months_translated[month] = counter +
1;
298 error(
"collectLocales: " + e + ', line ' + e.line);
303 var criteria = new Object();
304 criteria.Type =
"CalendarEntry";
309 var result = calendarService.IDataSource.Delete(criteria);
310 if (result.ErrorCode)
311 throw(result.ErrorMessage);
313 error('deleting temp calendar entries:' + e + ', line ' + e.line);
318 function requestNotification()
320 var criteria = new Object();
321 criteria.Type =
"CalendarEntry";
322 criteria.Filter = new Object();
323 for(var i=
0; i < calendarList.length; i++) {
324 criteria.Filter.CalendarName = calendarList[i];
326 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria, callback);
327 if (notificationRequest.ErrorCode)
328 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
329 notificationRequests.push(notificationRequest);
331 error(
"requestNotification: " + e + ', line ' + e.line);
335 var criteria2 = new Object();
336 criteria2.Type =
"CalendarEntry";
337 criteria2.Filter = new Object();
338 criteria2.Filter.LocalIdList = new Array();
339 criteria2.Filter.LocalIdList[
0] = settingsCalEntryId;
341 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria2, settingsCallback);
342 if (notificationRequest.ErrorCode)
343 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
344 notificationRequests.push(notificationRequest);
346 error(
"requestNotification: " + e + ', line ' + e.line);
350 function cancelNotification()
352 for(var i=
0; i < notificationRequests.length; i++) {
354 var result = calendarService.IDataSource.Cancel(notificationRequests[i]);
355 if (result.ErrorCode)
356 error('cancelNotification failed with error code ' + result.ErrorCode);
358 error(
"cancelNotification: " + e + ', line ' + e.line);
363 function callback(transId, eventCode, result)
365 log(
"callback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
366 lastReloadTime = null; // force calendar data reload on next update
370 function settingsCallback(transId, eventCode, result)
372 log(
"settingsCallback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
376 function parseDate(dateString)
379 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:
380 Wednesday,
26 August,
2009 24:
00:
00
381 Wednesday,
26 August,
2009 12:
00:
00 am
382 Wednesday, August
26,
2009 12:
00:
00 am
383 Wednesday,
2009 August,
26 12:
00:
00 am
384 Wednesday,
2009 August,
28 8.00.00 pm
385 Wednesday,
2009 August,
28 08:
00:
00 PM
389 if (dateString ==
"" || dateString == null || dateString == undefined)
391 if (dateString instanceof Date) {
392 // we already have a date object, no need to parse string here
396 var dateArr = (dateString + '').replace(/,/g, '').replace(/\./g, ':').replace(/ /g, ' ').split(' ');
397 if (dateArr.length !=
5 && dateArr.length !=
6)
401 var weekDay = dateArr[
0];
402 var day = dateArr[
1];
403 var month = dateArr[
2];
404 var year = dateArr[
3];
405 // make sure month is set properly
406 if (isNaN(parseInt(day))) {
412 if (isNaN(parseInt(year))) {
417 // make sure day and year are set properly
418 if (Number(day)
> Number(year)) {
423 month = months_translated[month];
426 var timeArr = dateArr[
4].split(':');
427 if (timeArr.length !=
3)
429 var hours = Number(timeArr[
0]);
430 var minutes = Number(timeArr[
1]);
431 var seconds = Number(timeArr[
2]);
432 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'pm' && hours <
12)
434 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'am' && hours ==
12)
437 result = new Date(year, month -
1, day, hours, minutes, seconds);
440 // take care of daylight saving time
441 if (config['enableDaylightSaving'].Value) {
443 // determine if date is in summer or winter time
444 var dateSummerTime = isSummertime(result);
446 // work around bug in Nokias calendar api resulting in dates within a different DST to be off by
1 hour
447 if (summertime && !dateSummerTime) {
448 result = new Date(result.getTime() -
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // -
1 hour
449 log('parseDate(): fixing time -
1h: ' + result);
451 else if (!summertime && dateSummerTime) {
452 result = new Date(result.getTime() +
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // +
1 hour
453 log('parseDate(): fixing time +
1h: ' + result);
460 // 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"
461 function formatDate(date, format)
463 var day = date.getDate().toString();
464 var month = (date.getMonth() +
1).toString();
465 while (day.length <
2) { day = '
0' + day; }
466 while (month.length <
2) { month = '
0' + month; }
468 if (config['showTodayAsText'].Value && isToday(date))
469 return '
<span class=
"today">' + config['todayText'].Value + '
</span>';
470 if (config['showTodayAsText'].Value && isTomorrow(date))
471 return '
<span class=
"tomorrow">' + config['tomorrowText'].Value + '
</span>';
473 if (format instanceof Date) {
474 // we don't know how to format this
475 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
476 return day + config['dateSeparator'].Value + month;
478 return month + config['dateSeparator'].Value + day;
480 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
481 if (dateArr.length !=
5 && dateArr.length !=
6) {
482 // we don't know how to format this
483 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
484 return day + config['dateSeparator'].Value + month;
486 return month + config['dateSeparator'].Value + day;
490 if (config['dateFormat'].Value == 'MMDD')
492 else if (config['dateFormat'].Value == 'DDMM')
495 // config['dateFormat'].Value == 'auto', try to detect system setting
497 var day_ = dateArr[
1];
498 var month_ = dateArr[
2];
499 var year_ = dateArr[
3];
500 // make sure month is set properly
501 if (isNaN(parseInt(day_))) {
506 } else if (isNaN(parseInt(year_))) {
512 // make sure day and year are set properly
513 if (Number(day_)
> Number(year_))
518 return day + config['dateSeparator'].Value + month;
520 return month + config['dateSeparator'].Value + day;
523 function formatTime(date)
525 // date is a Date() object
526 date.setSeconds(
0); // we don't care about seconds
527 var time = date.toLocaleTimeString().replace(/[\.:]
00/, ''); // remove seconds from string
528 if (time.replace(/\./, ':').split(':')[
0].length <
2)
530 if (config['showNowAsText'].Value && date.getTime() == now.getTime())
531 time = '
<span class=
"now">' + config['nowText'].Value + '
</span>';
535 function updateData()
542 // check if we got additional or less calendars since our last update
543 var newCalendarList = listCalendars();
544 if (newCalendarList == null) {
545 // Something went wrong fetching the calendars list.
546 // This usually happens when a backup is being made.
547 // Retry the next time updateData() is called by
548 // resetting errorOccured
549 log('updateData(): listCalendars() failed, trying again laster...');
550 cacheEntriesHtml = ''; // make sure we replace the currently shown error message on the next update
551 errorOccured = false;
554 if (newCalendarList.length != calendarList.length) {
555 calendarList = newCalendarList;
556 updateCalendarColors();
557 cancelNotification();
558 requestNotification();
559 lastReloadTime = null; // force calendar data reload on this update
564 // only reload calendar data every
6 hours, visual updates occure more often
565 if (!lastReloadTime || now.getTime() - lastReloadTime.getTime()
> reloadInterval) {
566 log('updateData(): reloading calendar data');
568 // meetings have time
569 // 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
570 summertime = isSummertime(now); // cache summer time info for today
571 var meetingList = [];
572 for(var i=
0; i < calendarList.length; i++) {
573 // ignore excluded calendars
574 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
576 var meetingListFiltering = {
577 Type:'CalendarEntry',
579 CalendarName: calendarList[i],
580 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
581 EndRange: (new Date(now.getFullYear(), now.getMonth() + config['monthRange'].Value, now.getDate(),
0,
0,
0))
584 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
585 if (meetingResult.ErrorCode !=
0)
586 throw(
"Error fetching calendar data: " + meetingResult.ErrorCode + ': ' + meetingResult.ErrorMessage);
587 var list = meetingResult.ReturnValue;
588 meetingList = meetingList.concat(listToArray(list, calendarList[i]));
590 log(
"updateData(): meetingList.sort()");
591 meetingList.sort(sortCalendarEntries);
593 // todos don't, they start on
00:
00 hrs., but should be visible anyway
594 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
595 if (config['includeTodos'].Value) {
596 var todayTodoList = [];
597 for(var i=
0; i < calendarList.length; i++) {
598 // ignore excluded calendars
599 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
601 var todayTodoListFiltering = {
602 Type:'CalendarEntry',
604 CalendarName: calendarList[i],
606 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
607 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
610 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
611 var list = todayTodoResult.ReturnValue;
612 todayTodoList = todayTodoList.concat(listToArray(list, calendarList[i]));
614 log(
"updateData(): todayTodoList.sort()");
615 todayTodoList.sort(sortCalendarEntries);
616 entryLists = [todayTodoList, meetingList];
618 entryLists = [meetingList];
620 lastReloadTime = new Date();
622 error('loading Calendar items list:' + e + ', line ' + e.line);
632 var fontsize = 'normal';
634 if (config['eventsPerWidget'].Value ==
3) {
636 changeCssClass('.icon', 'width:
20px; height:
20px');
638 else if (config['eventsPerWidget'].Value ==
5) {
640 changeCssClass('.icon', 'width:
10px; height:
10px');
642 else if (config['eventsPerWidget'].Value ==
6) {
644 changeCssClass('.icon', 'width:
8px; height:
8px');
648 changeCssClass('.icon', config['cssStyle_icon'].Value);
649 var entriesHtml = '
<table style=
"font-size:' + fontsize + ';">';
653 max = (panelNum +
1) * config['eventsPerWidget'].Value;
655 max =
30; // we can display a lot more events in fullscreen mode
657 if (config['enableLogging'].Value) {
659 for (var i=
0; i < entryLists.length; i++) {
660 listinfo = listinfo +
" " + entryLists[i].length;
661 var entrieslist =
"";
662 for (var j=
0; j < entryLists[i].length; j++) {
663 entrieslist += entryLists[i][j].Summary +
", ";
665 log(
"updateData(): entrieslist: " + entrieslist);
667 log(
"updateData(): inner loop, " + entryLists.length +
" lists, [" + listinfo +
"] entries");
670 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
671 for (var i=
0; counter < max && i < entryLists.length; i++) {
672 for (var j=
0; (counter < max) && (j < entryLists[i].length); j++) {
673 entry = entryLists[i][j];
676 // output event info for debugging
677 var entryInfo =
"event: ";
678 for(var k=
0; k < entryFields.length; ++k) {
679 if (entry[entryFields[k]] != undefined) {
680 entryInfo += entryFields[k] +
"=" + entry[entryFields[k]] +
",";
685 // we don't want ToDos when includeTodos == false or when they are completed
686 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !config['includeTodos'].Value)) {
687 log('skipping ' + entry.id );
692 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
693 if (eventIds[entry.id] ==
1 && entry.Type == 'ToDo') {
694 log('skipped (already included) ' + entry.id);
698 eventIds[entry.id] =
1;
700 // summary can be undefined!
701 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
702 if (entry.Location != '' && entry.Location != undefined && config['showLocation'].Value)
703 Summary += ', ' + entry.Location;
705 // fix by yves: determine start and end dates/times
706 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
707 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
709 // there can be ToDos that have no date at all!
710 if (entry.Type == 'ToDo' && entry.EndTime == null)
711 entryDate =
""; // this will cause parseDate(entryDate) to return null;
713 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
715 // Convert date/time string to Date object
716 var date = parseDate(entryDate);
717 log('date: ' + date);
718 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
719 log('endDate: ' + endDate);
721 // check if meeting event has already passed
722 if (entry.Type == 'Meeting') {
723 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
724 if (now.getTime()
> compareTime) {
725 log('skipping Meeting (already passed) ' + entry.id);
727 eventIds[entry.id] =
0;
732 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
733 if (entry.Type == 'Anniversary') {
734 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
735 if (date.getTime() < tmp.getTime()) {
736 log('skipping Anniversary (already passed) ' + entry.id);
738 eventIds[entry.id] =
0;
743 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
744 if (entry.Type == 'DayEvent' && endDate != null) {
745 endDate.setMinutes(endDate.getMinutes() -
1);
746 log('fixing DayEvent endDate: ' + endDate);
747 if (now.getTime()
> endDate.getTime()) {
748 log('event already passed ' + entry.id);
750 eventIds[entry.id] =
0;
755 // check if the event is currently taking place
756 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
757 // check if we are between start and endtime
758 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
759 date = now; // change appointment date/time to now
760 log('event is currently taking place: ' + date);
764 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
765 if (mode ==
0 && panelNum
> 0 && counter < panelNum * config['eventsPerWidget'].Value +
1) {
766 log('skipping (already in first widget) ' + entry.id);
770 // mark overdue todos
772 if (entry.Type == 'ToDo' && date != null) {
773 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
0,
0,
0);
774 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
775 if (tmp1.getTime() < tmp2.getTime()) {
780 // generate html output
781 entriesHtml += '
<tr>';
782 if (config['showCalendarIndicator'].Value && calendarList.length - config['excludedCalendars'].Value.length
> 1) {
783 entriesHtml += '
<td><span class=
"calendar' + calendarColors[entry.CalendarName] + '"> </span></td>';
785 entriesHtml += '
<td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
787 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
788 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
790 var weekDay = date.toLocaleDateString().substr(
0,config['weekDayLength'].Value);
791 var time = formatTime(date);
792 var dateStr = formatDate(date, entryDate);
793 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
794 dateStr = '
<span class=
"overdue">' + config['overdueText'].Value + '
</span>';
795 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
796 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
797 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
798 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
800 entriesHtml += '
<td class=
"weekDay" width=
"1px">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
801 } else if (entry.Type == 'Meeting') {
802 if (config['showCombinedDateTime'].Value) {
804 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
805 else if (isTomorrow(date))
806 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
808 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
810 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
811 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
813 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
817 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
820 entriesHtml += '
</table>';
821 if (config['showNothingText'].Value && entriesHtml == '
<table></table>') {
822 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
823 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '
</div>';
825 if (cacheEntriesHtml != entriesHtml) {
827 document.getElementById('calendarList').innerHTML = entriesHtml;
829 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
830 cacheEntriesHtml = entriesHtml;
833 lastUpdateTime = new Date();
835 error('displaying list:' + e + ', line ' + e.line);
840 // called by handleOnShow() and onResize events
841 function updateScreen()
843 log('updateScreen()');
845 // check if opening fullscreen
846 if( window.innerHeight
> 91 && mode ==
0) {
848 cacheEntriesHtml = '';
849 document.getElementById('body').style.backgroundImage =
"";
852 else if (window.innerHeight <=
91 && mode !=
0) {
854 cacheEntriesHtml = '';
859 updateHomescreen(); // check for screen rotation
864 function handleOnShow()
868 var time = new Date();
869 if (time.getTime() - lastUpdateTime.getTime()
> config['updateDataInterval'].Value *
60 *
1000) {
870 log('updateScreen(): force updateData() because last update was too long ago (' + (time.getTime() - lastUpdateTime.getTime()) /
1000 + 's)');
873 setUpdateTimer(); // reinitialize update timer
877 function launchCalendar()
880 widget.openApplication(config['calendarApp'].Value,
"");
881 if (config['hideWidgetOnCalendarOpen'].Value)
884 error('starting Calendar App');
891 log('New widget instance starting up...');
894 // call calendar service
895 if (device !=
"undefined")
896 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
898 throw('device object does not exist');
900 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>');
904 calendarList = listCalendars();
906 updateCalendarColors();
909 requestNotification();
910 document.getElementById(
"settingsTitle").innerHTML = getLocalizedText('menu.settings');
912 if (window.innerHeight
> 91) {
913 mode =
0; // we're starting fullscreen, we set mode to homescreen in order to let updateScreen() do all the work for us
918 log(
"init(): updateScreen()");
920 if (config['useBackgroundImage'].Value)
921 // check for screen rotation every
1 secs
922 screenRotationTimer = window.setInterval('checkOrientation()',
1000 *
1);
924 // call updateScreen() when widget changes from background to forground
925 window.widget.onshow = handleOnShow;
927 log(
"init(): finished...");
929 statupSuccessful = true;
932 function checkOrientation()
936 updateHomescreen(); // check for screen rotation
939 function setUpdateTimer()
941 updateTimer = window.setInterval('updateTimerCallback()',
1000 *
60 * config['updateDataInterval'].Value);
944 function clearUpdateTimer()
946 window.clearInterval(updateTimer);
949 function updateTimerCallback()
951 log(
"updateTimerCallback()");
955 function createMenu()
957 window.menu.setLeftSoftkeyLabel(
"",null);
958 window.menu.setRightSoftkeyLabel(
"",null);
960 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
961 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
962 var menuHelp = new MenuItem(getLocalizedText('menu.help'), id++);
963 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
964 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
965 menuSettings.onSelect = showSettings;
966 menuAbout.onSelect = showAbout;
967 menuCallApp.onSelect = launchCalendar;
968 menuUpdate.onSelect = showUpdate;
969 menuHelp.onSelect = showHelp;
971 window.menu.append(menuCallApp);
972 window.menu.append(menuSettings);
973 window.menu.append(menuHelp);
974 window.menu.append(menuUpdate);
975 window.menu.append(menuAbout);
978 function showSettings()
982 document.getElementById(
"settingsView").style.display =
"block";
983 document.onclick = null;
985 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
987 for (var key in config) {
988 if (config[key].Type == 'String')
989 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
990 else if (config[key].Type == 'Int') {
991 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
992 if (config[key].Value <
0 || isNaN(config[key].Value))
993 config[key].Value = config[key].Default;
995 else if (config[key].Type == 'Bool')
996 config[key].Value = document.forms[
0].elements[
"settings." + key].checked;
997 else if (config[key].Type == 'UID') {
998 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
999 if (isNaN(config[key].Value))
1000 config[key].Value = config[key].Default;
1002 else if (config[key].Type == 'Enum') {
1003 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
1004 if (config[key].ValidValues.indexOf(config[key].Value) == -
1)
1005 config[key].Value = config[key].Default;
1007 else if (config[key].Type == 'Array') {
1008 if (key == 'excludedCalendars') {
1009 config[key].Value = new Array();
1010 for(var i=
0; i < calendarList.length; i++) {
1011 var element = document.forms[
0].elements[
"settings." + key +
"." + calendarList[i]];
1012 if (element != null && element.checked == false)
1013 config[key].Value.push(calendarList[i]);
1026 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
1032 var settingsHtml = '
<form>';
1033 for (var key in config) {
1034 if (config[key].Type == 'String') {
1036 if (key.substring(
0,
9) ==
"cssStyle_")
1037 prefix = getLocalizedText('settings.cssStyle_prefix');
1038 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 />';
1040 else if (config[key].Type == 'Int')
1041 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 />';
1042 else if (config[key].Type == 'Bool')
1043 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 />';
1044 else if (config[key].Type == 'UID')
1045 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 />';
1046 else if (config[key].Type == 'Enum') {
1047 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><select name=
"settings.' + key + '" size=
"1">';
1048 for(var i =
0; i < config[key].ValidValues.length; i++)
1049 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>';
1050 settingsHtml += '
</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1052 else if (config[key].Type == 'Array') {
1053 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br />';
1054 if (key == 'excludedCalendars') {
1055 for(var i=
0; i < calendarList.length; i++) {
1056 var checked = '
checked=
"checked"';
1057 if (config[key].Value.indexOf(calendarList[i]) != -
1)
1059 settingsHtml += '
<input name=
"settings.' + key + '.' + calendarList[i] + '" type=
"checkbox" value=
"' + calendarList[i] + '" ' + checked + '
/> ' + calendarList[i] + '
<br />';
1062 settingsHtml += '
</td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1065 settingsHtml += '
<input name=
"reset" type=
"button" value=
"' + getLocalizedText('settings.restoreDefaults') + '" onclick=
"javascript:restoreDefaultSettings();showSettings();" />';
1066 settingsHtml += '
</form>';
1067 document.getElementById(
"settingsList").innerHTML = settingsHtml;
1070 function changeCssClass(classname, properties)
1072 for(var i =
0; i < document.styleSheets[
0]['cssRules'].length; i++)
1074 if (document.styleSheets[
0]['cssRules'][i].selectorText == classname) {
1075 document.styleSheets[
0].deleteRule(i);
1076 document.styleSheets[
0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[
0]['cssRules'].length);
1082 function updateCssClasses()
1084 for(var key in config) {
1085 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
1089 function getSettingsCalEntryId()
1091 if (settingsCalEntryId == null) {
1092 // check if entry already exists
1093 var listFiltering = {
1094 Type:'CalendarEntry',
1096 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!
1097 EndRange: new Date(
2000,
0,
2),
1098 SearchText: 'ComingNext Settings|',
1104 result = calendarService.IDataSource.GetList(listFiltering);
1105 if (result.ErrorCode)
1106 throw(result.ErrorMessage);
1109 error(
"getSettingsCalEntryId: GetList() failed: " + e + ', line ' + e.line);
1112 var list = result.ReturnValue;
1113 var entry = list.getNext();
1114 if (entry != undefined) {
1115 settingsCalEntryId = entry.LocalId;
1116 log(
"settingsCalEntryId=" + settingsCalEntryId);
1118 else { // create settings item
1119 var item = new Object();
1120 item.Type =
"DayEvent";
1121 item.StartTime = new Date(
2000,
0,
1);
1122 item.Summary =
"ComingNext Settings|";
1124 var criteria = new Object();
1125 criteria.Type =
"CalendarEntry";
1126 criteria.Item = item;
1129 var result = calendarService.IDataSource.Add(criteria);
1130 if (result.ErrorCode)
1131 throw(result.ErrorMessage);
1133 error(
"getSettingsCalEntryId: " + e + ', line ' + e.line);
1136 getSettingsCalEntryId();
1141 function restoreDefaultSettings()
1143 for (var key in config)
1144 config[key].Value = config[key].Default;
1147 function loadSettings()
1149 getSettingsCalEntryId();
1150 var listFiltering = {
1151 Type:'CalendarEntry',
1153 LocalId: settingsCalEntryId
1158 result = calendarService.IDataSource.GetList(listFiltering);
1159 if (result.ErrorCode)
1160 throw(result.ErrorMessage);
1163 error(
"loadSettings: GetList() failed: " + e + ', line ' + e.line);
1166 var entry = result.ReturnValue.getNext();
1167 if (entry != undefined) {
1168 log(
"Loading Settings...");
1169 // only reload settings if they chanced since the last reload
1170 if (settingsCache != entry.Summary)
1172 restoreDefaultSettings();
1173 var stringlist = entry.Summary.split(
"|");
1174 // skip the first two entries, those contain header and version info
1175 for(var i =
2; i < stringlist.length -
1; i++) {
1176 var pair = stringlist[i].split('=');
1178 var value = pair[
1];
1179 if (key == null || value == null || config[key] == null) {
1180 log('Warning: unknown or invalid setting: ' + stringlist[i]);
1183 log('stringlist: ' + key + '=\'' + value + '\'');
1184 if (config[key].Type == 'Int') {
1185 config[key].Value = Number(value);
1186 if (isNaN(config[key].Value))
1187 config[key].Value = config[key].Default;
1189 else if (config[key].Type == 'String')
1190 config[key].Value = value;
1191 else if (config[key].Type == 'Bool')
1192 config[key].Value = (value == 'true')
1193 else if (config[key].Type == 'Enum')
1194 config[key].Value = value;
1195 else if (config[key].Type == 'UID') {
1196 config[key].Value = Number(value);
1197 if (isNaN(config[key].Value))
1198 config[key].Value = config[key].Default;
1200 else if (config[key].Type == 'Array') {
1201 config[key].Value = value.split(
"^");
1202 if (config[key].Value.length ==
1 && config[key].Value[
0] ==
"") {
1203 config[key].Value = [];
1207 settingsCache = entry.Summary;
1211 log(
"Settings already cached and did not change");
1215 error(
"Failed to load settings, calendar entry could not be found");
1219 function saveSettings()
1221 getSettingsCalEntryId();
1222 var item = new Object();
1223 item.Type =
"DayEvent";
1224 item.StartTime = new Date(
2000,
0,
1);
1225 item.LocalId = settingsCalEntryId;
1226 item.Summary =
"ComingNext Settings|" + version +
"|";
1228 for (var key in config) {
1229 if (config[key].Type == 'Int')
1230 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1231 else if (config[key].Type == 'String')
1232 item.Summary += key +
"=" + config[key].Value +
"|";
1233 else if (config[key].Type == 'Bool')
1234 item.Summary += key +
"=" + (config[key].Value ? 'true' : 'false') +
"|";
1235 else if (config[key].Type == 'Enum')
1236 item.Summary += key +
"=" + config[key].Value +
"|";
1237 else if (config[key].Type == 'UID')
1238 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1239 else if (config[key].Type == 'Array')
1240 item.Summary += key +
"=" + config[key].Value.join(
"^") +
"|";
1242 settingsCache = item.Summary;
1244 var criteria = new Object();
1245 criteria.Type =
"CalendarEntry";
1246 criteria.Item = item;
1248 log(
"Saving settings to calendar entry: " + item.Summary);
1250 var result = calendarService.IDataSource.Add(criteria);
1251 if (result.ErrorCode)
1252 throw(result.ErrorMessage);
1254 error(
"saveSettings: " + e + ', line ' + e.line);
1257 lastReloadTime = null; // force calendar data reload on next update
1262 function toggleVisibility(elementId)
1264 if (document.getElementById(elementId).style.display ==
"none")
1265 document.getElementById(elementId).style.display =
"block";
1267 document.getElementById(elementId).style.display =
"none";
1271 function printHintBox(text)
1274 return '
<td width=
"1%" align=
"right" onclick=
"javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '
</td></tr></table>'+
1275 '
<div class=
"settingsInfo" id=
"info' + uniqueId + '">' + text + '
</div>';
1278 function showAbout()
1282 document.getElementById(
"aboutView").style.display =
"block";
1283 document.onclick = null;
1285 window.menu.setLeftSoftkeyLabel(
" ", function(){});
1286 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1292 //document.getElementById(
"aboutView").innerHTML = 'aboutView';
1293 document.getElementById(
"name").innerHTML =
"Coming Next " + version;
1296 function showHelp() {
1297 widget.openURL('http://comingnext.sf.net/help');
1300 function updateFullscreen()
1304 function showFullscreen()
1306 log(
"showFullscreen()");
1308 document.getElementById(
"fullscreenView").style.display =
"block";
1309 document.getElementById('body').className =
"backgroundFullscreen";
1311 document.onclick = launchCalendar;
1316 function getBackgroundImage()
1321 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[
0]) // internal
1322 bgImage = 'background_' + orientation + '.png';
1324 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
1328 function updateHomescreen()
1330 if (config['useBackgroundImage'].Value) {
1331 // check if we have a completely unknown screen resolution
1332 var screenHeight = screen.height;
1333 var screenWidth = screen.width;
1334 if (screenHeight !=
640 && screenHeight !=
480 && screenHeight !=
360)
1335 screenHeight =
360; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1336 if (screenWidth !=
640 && screenWidth !=
480 && screenWidth !=
360)
1337 screenWidth =
640; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1339 // check for screen rotation
1340 if (orientation != 'portrait' && ((screenWidth ==
360 && screenHeight ==
640) || (screenWidth ==
640 && screenHeight ==
480))) {
1341 window.widget.prepareForTransition(
"fade");
1342 orientation = 'portrait';
1343 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1344 document.getElementById('body').style.backgroundColor = 'none';
1345 window.widget.performTransition();
1346 } else if (orientation != 'landscape' && ((screenWidth ==
640 && screenHeight ==
360) || (screenWidth ==
480 && screenHeight ==
640))) {
1347 window.widget.prepareForTransition(
"fade");
1348 orientation = 'landscape';
1349 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1350 document.getElementById('body').style.backgroundColor = 'none';
1351 window.widget.performTransition();
1353 else if (document.getElementById('body').style.backgroundImage ==
"")
1355 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1360 function showHomescreen()
1362 log(
"showHomescreen()");
1364 document.getElementById(
"homescreenView").style.display =
"block";
1365 document.getElementById('body').className =
"background";
1366 document.onclick = null;
1370 function getLocalizedText(p_Txt)
1372 if (localizedText[p_Txt])
1373 return localizedText[p_Txt];
1375 return 'ERROR: missing translation for ' + p_Txt;
1378 function showUpdate()
1382 document.getElementById(
"updateView").style.display =
"block";
1383 document.onclick = null;
1385 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1388 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1394 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
1398 function checkForUpdate()
1400 // asynch XHR to server url
1401 reqV = new XMLHttpRequest();
1402 reqV.onreadystatechange = checkForUpdateCallback;
1403 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
1404 reqV.open(
"GET", versionURL, true);
1405 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1409 function checkForUpdateCallback()
1411 if (reqV.readyState ==
4) {
1412 if (reqV.status ==
200) {
1413 var resultXml = reqV.responseText;
1415 var div = document.getElementById(
"tmp");
1416 div.innerHTML = resultXml;
1417 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
1418 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
1420 if (version != newVersion) {
1421 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1424 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1429 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1434 function hideViews()
1436 document.getElementById(
"homescreenView").style.display =
"none";
1437 document.getElementById(
"fullscreenView").style.display =
"none";
1438 document.getElementById(
"aboutView").style.display =
"none";
1439 document.getElementById(
"settingsView").style.display =
"none";
1440 document.getElementById(
"updateView").style.display =
"none";
1443 function listCalendars()
1453 DefaultCalendar: false
1457 var calendarsResult = calendarService.IDataSource.GetList(criteria);
1458 if (calendarsResult.ErrorCode !=
0)
1459 throw(
"Error fetching list of calendars: " + calendarsResult.ErrorCode + ': ' + calendarsResult.ErrorMessage);
1460 var calendarListIterator = calendarsResult.ReturnValue;
1465 while (( item = calendarListIterator.getNext()) != undefined ) {
1466 calendars[count++] = item;
1468 log(
"Available Calendars: " + calendars.join(
", "));
1471 error('listing calendars:' + e + ', line ' + e.line);
1476 // Copies all objects and their properties to an array. Data is copied so nothing gets lost when the reference is removed
1477 // 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
1478 function listToArray(list, calendarName)
1480 var array = new Array();
1483 while (( item = list.getNext()) != undefined ) {
1484 var itemCopy = new Object();
1485 for(var i=
0; i < entryFields.length; i++) {
1486 itemCopy[entryFields[i]] = item[entryFields[i]];
1488 // for some reason, the CalendarName property is never correctly queried, so we assign it manually here
1489 if (!itemCopy['CalendarName']) {
1490 itemCopy['CalendarName'] = calendarName;
1492 array.push(itemCopy);
1493 txt += array[array.length -
1].Summary +
", ";
1495 log(
"listToArray(): " + txt);
1499 function sortCalendarEntries(a, b)
1502 log(
"sortCalendarEntries(" + a.Summary +
"," + b.Summary +
")");
1504 if (a.InstanceStartTime != null) {
1505 atime = a.InstanceStartTime;
1507 else if (a.StartTime != null) {
1508 atime = a.StartTime;
1510 else if (a.InstanceEndTime != null) {
1511 atime = a.InstanceEndTime;
1513 else if (a.EndTime != null) {
1517 if (b.InstanceStartTime != null) {
1518 btime = b.InstanceStartTime;
1520 else if (b.StartTime != null) {
1521 btime = b.StartTime;
1523 else if (b.InstanceEndTime != null) {
1524 btime = b.InstanceEndTime;
1526 else if (b.EndTime != null) {
1530 if (atime && btime) {
1532 atime = parseDate(atime);
1533 btime = parseDate(btime);
1535 // sort by date & time
1536 if (atime < btime) {
1539 else if (atime
> btime) {
1543 else if (a.Type != b.Type) {
1544 if (a.Type < b.Type) {
1547 else if (a.Type
> b.Type) {
1551 // sort by description
1552 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1553 if (a.Summary < b.Summary) {
1556 else if (a.Summary
> b.Summary) {
1561 // NOTE: events my have no date information at all. In that case, we list events without date first
1562 else if (atime && !btime) {
1565 else if (!atime && btime) {
1568 else if (!atime && !btime) {
1570 if (a.Type != b.Type) {
1571 if (a.Type < b.Type) {
1574 else if (a.Type
> b.Type) {
1578 // sort by description
1579 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1580 if (a.Summary < b.Summary) {
1583 else if (a.Summary
> b.Summary) {
1592 function updateCalendarColors()
1595 calendarColors = [];
1596 if (calendarList.length
> maxColors) {
1597 log(
"updateCalendarColors(): Warning: more calendars than available indicator colors");
1599 for(var i=
0; i < calendarList.length; i++) {
1600 calendarColors[calendarList[i]] = (i % maxColors) +
1;
1604 function log(message)
1606 if (config['enableLogging'].Value) {
1607 console.info(message);
1613 <style type=
"text/css">
1615 table { margin:
0px; padding:
0px; border-spacing:
0px; }
1616 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
1617 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1618 .settingsInfo { display:none; font-style:italic; }
1619 .title { font-weight:bold; font-size:
14pt; }
1620 .textInput { width:
90%; }
1621 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1622 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
1623 #calendarList { position:absolute; left:
5px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
1624 #name { text-align:center; }
1625 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1626 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1631 <body onload=
"javascript:setTimeout('init()', 10)" onresize=
"javascript:updateScreen()" id=
"body" class=
"background">
1632 <div id=
"homescreenView">
1633 <div id=
"calendarList">loading...
</div>
1635 <div id=
"fullscreenView" style=
"display:none;">
1636 <img src=
"Icon.png" id=
"smallappicon">
1637 <h1 class=
"title">Coming Next
</h1>
1639 <div id=
"fullscreenCalendarList">loading...
</div>
1641 <div id=
"settingsView" style=
"display:none">
1642 <img src=
"Icon.png" id=
"smallappicon">
1643 <h1 id=
"settingsTitle" class=
"title">Settings
</h1>
1645 <div id=
"settingsList"></div>
1647 <div id=
"aboutView" style=
"display:none">
1648 <img src=
"Icon.png" id=
"appicon">
1649 <h1 id=
"name">Coming Next
</h1>
1651 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1652 <p>Contributions:
</p>
1653 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1654 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1655 <p class=
"credits">Christophe Milsent (translation support & french translation)
</p>
1656 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation)
</p>
1657 <p class=
"credits">Tokeda (russian translation)
</p>
1658 <p class=
"credits">Marcella Ferrari (italian translation)
</p>
1659 <p class=
"credits">Venos (italian translation)
</p>
1660 <p>This software is open source and licensed under the GPLv3.
</p>
1661 <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>
1664 <div id=
"updateView" style=
"display:none">
1665 <img src=
"Icon.png" id=
"smallappicon">
1666 <h1 class=
"title">Check for update
</h1>
1668 <div id=
"currentVersion">Coming Next ??
</div>
1669 <div id=
"updateDiv"></div>
1670 <div id=
"tmp" style=
"display:none;"></div>