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 = [];
91 var weekdays_translated = [];
94 var mode =
0; //
0 = homescreen,
1 = fullscreen,
2 = settings,
3 = about,
4 = check for update
96 var settingsCalEntryId = null;
97 var settingsCache = null;
98 var notificationRequests = new Array();
99 var calendarList = [];
100 var calendarColors = [];
101 var updateTimer = null;
102 var screenRotationTimer = null;
103 var lastUpdateTime = now; // last time we updated the display
104 var lastReloadTime = null; // last time we fetched calendar data
105 var reloadInterval =
6 *
60 *
60 *
1000; // =
6 hours; time interval for reloading calendar data
106 var errorOccured = false;
107 var entryLists = null; // stores all fetched calendar entries until data is refreshed
108 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.
110 // vars for daylight saving time
111 var summertime = false; // true, if current date is in summer, false if in winter
112 var daylightSavingDates = new Object(); // caches calculated DST winter and summer time shift dates
114 // this is a list of data fields a calendar event can have
128 function isLeapYear( year ) {
129 if (( year %
4 ==
0 && year %
100 !=
0 ) || year %
400 ==
0 )
135 function calcLeapYear(year, days)
137 if (isLeapYear(year))
143 function subToSunday(myDate, year, days, prevMonthDays)
145 for (i = myDate.getDay(); i
> 0 ;i--)
147 days -= prevMonthDays;
148 days = isLeapYear(year) ? --days : days;
152 function isSummertime(curDate)
157 // if we already calculated DST summer and winter time dates for this year, use cached values
158 var dst = daylightSavingDates[curDate.getFullYear()];
160 var thisYearS = new Date(curDate.getFullYear(),
3,
0,
0,
0,
0 );
161 var thisYearW = new Date(curDate.getFullYear(),
10,
0,
0,
0,
0 );
162 var nextYearS = new Date(curDate.getFullYear() +
1,
3,
0,
0,
0,
0 );
163 var nextYearW = new Date(curDate.getFullYear() +
1,
10,
0,
0,
0,
0 );
165 thisYearSDays = nextYearSDays =
90;
166 thisYearWDays = nextYearWDays =
304;
168 thisYearSDays = calcLeapYear(curDate.getFullYear(), thisYearSDays);
169 thisYearWDays = calcLeapYear(curDate.getFullYear(), thisYearWDays);
170 nextYearSDays = calcLeapYear(curDate.getFullYear() +
1, nextYearSDays);
171 nextYearWDays = calcLeapYear(curDate.getFullYear() +
1, nextYearWDays);
173 thisYearSDays = subToSunday(thisYearS, curDate.getFullYear(), thisYearSDays,
59);
174 thisYearWDays = subToSunday(thisYearW, curDate.getFullYear(), thisYearWDays,
273);
175 nextYearSDays = subToSunday(nextYearS, curDate.getFullYear() +
1, nextYearSDays,
59);
176 nextYearWDays = subToSunday(nextYearW, curDate.getFullYear() +
1, nextYearWDays,
273);
179 Summer: new Date (curDate.getFullYear(),
03-
1, thisYearSDays,
2,
0,
0),
180 Winter: new Date (curDate.getFullYear(),
10-
1, thisYearWDays,
2,
0,
0),
182 daylightSavingDates[curDate.getFullYear()] = dst;
185 if (dst.Summer < curDate)
187 if (dst.Winter < curDate)
189 if (summer && !winter)
195 function error(message)
197 console.info('Error: ' + message);
198 document.getElementById(
"calendarList").innerHTML = 'Error: ' + message;
199 document.getElementById(
"fullscreenCalendarList").innerHTML = 'Error: ' + message;
201 document.onclick = null;
204 function areDatesEqual(date1, date2)
206 return (date1.getFullYear() == date2.getFullYear() &&
207 date1.getMonth() == date2.getMonth() &&
208 date1.getDate() == date2.getDate());
211 function isTomorrow(date)
213 // tommorow = now +
1 day
214 // ToDo: some days can be shorter as
24 hours(daylight saving change day)
215 return areDatesEqual(date, new Date (now.getTime() +
24*
60*
60*
1000));
218 function isToday(date)
220 return areDatesEqual(date, now);
223 function collectLocales()
225 var tmpyear =
2000 + panelNum;
228 if (months_translated.length
> 0)
230 for (month =
0; month <
12; month++) {
231 var startDate = new Date(tmpyear, month,
15);
233 var item = new Object();
234 item.Type =
"DayEvent";
235 item.StartTime = startDate;
236 item.Summary =
"__temp" + month;
238 var criteria = new Object();
239 criteria.Type =
"CalendarEntry";
240 criteria.Item = item;
243 var result = calendarService.IDataSource.Add(criteria);
244 if (result.ErrorCode)
245 throw(result.ErrorMessage);
247 error(
"collectLocales: " + e + ', line ' + e.line);
250 for (weekday =
0; weekday <
7; weekday++) {
251 var startDate = new Date(
2000,
0,
2 + weekday); // date that we know for sure is a sunday
253 var item = new Object();
254 item.Type =
"DayEvent";
255 item.StartTime = startDate;
256 item.Summary =
"__weekday_temp" + weekday;
258 var criteria = new Object();
259 criteria.Type =
"CalendarEntry";
260 criteria.Item = item;
263 var result = calendarService.IDataSource.Add(criteria);
264 if (result.ErrorCode)
265 throw(result.ErrorMessage);
267 error(
"collectLocales: " + e + ', line ' + e.line);
271 var startTime = new Date(tmpyear,
0,
1);
272 var endTime = new Date(tmpyear,
11,
31);
273 var listFiltering = {
274 Type:'CalendarEntry',
276 StartRange: startTime,
278 SearchText: '__temp',
282 var result = calendarService.IDataSource.GetList(listFiltering);
283 if (result.ErrorCode)
284 throw(result.ErrorMessage);
285 var list = result.ReturnValue;
287 error(
"collectLocales: " + e + ', line ' + e.line);
290 var ids = new Array();
296 while (list && (entry = list.getNext()) != undefined) {
297 dateArr = (entry.StartTime + '').replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
298 var day = dateArr[
1];
299 var month = dateArr[
2];
300 var year = dateArr[
3];
302 // make sure month is set properly
303 if (isNaN(parseInt(day))) {
307 } else if (isNaN(parseInt(year))) {
313 log(entry.StartTime + ' -
> ' + month + ' ' + counter);
314 ids[counter] = entry.id;
315 months_translated[month] = counter +
1;
319 error(
"collectLocales: " + e + ', line ' + e.line);
323 var startTime = new Date(
2000,
0,
2);
324 var endTime = new Date(
2000,
0,
9);
325 var listFiltering = {
326 Type:'CalendarEntry',
328 StartRange: startTime,
330 SearchText: '__weekday_temp',
334 var result = calendarService.IDataSource.GetList(listFiltering);
335 if (result.ErrorCode)
336 throw(result.ErrorMessage);
337 var weekdaylist = result.ReturnValue;
339 error(
"collectLocales: " + e + ', line ' + e.line);
347 while (weekdaylist && (entry = weekdaylist.getNext()) != undefined) {
348 curWeekday = (entry.StartTime + '').split(',')[
0];
349 log(entry.StartTime + ' -
> ' + curWeekday + ' ' + counter2);
350 ids[counter + counter2] = entry.id;
351 weekdays_translated[counter2] = curWeekday;
355 error(
"collectLocales: " + e + ', line ' + e.line);
360 var criteria = new Object();
361 criteria.Type =
"CalendarEntry";
366 var result = calendarService.IDataSource.Delete(criteria);
367 if (result.ErrorCode)
368 throw(result.ErrorMessage);
370 error('deleting temp calendar entries:' + e + ', line ' + e.line);
375 function requestNotification()
377 var criteria = new Object();
378 criteria.Type =
"CalendarEntry";
379 criteria.Filter = new Object();
380 for(var i=
0; i < calendarList.length; i++) {
381 criteria.Filter.CalendarName = calendarList[i];
383 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria, callback);
384 if (notificationRequest.ErrorCode)
385 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
386 notificationRequests.push(notificationRequest);
388 error(
"requestNotification: " + e + ', line ' + e.line);
392 var criteria2 = new Object();
393 criteria2.Type =
"CalendarEntry";
394 criteria2.Filter = new Object();
395 criteria2.Filter.LocalIdList = new Array();
396 criteria2.Filter.LocalIdList[
0] = settingsCalEntryId;
398 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria2, settingsCallback);
399 if (notificationRequest.ErrorCode)
400 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
401 notificationRequests.push(notificationRequest);
403 error(
"requestNotification: " + e + ', line ' + e.line);
407 function cancelNotification()
409 for(var i=
0; i < notificationRequests.length; i++) {
411 var result = calendarService.IDataSource.Cancel(notificationRequests[i]);
412 if (result.ErrorCode)
413 error('cancelNotification failed with error code ' + result.ErrorCode);
415 error(
"cancelNotification: " + e + ', line ' + e.line);
420 function callback(transId, eventCode, result)
422 log(
"callback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
423 lastReloadTime = null; // force calendar data reload on next update
427 function settingsCallback(transId, eventCode, result)
429 log(
"settingsCallback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
433 function parseDate(dateString)
436 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:
437 Wednesday,
26 August,
2009 24:
00:
00
438 Wednesday,
26 August,
2009 12:
00:
00 am
439 Wednesday, August
26,
2009 12:
00:
00 am
440 Wednesday,
2009 August,
26 12:
00:
00 am
441 Wednesday,
2009 August,
28 8.00.00 pm
442 Wednesday,
2009 August,
28 08:
00:
00 PM
446 if (dateString ==
"" || dateString == null || dateString == undefined)
448 if (dateString instanceof Date) {
449 // we already have a date object, no need to parse string here
453 var dateArr = (dateString + '').replace(/,/g, '').replace(/\./g, ':').replace(/ /g, ' ').split(' ');
454 if (dateArr.length !=
5 && dateArr.length !=
6)
458 var weekDay = dateArr[
0];
459 var day = dateArr[
1];
460 var month = dateArr[
2];
461 var year = dateArr[
3];
462 // make sure month is set properly
463 if (isNaN(parseInt(day))) {
469 if (isNaN(parseInt(year))) {
474 // make sure day and year are set properly
475 if (Number(day)
> Number(year)) {
480 month = months_translated[month];
483 var timeArr = dateArr[
4].split(':');
484 if (timeArr.length !=
3)
486 var hours = Number(timeArr[
0]);
487 var minutes = Number(timeArr[
1]);
488 var seconds = Number(timeArr[
2]);
489 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'pm' && hours <
12)
491 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'am' && hours ==
12)
494 result = new Date(year, month -
1, day, hours, minutes, seconds);
497 // take care of daylight saving time
498 if (config['enableDaylightSaving'].Value) {
500 // determine if date is in summer or winter time
501 var dateSummerTime = isSummertime(result);
503 // work around bug in Nokias calendar api resulting in dates within a different DST to be off by
1 hour
504 if (summertime && !dateSummerTime) {
505 result = new Date(result.getTime() -
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // -
1 hour
506 log('parseDate(): fixing time -
1h: ' + result);
508 else if (!summertime && dateSummerTime) {
509 result = new Date(result.getTime() +
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // +
1 hour
510 log('parseDate(): fixing time +
1h: ' + result);
517 function getWeekdayLocalized(date) {
518 var localizedString = date.toLocaleDateString();
519 if (localizedString.match(/\d\d\/\d\d\/\d\d/)) {
520 return weekdays_translated[date.getDay()];
522 return localizedString.split(',')[
0];
525 // 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"
526 function formatDate(date, format)
528 var day = date.getDate().toString();
529 var month = (date.getMonth() +
1).toString();
530 while (day.length <
2) { day = '
0' + day; }
531 while (month.length <
2) { month = '
0' + month; }
533 if (config['showTodayAsText'].Value && isToday(date))
534 return '
<span class=
"today">' + config['todayText'].Value + '
</span>';
535 if (config['showTodayAsText'].Value && isTomorrow(date))
536 return '
<span class=
"tomorrow">' + config['tomorrowText'].Value + '
</span>';
538 if (format instanceof Date) {
539 // we don't know how to format this
540 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
541 return day + config['dateSeparator'].Value + month;
543 return month + config['dateSeparator'].Value + day;
545 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
546 if (dateArr.length !=
5 && dateArr.length !=
6) {
547 // we don't know how to format this
548 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
549 return day + config['dateSeparator'].Value + month;
551 return month + config['dateSeparator'].Value + day;
555 if (config['dateFormat'].Value == 'MMDD')
557 else if (config['dateFormat'].Value == 'DDMM')
560 // config['dateFormat'].Value == 'auto', try to detect system setting
562 var day_ = dateArr[
1];
563 var month_ = dateArr[
2];
564 var year_ = dateArr[
3];
565 // make sure month is set properly
566 if (isNaN(parseInt(day_))) {
571 } else if (isNaN(parseInt(year_))) {
577 // make sure day and year are set properly
578 if (Number(day_)
> Number(year_))
583 return day + config['dateSeparator'].Value + month;
585 return month + config['dateSeparator'].Value + day;
588 function formatTime(date)
590 // date is a Date() object
591 date.setSeconds(
0); // we don't care about seconds
592 var time = date.toLocaleTimeString().replace(/[\.:]
00/, ''); // remove seconds from string
593 if (time.replace(/\./, ':').split(':')[
0].length <
2)
595 if (config['showNowAsText'].Value && date.getTime() == now.getTime())
596 time = '
<span class=
"now">' + config['nowText'].Value + '
</span>';
600 function updateData()
607 // check if we got additional or less calendars since our last update
608 var newCalendarList = listCalendars();
609 if (newCalendarList == null) {
610 // Something went wrong fetching the calendars list.
611 // This usually happens when a backup is being made.
612 // Retry the next time updateData() is called by
613 // resetting errorOccured
614 log('updateData(): listCalendars() failed, trying again laster...');
615 cacheEntriesHtml = ''; // make sure we replace the currently shown error message on the next update
616 errorOccured = false;
619 if (newCalendarList.length != calendarList.length) {
620 calendarList = newCalendarList;
621 updateCalendarColors();
622 cancelNotification();
623 requestNotification();
624 lastReloadTime = null; // force calendar data reload on this update
629 // only reload calendar data every
6 hours, visual updates occure more often
630 if (!lastReloadTime || now.getTime() - lastReloadTime.getTime()
> reloadInterval) {
631 log('updateData(): reloading calendar data');
633 // meetings have time
634 // 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
635 summertime = isSummertime(now); // cache summer time info for today
636 var meetingList = [];
637 for(var i=
0; i < calendarList.length; i++) {
638 // ignore excluded calendars
639 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
641 var meetingListFiltering = {
642 Type:'CalendarEntry',
644 CalendarName: calendarList[i],
645 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
646 EndRange: (new Date(now.getFullYear(), now.getMonth() + config['monthRange'].Value, now.getDate(),
0,
0,
0))
649 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
650 if (meetingResult.ErrorCode !=
0)
651 throw(
"Error fetching calendar data: " + meetingResult.ErrorCode + ': ' + meetingResult.ErrorMessage);
652 var list = meetingResult.ReturnValue;
653 meetingList = meetingList.concat(listToArray(list, calendarList[i]));
655 log(
"updateData(): meetingList.sort()");
656 meetingList.sort(sortCalendarEntries);
658 // todos don't, they start on
00:
00 hrs., but should be visible anyway
659 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
660 if (config['includeTodos'].Value) {
661 var todayTodoList = [];
662 for(var i=
0; i < calendarList.length; i++) {
663 // ignore excluded calendars
664 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
666 var todayTodoListFiltering = {
667 Type:'CalendarEntry',
669 CalendarName: calendarList[i],
671 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
672 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
675 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
676 var list = todayTodoResult.ReturnValue;
677 todayTodoList = todayTodoList.concat(listToArray(list, calendarList[i]));
679 log(
"updateData(): todayTodoList.sort()");
680 todayTodoList.sort(sortCalendarEntries);
681 entryLists = [todayTodoList, meetingList];
683 entryLists = [meetingList];
685 lastReloadTime = new Date();
687 error('loading Calendar items list:' + e + ', line ' + e.line);
697 var fontsize = 'normal';
699 if (config['eventsPerWidget'].Value ==
3) {
701 changeCssClass('.icon', 'width:
20px; height:
20px');
703 else if (config['eventsPerWidget'].Value ==
5) {
705 changeCssClass('.icon', 'width:
10px; height:
10px');
707 else if (config['eventsPerWidget'].Value ==
6) {
709 changeCssClass('.icon', 'width:
8px; height:
8px');
713 changeCssClass('.icon', config['cssStyle_icon'].Value);
714 var entriesHtml = '
<table style=
"font-size:' + fontsize + ';">';
718 max = (panelNum +
1) * config['eventsPerWidget'].Value;
720 max =
30; // we can display a lot more events in fullscreen mode
722 if (config['enableLogging'].Value) {
724 for (var i=
0; i < entryLists.length; i++) {
725 listinfo = listinfo +
" " + entryLists[i].length;
726 var entrieslist =
"";
727 for (var j=
0; j < entryLists[i].length; j++) {
728 entrieslist += entryLists[i][j].Summary +
", ";
730 log(
"updateData(): entrieslist: " + entrieslist);
732 log(
"updateData(): inner loop, " + entryLists.length +
" lists, [" + listinfo +
"] entries");
735 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
736 for (var i=
0; counter < max && i < entryLists.length; i++) {
737 for (var j=
0; (counter < max) && (j < entryLists[i].length); j++) {
738 entry = entryLists[i][j];
741 // output event info for debugging
742 var entryInfo =
"event: ";
743 for(var k=
0; k < entryFields.length; ++k) {
744 if (entry[entryFields[k]] != undefined) {
745 entryInfo += entryFields[k] +
"=" + entry[entryFields[k]] +
",";
750 // we don't want ToDos when includeTodos == false or when they are completed
751 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !config['includeTodos'].Value)) {
752 log('skipping ' + entry.id );
757 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
758 if (eventIds[entry.id] ==
1 && entry.Type == 'ToDo') {
759 log('skipped (already included) ' + entry.id);
763 eventIds[entry.id] =
1;
765 // summary can be undefined!
766 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
767 if (entry.Location != '' && entry.Location != undefined && config['showLocation'].Value)
768 Summary += ', ' + entry.Location;
770 // fix by yves: determine start and end dates/times
771 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
772 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
774 // there can be ToDos that have no date at all!
775 if (entry.Type == 'ToDo' && entry.EndTime == null)
776 entryDate =
""; // this will cause parseDate(entryDate) to return null;
778 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
780 // Convert date/time string to Date object
781 var date = parseDate(entryDate);
782 log('date: ' + date);
783 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
784 log('endDate: ' + endDate);
786 // check if meeting event has already passed
787 if (entry.Type == 'Meeting') {
788 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
789 if (now.getTime()
> compareTime) {
790 log('skipping Meeting (already passed) ' + entry.id);
792 eventIds[entry.id] =
0;
797 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
798 if (entry.Type == 'Anniversary') {
799 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
800 if (date.getTime() < tmp.getTime()) {
801 log('skipping Anniversary (already passed) ' + entry.id);
803 eventIds[entry.id] =
0;
808 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
809 if (entry.Type == 'DayEvent' && endDate != null) {
810 endDate.setMinutes(endDate.getMinutes() -
1);
811 log('fixing DayEvent endDate: ' + endDate);
812 if (now.getTime()
> endDate.getTime()) {
813 log('event already passed ' + entry.id);
815 eventIds[entry.id] =
0;
820 // check if the event is currently taking place
821 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
822 // check if we are between start and endtime
823 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
824 date = now; // change appointment date/time to now
825 log('event is currently taking place: ' + date);
829 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
830 if (mode ==
0 && panelNum
> 0 && counter < panelNum * config['eventsPerWidget'].Value +
1) {
831 log('skipping (already in first widget) ' + entry.id);
835 // mark overdue todos
837 if (entry.Type == 'ToDo' && date != null) {
838 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
0,
0,
0);
839 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
840 if (tmp1.getTime() < tmp2.getTime()) {
845 // generate html output
846 entriesHtml += '
<tr>';
847 if (config['showCalendarIndicator'].Value && calendarList.length - config['excludedCalendars'].Value.length
> 1) {
848 entriesHtml += '
<td><span class=
"calendar' + calendarColors[entry.CalendarName] + '"> </span></td>';
850 entriesHtml += '
<td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
852 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
853 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
855 var weekDay = getWeekdayLocalized(date).substr(
0,config['weekDayLength'].Value);
856 log('date.toLocaleDateString(): ' + date.toLocaleDateString());
857 log('weekDay: ' + weekDay);
858 var time = formatTime(date);
859 var dateStr = formatDate(date, entryDate);
860 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
861 dateStr = '
<span class=
"overdue">' + config['overdueText'].Value + '
</span>';
862 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
863 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
864 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
865 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
867 entriesHtml += '
<td class=
"weekDay" width=
"1px">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
868 } else if (entry.Type == 'Meeting') {
869 if (config['showCombinedDateTime'].Value) {
871 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
872 else if (isTomorrow(date))
873 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
875 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
877 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
878 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
880 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
884 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
887 entriesHtml += '
</table>';
888 if (config['showNothingText'].Value && entriesHtml == '
<table></table>') {
889 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
890 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '
</div>';
892 if (cacheEntriesHtml != entriesHtml) {
894 document.getElementById('calendarList').innerHTML = entriesHtml;
896 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
897 cacheEntriesHtml = entriesHtml;
900 lastUpdateTime = new Date();
902 error('displaying list:' + e + ', line ' + e.line);
907 // called by handleOnShow() and onResize events
908 function updateScreen()
910 log('updateScreen()');
912 // check if opening fullscreen
913 if( window.innerHeight
> 91 && mode ==
0) {
915 cacheEntriesHtml = '';
916 document.getElementById('body').style.backgroundImage =
"";
919 else if (window.innerHeight <=
91 && mode !=
0) {
921 cacheEntriesHtml = '';
926 updateHomescreen(); // check for screen rotation
931 function handleOnShow()
935 var time = new Date();
936 if (time.getTime() - lastUpdateTime.getTime()
> config['updateDataInterval'].Value *
60 *
1000) {
937 log('updateScreen(): force updateData() because last update was too long ago (' + (time.getTime() - lastUpdateTime.getTime()) /
1000 + 's)');
940 setUpdateTimer(); // reinitialize update timer
944 function launchCalendar()
947 widget.openApplication(config['calendarApp'].Value,
"");
948 if (config['hideWidgetOnCalendarOpen'].Value)
951 error('starting Calendar App');
958 log('New widget instance starting up...');
961 // call calendar service
962 if (device !=
"undefined")
963 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
965 throw('device object does not exist');
967 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>');
971 calendarList = listCalendars();
973 updateCalendarColors();
976 requestNotification();
977 document.getElementById(
"settingsTitle").innerHTML = getLocalizedText('menu.settings');
979 if (window.innerHeight
> 91) {
980 mode =
0; // we're starting fullscreen, we set mode to homescreen in order to let updateScreen() do all the work for us
985 log(
"init(): updateScreen()");
987 if (config['useBackgroundImage'].Value)
988 // check for screen rotation every
1 secs
989 screenRotationTimer = window.setInterval('checkOrientation()',
1000 *
1);
991 // call updateScreen() when widget changes from background to forground
992 window.widget.onshow = handleOnShow;
994 log(
"init(): finished...");
996 statupSuccessful = true;
999 function checkOrientation()
1003 updateHomescreen(); // check for screen rotation
1006 function setUpdateTimer()
1008 updateTimer = window.setInterval('updateTimerCallback()',
1000 *
60 * config['updateDataInterval'].Value);
1011 function clearUpdateTimer()
1013 window.clearInterval(updateTimer);
1016 function updateTimerCallback()
1018 log(
"updateTimerCallback()");
1022 function createMenu()
1024 window.menu.setLeftSoftkeyLabel(
"",null);
1025 window.menu.setRightSoftkeyLabel(
"",null);
1027 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
1028 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
1029 var menuHelp = new MenuItem(getLocalizedText('menu.help'), id++);
1030 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
1031 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
1032 menuSettings.onSelect = showSettings;
1033 menuAbout.onSelect = showAbout;
1034 menuCallApp.onSelect = launchCalendar;
1035 menuUpdate.onSelect = showUpdate;
1036 menuHelp.onSelect = showHelp;
1037 window.menu.clear();
1038 window.menu.append(menuCallApp);
1039 window.menu.append(menuSettings);
1040 window.menu.append(menuHelp);
1041 window.menu.append(menuUpdate);
1042 window.menu.append(menuAbout);
1045 function showSettings()
1049 document.getElementById(
"settingsView").style.display =
"block";
1050 document.onclick = null;
1052 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
1054 for (var key in config) {
1055 if (config[key].Type == 'String')
1056 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
1057 else if (config[key].Type == 'Int') {
1058 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
1059 if (config[key].Value <
0 || isNaN(config[key].Value))
1060 config[key].Value = config[key].Default;
1062 else if (config[key].Type == 'Bool')
1063 config[key].Value = document.forms[
0].elements[
"settings." + key].checked;
1064 else if (config[key].Type == 'UID') {
1065 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
1066 if (isNaN(config[key].Value))
1067 config[key].Value = config[key].Default;
1069 else if (config[key].Type == 'Enum') {
1070 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
1071 if (config[key].ValidValues.indexOf(config[key].Value) == -
1)
1072 config[key].Value = config[key].Default;
1074 else if (config[key].Type == 'Array') {
1075 if (key == 'excludedCalendars') {
1076 config[key].Value = new Array();
1077 for(var i=
0; i < calendarList.length; i++) {
1078 var element = document.forms[
0].elements[
"settings." + key +
"." + calendarList[i]];
1079 if (element != null && element.checked == false)
1080 config[key].Value.push(calendarList[i]);
1093 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
1099 var settingsHtml = '
<form>';
1100 for (var key in config) {
1101 if (config[key].Type == 'String') {
1103 if (key.substring(
0,
9) ==
"cssStyle_")
1104 prefix = getLocalizedText('settings.cssStyle_prefix');
1105 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 />';
1107 else if (config[key].Type == 'Int')
1108 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 />';
1109 else if (config[key].Type == 'Bool')
1110 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 />';
1111 else if (config[key].Type == 'UID')
1112 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 />';
1113 else if (config[key].Type == 'Enum') {
1114 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><select name=
"settings.' + key + '" size=
"1">';
1115 for(var i =
0; i < config[key].ValidValues.length; i++)
1116 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>';
1117 settingsHtml += '
</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1119 else if (config[key].Type == 'Array') {
1120 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br />';
1121 if (key == 'excludedCalendars') {
1122 for(var i=
0; i < calendarList.length; i++) {
1123 var checked = '
checked=
"checked"';
1124 if (config[key].Value.indexOf(calendarList[i]) != -
1)
1126 settingsHtml += '
<input name=
"settings.' + key + '.' + calendarList[i] + '" type=
"checkbox" value=
"' + calendarList[i] + '" ' + checked + '
/> ' + calendarList[i] + '
<br />';
1129 settingsHtml += '
</td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1132 settingsHtml += '
<input name=
"reset" type=
"button" value=
"' + getLocalizedText('settings.restoreDefaults') + '" onclick=
"javascript:restoreDefaultSettings();showSettings();" />';
1133 settingsHtml += '
</form>';
1134 document.getElementById(
"settingsList").innerHTML = settingsHtml;
1137 function changeCssClass(classname, properties)
1139 for(var i =
0; i < document.styleSheets[
0]['cssRules'].length; i++)
1141 if (document.styleSheets[
0]['cssRules'][i].selectorText == classname) {
1142 document.styleSheets[
0].deleteRule(i);
1143 document.styleSheets[
0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[
0]['cssRules'].length);
1149 function updateCssClasses()
1151 for(var key in config) {
1152 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
1156 function getSettingsCalEntryId()
1158 if (settingsCalEntryId == null) {
1159 // check if entry already exists
1160 var listFiltering = {
1161 Type:'CalendarEntry',
1163 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!
1164 EndRange: new Date(
2000,
0,
2),
1165 SearchText: 'ComingNext Settings|',
1171 result = calendarService.IDataSource.GetList(listFiltering);
1172 if (result.ErrorCode)
1173 throw(result.ErrorMessage);
1176 error(
"getSettingsCalEntryId: GetList() failed: " + e + ', line ' + e.line);
1179 var list = result.ReturnValue;
1180 var entry = list.getNext();
1181 if (entry != undefined) {
1182 settingsCalEntryId = entry.LocalId;
1183 log(
"settingsCalEntryId=" + settingsCalEntryId);
1185 else { // create settings item
1186 var item = new Object();
1187 item.Type =
"DayEvent";
1188 item.StartTime = new Date(
2000,
0,
1);
1189 item.Summary =
"ComingNext Settings|";
1191 var criteria = new Object();
1192 criteria.Type =
"CalendarEntry";
1193 criteria.Item = item;
1196 var result = calendarService.IDataSource.Add(criteria);
1197 if (result.ErrorCode)
1198 throw(result.ErrorMessage);
1200 error(
"getSettingsCalEntryId: " + e + ', line ' + e.line);
1203 getSettingsCalEntryId();
1208 function restoreDefaultSettings()
1210 for (var key in config)
1211 config[key].Value = config[key].Default;
1214 function loadSettings()
1216 getSettingsCalEntryId();
1217 var listFiltering = {
1218 Type:'CalendarEntry',
1220 LocalId: settingsCalEntryId
1225 result = calendarService.IDataSource.GetList(listFiltering);
1226 if (result.ErrorCode)
1227 throw(result.ErrorMessage);
1230 error(
"loadSettings: GetList() failed: " + e + ', line ' + e.line);
1233 var entry = result.ReturnValue.getNext();
1234 if (entry != undefined) {
1235 log(
"Loading Settings...");
1236 // only reload settings if they chanced since the last reload
1237 if (settingsCache != entry.Summary)
1239 restoreDefaultSettings();
1240 var stringlist = entry.Summary.split(
"|");
1241 // skip the first two entries, those contain header and version info
1242 for(var i =
2; i < stringlist.length -
1; i++) {
1243 var pair = stringlist[i].split('=');
1245 var value = pair[
1];
1246 if (key == null || value == null || config[key] == null) {
1247 log('Warning: unknown or invalid setting: ' + stringlist[i]);
1250 log('stringlist: ' + key + '=\'' + value + '\'');
1251 if (config[key].Type == 'Int') {
1252 config[key].Value = Number(value);
1253 if (isNaN(config[key].Value))
1254 config[key].Value = config[key].Default;
1256 else if (config[key].Type == 'String')
1257 config[key].Value = value;
1258 else if (config[key].Type == 'Bool')
1259 config[key].Value = (value == 'true')
1260 else if (config[key].Type == 'Enum')
1261 config[key].Value = value;
1262 else if (config[key].Type == 'UID') {
1263 config[key].Value = Number(value);
1264 if (isNaN(config[key].Value))
1265 config[key].Value = config[key].Default;
1267 else if (config[key].Type == 'Array') {
1268 config[key].Value = value.split(
"^");
1269 if (config[key].Value.length ==
1 && config[key].Value[
0] ==
"") {
1270 config[key].Value = [];
1274 settingsCache = entry.Summary;
1278 log(
"Settings already cached and did not change");
1282 error(
"Failed to load settings, calendar entry could not be found");
1286 function saveSettings()
1288 getSettingsCalEntryId();
1289 var item = new Object();
1290 item.Type =
"DayEvent";
1291 item.StartTime = new Date(
2000,
0,
1);
1292 item.LocalId = settingsCalEntryId;
1293 item.Summary =
"ComingNext Settings|" + version +
"|";
1295 for (var key in config) {
1296 if (config[key].Type == 'Int')
1297 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1298 else if (config[key].Type == 'String')
1299 item.Summary += key +
"=" + config[key].Value +
"|";
1300 else if (config[key].Type == 'Bool')
1301 item.Summary += key +
"=" + (config[key].Value ? 'true' : 'false') +
"|";
1302 else if (config[key].Type == 'Enum')
1303 item.Summary += key +
"=" + config[key].Value +
"|";
1304 else if (config[key].Type == 'UID')
1305 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1306 else if (config[key].Type == 'Array')
1307 item.Summary += key +
"=" + config[key].Value.join(
"^") +
"|";
1309 settingsCache = item.Summary;
1311 var criteria = new Object();
1312 criteria.Type =
"CalendarEntry";
1313 criteria.Item = item;
1315 log(
"Saving settings to calendar entry: " + item.Summary);
1317 var result = calendarService.IDataSource.Add(criteria);
1318 if (result.ErrorCode)
1319 throw(result.ErrorMessage);
1321 error(
"saveSettings: " + e + ', line ' + e.line);
1324 lastReloadTime = null; // force calendar data reload on next update
1329 function toggleVisibility(elementId)
1331 if (document.getElementById(elementId).style.display ==
"none")
1332 document.getElementById(elementId).style.display =
"block";
1334 document.getElementById(elementId).style.display =
"none";
1338 function printHintBox(text)
1341 return '
<td width=
"1%" align=
"right" onclick=
"javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '
</td></tr></table>'+
1342 '
<div class=
"settingsInfo" id=
"info' + uniqueId + '">' + text + '
</div>';
1345 function showAbout()
1349 document.getElementById(
"aboutView").style.display =
"block";
1350 document.onclick = null;
1352 window.menu.setLeftSoftkeyLabel(
" ", function(){});
1353 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1359 //document.getElementById(
"aboutView").innerHTML = 'aboutView';
1360 document.getElementById(
"name").innerHTML =
"Coming Next " + version;
1363 function showHelp() {
1364 widget.openURL('http://comingnext.sf.net/help');
1367 function updateFullscreen()
1371 function showFullscreen()
1373 log(
"showFullscreen()");
1375 document.getElementById(
"fullscreenView").style.display =
"block";
1376 document.getElementById('body').className =
"backgroundFullscreen";
1378 document.onclick = launchCalendar;
1383 function getBackgroundImage()
1388 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[
0]) // internal
1389 bgImage = 'background_' + orientation + '.png';
1391 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
1395 function updateHomescreen()
1397 if (config['useBackgroundImage'].Value) {
1398 // check if we have a completely unknown screen resolution
1399 var screenHeight = screen.height;
1400 var screenWidth = screen.width;
1401 if (screenHeight !=
640 && screenHeight !=
480 && screenHeight !=
360)
1402 screenHeight =
360; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1403 if (screenWidth !=
640 && screenWidth !=
480 && screenWidth !=
360)
1404 screenWidth =
640; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1406 // check for screen rotation
1407 if (orientation != 'portrait' && ((screenWidth ==
360 && screenHeight ==
640) || (screenWidth ==
640 && screenHeight ==
480))) {
1408 window.widget.prepareForTransition(
"fade");
1409 orientation = 'portrait';
1410 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1411 document.getElementById('body').style.backgroundColor = 'none';
1412 window.widget.performTransition();
1413 } else if (orientation != 'landscape' && ((screenWidth ==
640 && screenHeight ==
360) || (screenWidth ==
480 && screenHeight ==
640))) {
1414 window.widget.prepareForTransition(
"fade");
1415 orientation = 'landscape';
1416 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1417 document.getElementById('body').style.backgroundColor = 'none';
1418 window.widget.performTransition();
1420 else if (document.getElementById('body').style.backgroundImage ==
"")
1422 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1427 function showHomescreen()
1429 log(
"showHomescreen()");
1431 document.getElementById(
"homescreenView").style.display =
"block";
1432 document.getElementById('body').className =
"background";
1433 document.onclick = null;
1437 function getLocalizedText(p_Txt)
1439 if (localizedText[p_Txt])
1440 return localizedText[p_Txt];
1442 return 'ERROR: missing translation for ' + p_Txt;
1445 function showUpdate()
1449 document.getElementById(
"updateView").style.display =
"block";
1450 document.onclick = null;
1452 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1455 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1461 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
1465 function checkForUpdate()
1467 // asynch XHR to server url
1468 reqV = new XMLHttpRequest();
1469 reqV.onreadystatechange = checkForUpdateCallback;
1470 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
1471 reqV.open(
"GET", versionURL, true);
1472 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1476 function checkForUpdateCallback()
1478 if (reqV.readyState ==
4) {
1479 if (reqV.status ==
200) {
1480 var resultXml = reqV.responseText;
1482 var div = document.getElementById(
"tmp");
1483 div.innerHTML = resultXml;
1484 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
1485 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
1487 if (version != newVersion) {
1488 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1491 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1496 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1501 function hideViews()
1503 document.getElementById(
"homescreenView").style.display =
"none";
1504 document.getElementById(
"fullscreenView").style.display =
"none";
1505 document.getElementById(
"aboutView").style.display =
"none";
1506 document.getElementById(
"settingsView").style.display =
"none";
1507 document.getElementById(
"updateView").style.display =
"none";
1510 function listCalendars()
1520 DefaultCalendar: false
1524 var calendarsResult = calendarService.IDataSource.GetList(criteria);
1525 if (calendarsResult.ErrorCode !=
0)
1526 throw(
"Error fetching list of calendars: " + calendarsResult.ErrorCode + ': ' + calendarsResult.ErrorMessage);
1527 var calendarListIterator = calendarsResult.ReturnValue;
1532 while (( item = calendarListIterator.getNext()) != undefined ) {
1533 calendars[count++] = item;
1535 log(
"Available Calendars: " + calendars.join(
", "));
1538 error('listing calendars:' + e + ', line ' + e.line);
1543 // Copies all objects and their properties to an array. Data is copied so nothing gets lost when the reference is removed
1544 // 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
1545 function listToArray(list, calendarName)
1547 var array = new Array();
1550 while (( item = list.getNext()) != undefined ) {
1551 var itemCopy = new Object();
1552 for(var i=
0; i < entryFields.length; i++) {
1553 itemCopy[entryFields[i]] = item[entryFields[i]];
1555 // for some reason, the CalendarName property is never correctly queried, so we assign it manually here
1556 if (!itemCopy['CalendarName']) {
1557 itemCopy['CalendarName'] = calendarName;
1559 array.push(itemCopy);
1560 txt += array[array.length -
1].Summary +
", ";
1562 log(
"listToArray(): " + txt);
1566 function sortCalendarEntries(a, b)
1569 log(
"sortCalendarEntries(" + a.Summary +
"," + b.Summary +
")");
1571 if (a.InstanceStartTime != null) {
1572 atime = a.InstanceStartTime;
1574 else if (a.StartTime != null) {
1575 atime = a.StartTime;
1577 else if (a.InstanceEndTime != null) {
1578 atime = a.InstanceEndTime;
1580 else if (a.EndTime != null) {
1584 if (b.InstanceStartTime != null) {
1585 btime = b.InstanceStartTime;
1587 else if (b.StartTime != null) {
1588 btime = b.StartTime;
1590 else if (b.InstanceEndTime != null) {
1591 btime = b.InstanceEndTime;
1593 else if (b.EndTime != null) {
1597 if (atime && btime) {
1599 atime = parseDate(atime);
1600 btime = parseDate(btime);
1602 // sort by date & time
1603 if (atime < btime) {
1606 else if (atime
> btime) {
1610 else if (a.Type != b.Type) {
1611 if (a.Type < b.Type) {
1614 else if (a.Type
> b.Type) {
1618 // sort by description
1619 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1620 if (a.Summary < b.Summary) {
1623 else if (a.Summary
> b.Summary) {
1628 // NOTE: events my have no date information at all. In that case, we list events without date first
1629 else if (atime && !btime) {
1632 else if (!atime && btime) {
1635 else if (!atime && !btime) {
1637 if (a.Type != b.Type) {
1638 if (a.Type < b.Type) {
1641 else if (a.Type
> b.Type) {
1645 // sort by description
1646 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1647 if (a.Summary < b.Summary) {
1650 else if (a.Summary
> b.Summary) {
1659 function updateCalendarColors()
1662 calendarColors = [];
1663 if (calendarList.length
> maxColors) {
1664 log(
"updateCalendarColors(): Warning: more calendars than available indicator colors");
1666 for(var i=
0; i < calendarList.length; i++) {
1667 calendarColors[calendarList[i]] = (i % maxColors) +
1;
1671 function log(message)
1673 if (config['enableLogging'].Value) {
1674 console.info(message);
1680 <style type=
"text/css">
1682 table { margin:
0px; padding:
0px; border-spacing:
0px; }
1683 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
1684 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1685 .settingsInfo { display:none; font-style:italic; }
1686 .title { font-weight:bold; font-size:
14pt; }
1687 .textInput { width:
90%; }
1688 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1689 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
1690 #calendarList { position:absolute; left:
5px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
1691 #name { text-align:center; }
1692 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1693 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1698 <body onload=
"javascript:setTimeout('init()', 10)" onresize=
"javascript:updateScreen()" id=
"body" class=
"background">
1699 <div id=
"homescreenView">
1700 <div id=
"calendarList">loading...
</div>
1702 <div id=
"fullscreenView" style=
"display:none;">
1703 <img src=
"Icon.png" id=
"smallappicon">
1704 <h1 class=
"title">Coming Next
</h1>
1706 <div id=
"fullscreenCalendarList">loading...
</div>
1708 <div id=
"settingsView" style=
"display:none">
1709 <img src=
"Icon.png" id=
"smallappicon">
1710 <h1 id=
"settingsTitle" class=
"title">Settings
</h1>
1712 <div id=
"settingsList"></div>
1714 <div id=
"aboutView" style=
"display:none">
1715 <img src=
"Icon.png" id=
"appicon">
1716 <h1 id=
"name">Coming Next
</h1>
1718 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1719 <p>Contributions:
</p>
1720 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1721 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1722 <p class=
"credits">Christophe Milsent (translation support & french translation)
</p>
1723 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation)
</p>
1724 <p class=
"credits">Tokeda (russian translation)
</p>
1725 <p class=
"credits">Marcella Ferrari (italian translation)
</p>
1726 <p class=
"credits">Venos (italian translation)
</p>
1727 <p>This software is open source and licensed under the GPLv3.
</p>
1728 <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>
1731 <div id=
"updateView" style=
"display:none">
1732 <img src=
"Icon.png" id=
"smallappicon">
1733 <h1 class=
"title">Check for update
</h1>
1735 <div id=
"currentVersion">Coming Next ??
</div>
1736 <div id=
"updateDiv"></div>
1737 <div id=
"tmp" style=
"display:none;"></div>