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.length != calendarList.length) {
545 calendarList = newCalendarList;
546 updateCalendarColors();
547 cancelNotification();
548 requestNotification();
549 lastReloadTime = null; // force calendar data reload on this update
554 // only reload calendar data every
6 hours, visual updates occure more often
555 if (!lastReloadTime || now.getTime() - lastReloadTime.getTime()
> reloadInterval) {
556 log('updateData(): reloading calendar data');
558 // meetings have time
559 // 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
560 summertime = isSummertime(now); // cache summer time info for today
561 var meetingList = [];
562 for(var i=
0; i < calendarList.length; i++) {
563 // ignore excluded calendars
564 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
566 var meetingListFiltering = {
567 Type:'CalendarEntry',
569 CalendarName: calendarList[i],
570 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
571 EndRange: (new Date(now.getFullYear(), now.getMonth() + config['monthRange'].Value, now.getDate(),
0,
0,
0))
574 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
575 if (meetingResult.ErrorCode !=
0)
576 throw(
"Error fetching calendar data: " + meetingResult.ErrorCode + ': ' + meetingResult.ErrorMessage);
577 var list = meetingResult.ReturnValue;
578 meetingList = meetingList.concat(listToArray(list, calendarList[i]));
580 log(
"updateData(): meetingList.sort()");
581 meetingList.sort(sortCalendarEntries);
583 // todos don't, they start on
00:
00 hrs., but should be visible anyway
584 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
585 if (config['includeTodos'].Value) {
586 var todayTodoList = [];
587 for(var i=
0; i < calendarList.length; i++) {
588 // ignore excluded calendars
589 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
591 var todayTodoListFiltering = {
592 Type:'CalendarEntry',
594 CalendarName: calendarList[i],
596 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
597 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
600 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
601 var list = todayTodoResult.ReturnValue;
602 todayTodoList = todayTodoList.concat(listToArray(list, calendarList[i]));
604 log(
"updateData(): todayTodoList.sort()");
605 todayTodoList.sort(sortCalendarEntries);
606 entryLists = [todayTodoList, meetingList];
608 entryLists = [meetingList];
610 lastReloadTime = new Date();
612 error('loading Calendar items list:' + e + ', line ' + e.line);
622 var fontsize = 'normal';
624 if (config['eventsPerWidget'].Value ==
3) {
626 changeCssClass('.icon', 'width:
20px; height:
20px');
628 else if (config['eventsPerWidget'].Value ==
5) {
630 changeCssClass('.icon', 'width:
10px; height:
10px');
632 else if (config['eventsPerWidget'].Value ==
6) {
634 changeCssClass('.icon', 'width:
8px; height:
8px');
638 changeCssClass('.icon', config['cssStyle_icon'].Value);
639 var entriesHtml = '
<table style=
"font-size:' + fontsize + ';">';
643 max = (panelNum +
1) * config['eventsPerWidget'].Value;
645 max =
30; // we can display a lot more events in fullscreen mode
647 if (config['enableLogging'].Value) {
649 for (var i=
0; i < entryLists.length; i++) {
650 listinfo = listinfo +
" " + entryLists[i].length;
651 var entrieslist =
"";
652 for (var j=
0; j < entryLists[i].length; j++) {
653 entrieslist += entryLists[i][j].Summary +
", ";
655 log(
"updateData(): entrieslist: " + entrieslist);
657 log(
"updateData(): inner loop, " + entryLists.length +
" lists, [" + listinfo +
"] entries");
660 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
661 for (var i=
0; counter < max && i < entryLists.length; i++) {
662 for (var j=
0; (counter < max) && (j < entryLists[i].length); j++) {
663 entry = entryLists[i][j];
666 // output event info for debugging
667 var entryInfo =
"event: ";
668 for(var k=
0; k < entryFields.length; ++k) {
669 if (entry[entryFields[k]] != undefined) {
670 entryInfo += entryFields[k] +
"=" + entry[entryFields[k]] +
",";
675 // we don't want ToDos when includeTodos == false or when they are completed
676 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !config['includeTodos'].Value)) {
677 log('skipping ' + entry.id );
682 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
683 if (eventIds[entry.id] ==
1 && entry.Type == 'ToDo') {
684 log('skipped (already included) ' + entry.id);
688 eventIds[entry.id] =
1;
690 // summary can be undefined!
691 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
692 if (entry.Location != '' && entry.Location != undefined && config['showLocation'].Value)
693 Summary += ', ' + entry.Location;
695 // fix by yves: determine start and end dates/times
696 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
697 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
699 // there can be ToDos that have no date at all!
700 if (entry.Type == 'ToDo' && entry.EndTime == null)
701 entryDate =
""; // this will cause parseDate(entryDate) to return null;
703 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
705 // Convert date/time string to Date object
706 var date = parseDate(entryDate);
707 log('date: ' + date);
708 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
709 log('endDate: ' + endDate);
711 // check if meeting event has already passed
712 if (entry.Type == 'Meeting') {
713 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
714 if (now.getTime()
> compareTime) {
715 log('skipping Meeting (already passed) ' + entry.id);
717 eventIds[entry.id] =
0;
722 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
723 if (entry.Type == 'Anniversary') {
724 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
725 if (date.getTime() < tmp.getTime()) {
726 log('skipping Anniversary (already passed) ' + entry.id);
728 eventIds[entry.id] =
0;
733 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
734 if (entry.Type == 'DayEvent' && endDate != null) {
735 endDate.setMinutes(endDate.getMinutes() -
1);
736 log('fixing DayEvent endDate: ' + endDate);
737 if (now.getTime()
> endDate.getTime()) {
738 log('event already passed ' + entry.id);
740 eventIds[entry.id] =
0;
745 // check if the event is currently taking place
746 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
747 // check if we are between start and endtime
748 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
749 date = now; // change appointment date/time to now
750 log('event is currently taking place: ' + date);
754 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
755 if (mode ==
0 && panelNum
> 0 && counter < panelNum * config['eventsPerWidget'].Value +
1) {
756 log('skipping (already in first widget) ' + entry.id);
760 // mark overdue todos
762 if (entry.Type == 'ToDo' && date != null) {
763 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
0,
0,
0);
764 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
765 if (tmp1.getTime() < tmp2.getTime()) {
770 // generate html output
771 entriesHtml += '
<tr>';
772 if (config['showCalendarIndicator'].Value && calendarList.length - config['excludedCalendars'].Value.length
> 1) {
773 entriesHtml += '
<td><span class=
"calendar' + calendarColors[entry.CalendarName] + '"> </span></td>';
775 entriesHtml += '
<td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
777 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
778 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
780 var weekDay = date.toLocaleDateString().substr(
0,config['weekDayLength'].Value);
781 var time = formatTime(date);
782 var dateStr = formatDate(date, entryDate);
783 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
784 dateStr = '
<span class=
"overdue">' + config['overdueText'].Value + '
</span>';
785 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
786 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
787 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
788 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
790 entriesHtml += '
<td class=
"weekDay" width=
"1px">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
791 } else if (entry.Type == 'Meeting') {
792 if (config['showCombinedDateTime'].Value) {
794 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
795 else if (isTomorrow(date))
796 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
798 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
800 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
801 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
803 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
807 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
810 entriesHtml += '
</table>';
811 if (config['showNothingText'].Value && entriesHtml == '
<table></table>') {
812 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
813 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '
</div>';
815 if (cacheEntriesHtml != entriesHtml) {
817 document.getElementById('calendarList').innerHTML = entriesHtml;
819 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
820 cacheEntriesHtml = entriesHtml;
823 lastUpdateTime = new Date();
825 error('displaying list:' + e + ', line ' + e.line);
830 // called by handleOnShow() and onResize events
831 function updateScreen()
833 log('updateScreen()');
835 // check if opening fullscreen
836 if( window.innerHeight
> 91 && mode ==
0) {
838 cacheEntriesHtml = '';
839 document.getElementById('body').style.backgroundImage =
"";
842 else if (window.innerHeight <=
91 && mode !=
0) {
844 cacheEntriesHtml = '';
849 updateHomescreen(); // check for screen rotation
854 function handleOnShow()
858 var time = new Date();
859 if (time.getTime() - lastUpdateTime.getTime()
> config['updateDataInterval'].Value *
60 *
1000) {
860 log('updateScreen(): force updateData() because last update was too long ago (' + (time.getTime() - lastUpdateTime.getTime()) /
1000 + 's)');
863 setUpdateTimer(); // reinitialize update timer
867 function launchCalendar()
870 widget.openApplication(config['calendarApp'].Value,
"");
871 if (config['hideWidgetOnCalendarOpen'].Value)
874 error('starting Calendar App');
881 log('New widget instance starting up...');
884 // call calendar service
885 if (device !=
"undefined")
886 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
888 throw('device object does not exist');
890 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>');
894 calendarList = listCalendars();
896 updateCalendarColors();
899 requestNotification();
900 document.getElementById(
"settingsTitle").innerHTML = getLocalizedText('menu.settings');
902 if (window.innerHeight
> 91) {
903 mode =
0; // we're starting fullscreen, we set mode to homescreen in order to let updateScreen() do all the work for us
908 log(
"init(): updateScreen()");
910 if (config['useBackgroundImage'].Value)
911 // check for screen rotation every
1 secs
912 screenRotationTimer = window.setInterval('checkOrientation()',
1000 *
1);
914 // call updateScreen() when widget changes from background to forground
915 window.widget.onshow = handleOnShow;
917 log(
"init(): finished...");
919 statupSuccessful = true;
922 function checkOrientation()
926 updateHomescreen(); // check for screen rotation
929 function setUpdateTimer()
931 updateTimer = window.setInterval('updateTimerCallback()',
1000 *
60 * config['updateDataInterval'].Value);
934 function clearUpdateTimer()
936 window.clearInterval(updateTimer);
939 function updateTimerCallback()
941 log(
"updateTimerCallback()");
945 function createMenu()
947 window.menu.setLeftSoftkeyLabel(
"",null);
948 window.menu.setRightSoftkeyLabel(
"",null);
950 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
951 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
952 var menuHelp = new MenuItem(getLocalizedText('menu.help'), id++);
953 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
954 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
955 menuSettings.onSelect = showSettings;
956 menuAbout.onSelect = showAbout;
957 menuCallApp.onSelect = launchCalendar;
958 menuUpdate.onSelect = showUpdate;
959 menuHelp.onSelect = showHelp;
961 window.menu.append(menuCallApp);
962 window.menu.append(menuSettings);
963 window.menu.append(menuHelp);
964 window.menu.append(menuUpdate);
965 window.menu.append(menuAbout);
968 function showSettings()
972 document.getElementById(
"settingsView").style.display =
"block";
973 document.onclick = null;
975 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
977 for (var key in config) {
978 if (config[key].Type == 'String')
979 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
980 else if (config[key].Type == 'Int') {
981 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
982 if (config[key].Value <
0 || isNaN(config[key].Value))
983 config[key].Value = config[key].Default;
985 else if (config[key].Type == 'Bool')
986 config[key].Value = document.forms[
0].elements[
"settings." + key].checked;
987 else if (config[key].Type == 'UID') {
988 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
989 if (isNaN(config[key].Value))
990 config[key].Value = config[key].Default;
992 else if (config[key].Type == 'Enum') {
993 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
994 if (config[key].ValidValues.indexOf(config[key].Value) == -
1)
995 config[key].Value = config[key].Default;
997 else if (config[key].Type == 'Array') {
998 if (key == 'excludedCalendars') {
999 config[key].Value = new Array();
1000 for(var i=
0; i < calendarList.length; i++) {
1001 var element = document.forms[
0].elements[
"settings." + key +
"." + calendarList[i]];
1002 if (element != null && element.checked == false)
1003 config[key].Value.push(calendarList[i]);
1016 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
1022 var settingsHtml = '
<form>';
1023 for (var key in config) {
1024 if (config[key].Type == 'String') {
1026 if (key.substring(
0,
9) ==
"cssStyle_")
1027 prefix = getLocalizedText('settings.cssStyle_prefix');
1028 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 />';
1030 else if (config[key].Type == 'Int')
1031 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 />';
1032 else if (config[key].Type == 'Bool')
1033 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 />';
1034 else if (config[key].Type == 'UID')
1035 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 />';
1036 else if (config[key].Type == 'Enum') {
1037 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><select name=
"settings.' + key + '" size=
"1">';
1038 for(var i =
0; i < config[key].ValidValues.length; i++)
1039 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>';
1040 settingsHtml += '
</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1042 else if (config[key].Type == 'Array') {
1043 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br />';
1044 if (key == 'excludedCalendars') {
1045 for(var i=
0; i < calendarList.length; i++) {
1046 var checked = '
checked=
"checked"';
1047 if (config[key].Value.indexOf(calendarList[i]) != -
1)
1049 settingsHtml += '
<input name=
"settings.' + key + '.' + calendarList[i] + '" type=
"checkbox" value=
"' + calendarList[i] + '" ' + checked + '
/> ' + calendarList[i] + '
<br />';
1052 settingsHtml += '
</td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1055 settingsHtml += '
<input name=
"reset" type=
"button" value=
"' + getLocalizedText('settings.restoreDefaults') + '" onclick=
"javascript:restoreDefaultSettings();showSettings();" />';
1056 settingsHtml += '
</form>';
1057 document.getElementById(
"settingsList").innerHTML = settingsHtml;
1060 function changeCssClass(classname, properties)
1062 for(var i =
0; i < document.styleSheets[
0]['cssRules'].length; i++)
1064 if (document.styleSheets[
0]['cssRules'][i].selectorText == classname) {
1065 document.styleSheets[
0].deleteRule(i);
1066 document.styleSheets[
0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[
0]['cssRules'].length);
1072 function updateCssClasses()
1074 for(var key in config) {
1075 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
1079 function getSettingsCalEntryId()
1081 if (settingsCalEntryId == null) {
1082 // check if entry already exists
1083 var listFiltering = {
1084 Type:'CalendarEntry',
1086 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!
1087 EndRange: new Date(
2000,
0,
2),
1088 SearchText: 'ComingNext Settings|',
1094 result = calendarService.IDataSource.GetList(listFiltering);
1095 if (result.ErrorCode)
1096 throw(result.ErrorMessage);
1099 error(
"getSettingsCalEntryId: GetList() failed: " + e + ', line ' + e.line);
1102 var list = result.ReturnValue;
1103 var entry = list.getNext();
1104 if (entry != undefined) {
1105 settingsCalEntryId = entry.LocalId;
1106 log(
"settingsCalEntryId=" + settingsCalEntryId);
1108 else { // create settings item
1109 var item = new Object();
1110 item.Type =
"DayEvent";
1111 item.StartTime = new Date(
2000,
0,
1);
1112 item.Summary =
"ComingNext Settings|";
1114 var criteria = new Object();
1115 criteria.Type =
"CalendarEntry";
1116 criteria.Item = item;
1119 var result = calendarService.IDataSource.Add(criteria);
1120 if (result.ErrorCode)
1121 throw(result.ErrorMessage);
1123 error(
"getSettingsCalEntryId: " + e + ', line ' + e.line);
1126 getSettingsCalEntryId();
1131 function restoreDefaultSettings()
1133 for (var key in config)
1134 config[key].Value = config[key].Default;
1137 function loadSettings()
1139 getSettingsCalEntryId();
1140 var listFiltering = {
1141 Type:'CalendarEntry',
1143 LocalId: settingsCalEntryId
1148 result = calendarService.IDataSource.GetList(listFiltering);
1149 if (result.ErrorCode)
1150 throw(result.ErrorMessage);
1153 error(
"loadSettings: GetList() failed: " + e + ', line ' + e.line);
1156 var entry = result.ReturnValue.getNext();
1157 if (entry != undefined) {
1158 log(
"Loading Settings...");
1159 // only reload settings if they chanced since the last reload
1160 if (settingsCache != entry.Summary)
1162 restoreDefaultSettings();
1163 var stringlist = entry.Summary.split(
"|");
1164 // skip the first two entries, those contain header and version info
1165 for(var i =
2; i < stringlist.length -
1; i++) {
1166 var pair = stringlist[i].split('=');
1168 var value = pair[
1];
1169 if (key == null || value == null || config[key] == null) {
1170 log('Warning: unknown or invalid setting: ' + stringlist[i]);
1173 log('stringlist: ' + key + '=\'' + value + '\'');
1174 if (config[key].Type == 'Int') {
1175 config[key].Value = Number(value);
1176 if (isNaN(config[key].Value))
1177 config[key].Value = config[key].Default;
1179 else if (config[key].Type == 'String')
1180 config[key].Value = value;
1181 else if (config[key].Type == 'Bool')
1182 config[key].Value = (value == 'true')
1183 else if (config[key].Type == 'Enum')
1184 config[key].Value = value;
1185 else if (config[key].Type == 'UID') {
1186 config[key].Value = Number(value);
1187 if (isNaN(config[key].Value))
1188 config[key].Value = config[key].Default;
1190 else if (config[key].Type == 'Array') {
1191 config[key].Value = value.split(
"^");
1192 if (config[key].Value.length ==
1 && config[key].Value[
0] ==
"") {
1193 config[key].Value = [];
1197 settingsCache = entry.Summary;
1201 log(
"Settings already cached and did not change");
1205 error(
"Failed to load settings, calendar entry could not be found");
1209 function saveSettings()
1211 getSettingsCalEntryId();
1212 var item = new Object();
1213 item.Type =
"DayEvent";
1214 item.StartTime = new Date(
2000,
0,
1);
1215 item.LocalId = settingsCalEntryId;
1216 item.Summary =
"ComingNext Settings|" + version +
"|";
1218 for (var key in config) {
1219 if (config[key].Type == 'Int')
1220 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1221 else if (config[key].Type == 'String')
1222 item.Summary += key +
"=" + config[key].Value +
"|";
1223 else if (config[key].Type == 'Bool')
1224 item.Summary += key +
"=" + (config[key].Value ? 'true' : 'false') +
"|";
1225 else if (config[key].Type == 'Enum')
1226 item.Summary += key +
"=" + config[key].Value +
"|";
1227 else if (config[key].Type == 'UID')
1228 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1229 else if (config[key].Type == 'Array')
1230 item.Summary += key +
"=" + config[key].Value.join(
"^") +
"|";
1232 settingsCache = item.Summary;
1234 var criteria = new Object();
1235 criteria.Type =
"CalendarEntry";
1236 criteria.Item = item;
1238 log(
"Saving settings to calendar entry: " + item.Summary);
1240 var result = calendarService.IDataSource.Add(criteria);
1241 if (result.ErrorCode)
1242 throw(result.ErrorMessage);
1244 error(
"saveSettings: " + e + ', line ' + e.line);
1247 lastReloadTime = null; // force calendar data reload on next update
1252 function toggleVisibility(elementId)
1254 if (document.getElementById(elementId).style.display ==
"none")
1255 document.getElementById(elementId).style.display =
"block";
1257 document.getElementById(elementId).style.display =
"none";
1261 function printHintBox(text)
1264 return '
<td width=
"1%" align=
"right" onclick=
"javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '
</td></tr></table>'+
1265 '
<div class=
"settingsInfo" id=
"info' + uniqueId + '">' + text + '
</div>';
1268 function showAbout()
1272 document.getElementById(
"aboutView").style.display =
"block";
1273 document.onclick = null;
1275 window.menu.setLeftSoftkeyLabel(
" ", function(){});
1276 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1282 //document.getElementById(
"aboutView").innerHTML = 'aboutView';
1283 document.getElementById(
"name").innerHTML =
"Coming Next " + version;
1286 function showHelp() {
1287 widget.openURL('http://comingnext.sf.net/help');
1290 function updateFullscreen()
1294 function showFullscreen()
1296 log(
"showFullscreen()");
1298 document.getElementById(
"fullscreenView").style.display =
"block";
1299 document.getElementById('body').className =
"backgroundFullscreen";
1301 document.onclick = launchCalendar;
1306 function getBackgroundImage()
1311 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[
0]) // internal
1312 bgImage = 'background_' + orientation + '.png';
1314 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
1318 function updateHomescreen()
1320 if (config['useBackgroundImage'].Value) {
1321 // check if we have a completely unknown screen resolution
1322 var screenHeight = screen.height;
1323 var screenWidth = screen.width;
1324 if (screenHeight !=
640 && screenHeight !=
480 && screenHeight !=
360)
1325 screenHeight =
360; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1326 if (screenWidth !=
640 && screenWidth !=
480 && screenWidth !=
360)
1327 screenWidth =
640; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1329 // check for screen rotation
1330 if (orientation != 'portrait' && ((screenWidth ==
360 && screenHeight ==
640) || (screenWidth ==
640 && screenHeight ==
480))) {
1331 window.widget.prepareForTransition(
"fade");
1332 orientation = 'portrait';
1333 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1334 document.getElementById('body').style.backgroundColor = 'none';
1335 window.widget.performTransition();
1336 } else if (orientation != 'landscape' && ((screenWidth ==
640 && screenHeight ==
360) || (screenWidth ==
480 && screenHeight ==
640))) {
1337 window.widget.prepareForTransition(
"fade");
1338 orientation = 'landscape';
1339 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1340 document.getElementById('body').style.backgroundColor = 'none';
1341 window.widget.performTransition();
1343 else if (document.getElementById('body').style.backgroundImage ==
"")
1345 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1350 function showHomescreen()
1352 log(
"showHomescreen()");
1354 document.getElementById(
"homescreenView").style.display =
"block";
1355 document.getElementById('body').className =
"background";
1356 document.onclick = null;
1360 function getLocalizedText(p_Txt)
1362 if (localizedText[p_Txt])
1363 return localizedText[p_Txt];
1365 return 'ERROR: missing translation for ' + p_Txt;
1368 function showUpdate()
1372 document.getElementById(
"updateView").style.display =
"block";
1373 document.onclick = null;
1375 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1378 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1384 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
1388 function checkForUpdate()
1390 // asynch XHR to server url
1391 reqV = new XMLHttpRequest();
1392 reqV.onreadystatechange = checkForUpdateCallback;
1393 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
1394 reqV.open(
"GET", versionURL, true);
1395 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1399 function checkForUpdateCallback()
1401 if (reqV.readyState ==
4) {
1402 if (reqV.status ==
200) {
1403 var resultXml = reqV.responseText;
1405 var div = document.getElementById(
"tmp");
1406 div.innerHTML = resultXml;
1407 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
1408 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
1410 if (version != newVersion) {
1411 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1414 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1419 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1424 function hideViews()
1426 document.getElementById(
"homescreenView").style.display =
"none";
1427 document.getElementById(
"fullscreenView").style.display =
"none";
1428 document.getElementById(
"aboutView").style.display =
"none";
1429 document.getElementById(
"settingsView").style.display =
"none";
1430 document.getElementById(
"updateView").style.display =
"none";
1433 function listCalendars()
1443 DefaultCalendar: false
1447 var calendarsResult = calendarService.IDataSource.GetList(criteria);
1448 if (calendarsResult.ErrorCode !=
0)
1449 throw(
"Error fetching list of calendars: " + calendarsResult.ErrorCode + ': ' + calendarsResult.ErrorMessage);
1450 var calendarListIterator = calendarsResult.ReturnValue;
1455 while (( item = calendarListIterator.getNext()) != undefined ) {
1456 calendars[count++] = item;
1458 log(
"Available Calendars: " + calendars.join(
", "));
1461 error('listing calendars:' + e + ', line ' + e.line);
1466 // Copies all objects and their properties to an array. Data is copied so nothing gets lost when the reference is removed
1467 // 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
1468 function listToArray(list, calendarName)
1470 var array = new Array();
1473 while (( item = list.getNext()) != undefined ) {
1474 var itemCopy = new Object();
1475 for(var i=
0; i < entryFields.length; i++) {
1476 itemCopy[entryFields[i]] = item[entryFields[i]];
1478 // for some reason, the CalendarName property is never correctly queried, so we assign it manually here
1479 if (!itemCopy['CalendarName']) {
1480 itemCopy['CalendarName'] = calendarName;
1482 array.push(itemCopy);
1483 txt += array[array.length -
1].Summary +
", ";
1485 log(
"listToArray(): " + txt);
1489 function sortCalendarEntries(a, b)
1492 log(
"sortCalendarEntries(" + a.Summary +
"," + b.Summary +
")");
1494 if (a.InstanceStartTime != null) {
1495 atime = a.InstanceStartTime;
1497 else if (a.StartTime != null) {
1498 atime = a.StartTime;
1500 else if (a.InstanceEndTime != null) {
1501 atime = a.InstanceEndTime;
1503 else if (a.EndTime != null) {
1507 if (b.InstanceStartTime != null) {
1508 btime = b.InstanceStartTime;
1510 else if (b.StartTime != null) {
1511 btime = b.StartTime;
1513 else if (b.InstanceEndTime != null) {
1514 btime = b.InstanceEndTime;
1516 else if (b.EndTime != null) {
1520 if (atime && btime) {
1522 atime = parseDate(atime);
1523 btime = parseDate(btime);
1525 // sort by date & time
1526 if (atime < btime) {
1529 else if (atime
> btime) {
1533 else if (a.Type != b.Type) {
1534 if (a.Type < b.Type) {
1537 else if (a.Type
> b.Type) {
1541 // sort by description
1542 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1543 if (a.Summary < b.Summary) {
1546 else if (a.Summary
> b.Summary) {
1551 // NOTE: events my have no date information at all. In that case, we list events without date first
1552 else if (atime && !btime) {
1555 else if (!atime && btime) {
1558 else if (!atime && !btime) {
1560 if (a.Type != b.Type) {
1561 if (a.Type < b.Type) {
1564 else if (a.Type
> b.Type) {
1568 // sort by description
1569 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1570 if (a.Summary < b.Summary) {
1573 else if (a.Summary
> b.Summary) {
1582 function updateCalendarColors()
1585 calendarColors = [];
1586 if (calendarList.length
> maxColors) {
1587 log(
"updateCalendarColors(): Warning: more calendars than available indicator colors");
1589 for(var i=
0; i < calendarList.length; i++) {
1590 calendarColors[calendarList[i]] = (i % maxColors) +
1;
1594 function log(message)
1596 if (config['enableLogging'].Value) {
1597 console.info(message);
1603 <style type=
"text/css">
1605 table { margin:
0px; padding:
0px; border-spacing:
0px; }
1606 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
1607 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1608 .settingsInfo { display:none; font-style:italic; }
1609 .title { font-weight:bold; font-size:
14pt; }
1610 .textInput { width:
90%; }
1611 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1612 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
1613 #calendarList { position:absolute; left:
5px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
1614 #name { text-align:center; }
1615 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1616 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1621 <body onload=
"javascript:setTimeout('init()', 10)" onresize=
"javascript:updateScreen()" id=
"body" class=
"background">
1622 <div id=
"homescreenView">
1623 <div id=
"calendarList">loading...
</div>
1625 <div id=
"fullscreenView" style=
"display:none;">
1626 <img src=
"Icon.png" id=
"smallappicon">
1627 <h1 class=
"title">Coming Next
</h1>
1629 <div id=
"fullscreenCalendarList">loading...
</div>
1631 <div id=
"settingsView" style=
"display:none">
1632 <img src=
"Icon.png" id=
"smallappicon">
1633 <h1 id=
"settingsTitle" class=
"title">Settings
</h1>
1635 <div id=
"settingsList"></div>
1637 <div id=
"aboutView" style=
"display:none">
1638 <img src=
"Icon.png" id=
"appicon">
1639 <h1 id=
"name">Coming Next
</h1>
1641 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1642 <p>Contributions:
</p>
1643 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1644 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1645 <p class=
"credits">Christophe Milsent (translation support & french translation)
</p>
1646 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation)
</p>
1647 <p class=
"credits">Tokeda (russian translation)
</p>
1648 <p class=
"credits">Marcella Ferrari (italian translation)
</p>
1649 <p class=
"credits">Venos (italian translation)
</p>
1650 <p>This software is open source and licensed under the GPLv3.
</p>
1651 <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>
1654 <div id=
"updateView" style=
"display:none">
1655 <img src=
"Icon.png" id=
"smallappicon">
1656 <h1 class=
"title">Check for update
</h1>
1658 <div id=
"currentVersion">Coming Next ??
</div>
1659 <div id=
"updateDiv"></div>
1660 <div id=
"tmp" style=
"display:none;"></div>