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 later...');
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 is actually a DayEvent. Bug introduced by
"Anna" updates to various Symbian^
3 devices.
787 // Note that this workaround is not
100% save! It might missinterpret some meetings as dayevents of starting and ending on
00:
00
788 if (entry.Type == 'Meeting' && date.getHours() ==
0 && date.getMinutes() ==
0 &&
789 endDate != null && endDate.getHours() ==
0 && endDate.getMinutes() ==
0) {
790 log('fixing event type: changed from
"Meeting" to
"DayEvent".');
791 entry.Type = 'DayEvent';
794 // check if meeting event has already passed
795 if (entry.Type == 'Meeting') {
796 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
797 if (now.getTime()
> compareTime) {
798 log('skipping Meeting (already passed) ' + entry.id);
800 eventIds[entry.id] =
0;
805 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
806 if (entry.Type == 'Anniversary') {
807 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
808 if (date.getTime() < tmp.getTime()) {
809 log('skipping Anniversary (already passed) ' + entry.id);
811 eventIds[entry.id] =
0;
816 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
817 if (entry.Type == 'DayEvent' && endDate != null) {
818 endDate.setMinutes(endDate.getMinutes() -
1);
819 log('fixing DayEvent endDate: ' + endDate);
820 if (now.getTime()
> endDate.getTime()) {
821 log('event already passed ' + entry.id);
823 eventIds[entry.id] =
0;
828 // check if the event is currently taking place
829 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
830 // check if we are between start and endtime
831 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
832 date = now; // change appointment date/time to now
833 log('event is currently taking place: ' + date);
837 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
838 if (mode ==
0 && panelNum
> 0 && counter < panelNum * config['eventsPerWidget'].Value +
1) {
839 log('skipping (already in first widget) ' + entry.id);
843 // mark overdue todos
845 if (entry.Type == 'ToDo' && date != null) {
846 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
0,
0,
0);
847 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
848 if (tmp1.getTime() < tmp2.getTime()) {
853 // generate html output
854 entriesHtml += '
<tr>';
855 if (config['showCalendarIndicator'].Value && calendarList.length - config['excludedCalendars'].Value.length
> 1) {
856 entriesHtml += '
<td><span class=
"calendar' + calendarColors[entry.CalendarName] + '"> </span></td>';
858 entriesHtml += '
<td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
860 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
861 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
863 var weekDay = getWeekdayLocalized(date).substr(
0,config['weekDayLength'].Value);
864 log('date.toLocaleDateString(): ' + date.toLocaleDateString());
865 log('weekDay: ' + weekDay);
866 var time = formatTime(date);
867 var dateStr = formatDate(date, entryDate);
868 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
869 dateStr = '
<span class=
"overdue">' + config['overdueText'].Value + '
</span>';
870 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
871 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
872 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
873 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
875 entriesHtml += '
<td class=
"weekDay" width=
"1px">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
876 } else if (entry.Type == 'Meeting') {
877 if (config['showCombinedDateTime'].Value) {
879 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
880 else if (isTomorrow(date))
881 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
883 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
885 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
886 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
888 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
892 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
895 entriesHtml += '
</table>';
896 if (config['showNothingText'].Value && entriesHtml == '
<table></table>') {
897 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
898 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '
</div>';
900 if (cacheEntriesHtml != entriesHtml) {
902 document.getElementById('calendarList').innerHTML = entriesHtml;
904 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
905 cacheEntriesHtml = entriesHtml;
908 lastUpdateTime = new Date();
910 error('displaying list:' + e + ', line ' + e.line);
915 // called by handleOnShow() and onResize events
916 function updateScreen()
918 log('updateScreen()');
920 // check if opening fullscreen
921 if( window.innerHeight
> 91 && mode ==
0) {
923 cacheEntriesHtml = '';
924 document.getElementById('body').style.backgroundImage =
"";
927 else if (window.innerHeight <=
91 && mode !=
0) {
929 cacheEntriesHtml = '';
934 updateHomescreen(); // check for screen rotation
939 function handleOnShow()
943 var time = new Date();
944 if (time.getTime() - lastUpdateTime.getTime()
> config['updateDataInterval'].Value *
60 *
1000) {
945 log('updateScreen(): force updateData() because last update was too long ago (' + (time.getTime() - lastUpdateTime.getTime()) /
1000 + 's)');
948 setUpdateTimer(); // reinitialize update timer
952 function launchCalendar()
955 widget.openApplication(config['calendarApp'].Value,
"");
956 if (config['hideWidgetOnCalendarOpen'].Value)
959 error('starting Calendar App');
966 log('New widget instance starting up...');
969 // call calendar service
970 if (device !=
"undefined")
971 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
973 throw('device object does not exist');
975 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>');
979 calendarList = listCalendars();
981 updateCalendarColors();
984 requestNotification();
985 document.getElementById(
"settingsTitle").innerHTML = getLocalizedText('menu.settings');
987 if (window.innerHeight
> 91) {
988 mode =
0; // we're starting fullscreen, we set mode to homescreen in order to let updateScreen() do all the work for us
993 log(
"init(): updateScreen()");
995 if (config['useBackgroundImage'].Value)
996 // check for screen rotation every
1 secs
997 screenRotationTimer = window.setInterval('checkOrientation()',
1000 *
1);
999 // call updateScreen() when widget changes from background to forground
1000 window.widget.onshow = handleOnShow;
1002 log(
"init(): finished...");
1004 statupSuccessful = true;
1007 function checkOrientation()
1011 updateHomescreen(); // check for screen rotation
1014 function setUpdateTimer()
1016 updateTimer = window.setInterval('updateTimerCallback()',
1000 *
60 * config['updateDataInterval'].Value);
1019 function clearUpdateTimer()
1021 window.clearInterval(updateTimer);
1024 function updateTimerCallback()
1026 log(
"updateTimerCallback()");
1030 function createMenu()
1032 window.menu.setLeftSoftkeyLabel(
"",null);
1033 window.menu.setRightSoftkeyLabel(
"",null);
1035 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
1036 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
1037 var menuHelp = new MenuItem(getLocalizedText('menu.help'), id++);
1038 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
1039 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
1040 menuSettings.onSelect = showSettings;
1041 menuAbout.onSelect = showAbout;
1042 menuCallApp.onSelect = launchCalendar;
1043 menuUpdate.onSelect = showUpdate;
1044 menuHelp.onSelect = showHelp;
1045 window.menu.clear();
1046 window.menu.append(menuCallApp);
1047 window.menu.append(menuSettings);
1048 window.menu.append(menuHelp);
1049 window.menu.append(menuUpdate);
1050 window.menu.append(menuAbout);
1053 function showSettings()
1057 document.getElementById(
"settingsView").style.display =
"block";
1058 document.onclick = null;
1060 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
1062 for (var key in config) {
1063 if (config[key].Type == 'String')
1064 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
1065 else if (config[key].Type == 'Int') {
1066 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
1067 if (config[key].Value <
0 || isNaN(config[key].Value))
1068 config[key].Value = config[key].Default;
1070 else if (config[key].Type == 'Bool')
1071 config[key].Value = document.forms[
0].elements[
"settings." + key].checked;
1072 else if (config[key].Type == 'UID') {
1073 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
1074 if (isNaN(config[key].Value))
1075 config[key].Value = config[key].Default;
1077 else if (config[key].Type == 'Enum') {
1078 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
1079 if (config[key].ValidValues.indexOf(config[key].Value) == -
1)
1080 config[key].Value = config[key].Default;
1082 else if (config[key].Type == 'Array') {
1083 if (key == 'excludedCalendars') {
1084 config[key].Value = new Array();
1085 for(var i=
0; i < calendarList.length; i++) {
1086 var element = document.forms[
0].elements[
"settings." + key +
"." + calendarList[i]];
1087 if (element != null && element.checked == false)
1088 config[key].Value.push(calendarList[i]);
1101 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
1107 var settingsHtml = '
<form>';
1108 for (var key in config) {
1109 if (config[key].Type == 'String') {
1111 if (key.substring(
0,
9) ==
"cssStyle_")
1112 prefix = getLocalizedText('settings.cssStyle_prefix');
1113 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 />';
1115 else if (config[key].Type == 'Int')
1116 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 />';
1117 else if (config[key].Type == 'Bool')
1118 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 />';
1119 else if (config[key].Type == 'UID')
1120 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 />';
1121 else if (config[key].Type == 'Enum') {
1122 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><select name=
"settings.' + key + '" size=
"1">';
1123 for(var i =
0; i < config[key].ValidValues.length; i++)
1124 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>';
1125 settingsHtml += '
</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1127 else if (config[key].Type == 'Array') {
1128 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br />';
1129 if (key == 'excludedCalendars') {
1130 for(var i=
0; i < calendarList.length; i++) {
1131 var checked = '
checked=
"checked"';
1132 if (config[key].Value.indexOf(calendarList[i]) != -
1)
1134 settingsHtml += '
<input name=
"settings.' + key + '.' + calendarList[i] + '" type=
"checkbox" value=
"' + calendarList[i] + '" ' + checked + '
/> ' + calendarList[i] + '
<br />';
1137 settingsHtml += '
</td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1140 settingsHtml += '
<input name=
"reset" type=
"button" value=
"' + getLocalizedText('settings.restoreDefaults') + '" onclick=
"javascript:restoreDefaultSettings();showSettings();" />';
1141 settingsHtml += '
</form>';
1142 document.getElementById(
"settingsList").innerHTML = settingsHtml;
1145 function changeCssClass(classname, properties)
1147 for(var i =
0; i < document.styleSheets[
0]['cssRules'].length; i++)
1149 if (document.styleSheets[
0]['cssRules'][i].selectorText == classname) {
1150 document.styleSheets[
0].deleteRule(i);
1151 document.styleSheets[
0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[
0]['cssRules'].length);
1157 function updateCssClasses()
1159 for(var key in config) {
1160 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
1164 function getSettingsCalEntryId()
1166 if (settingsCalEntryId == null) {
1167 // check if entry already exists
1168 var listFiltering = {
1169 Type:'CalendarEntry',
1171 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!
1172 EndRange: new Date(
2000,
0,
2),
1173 SearchText: 'ComingNext Settings|',
1179 result = calendarService.IDataSource.GetList(listFiltering);
1180 if (result.ErrorCode)
1181 throw(result.ErrorMessage);
1184 error(
"getSettingsCalEntryId: GetList() failed: " + e + ', line ' + e.line);
1187 var list = result.ReturnValue;
1188 var entry = list.getNext();
1189 if (entry != undefined) {
1190 settingsCalEntryId = entry.LocalId;
1191 log(
"settingsCalEntryId=" + settingsCalEntryId);
1193 else { // create settings item
1194 var item = new Object();
1195 item.Type =
"DayEvent";
1196 item.StartTime = new Date(
2000,
0,
1);
1197 item.Summary =
"ComingNext Settings|";
1199 var criteria = new Object();
1200 criteria.Type =
"CalendarEntry";
1201 criteria.Item = item;
1204 var result = calendarService.IDataSource.Add(criteria);
1205 if (result.ErrorCode)
1206 throw(result.ErrorMessage);
1208 error(
"getSettingsCalEntryId: " + e + ', line ' + e.line);
1211 getSettingsCalEntryId();
1216 function restoreDefaultSettings()
1218 for (var key in config)
1219 config[key].Value = config[key].Default;
1222 function loadSettings()
1224 getSettingsCalEntryId();
1225 var listFiltering = {
1226 Type:'CalendarEntry',
1228 LocalId: settingsCalEntryId
1233 result = calendarService.IDataSource.GetList(listFiltering);
1234 if (result.ErrorCode)
1235 throw(result.ErrorMessage);
1238 error(
"loadSettings: GetList() failed: " + e + ', line ' + e.line);
1241 var entry = result.ReturnValue.getNext();
1242 if (entry != undefined) {
1243 log(
"Loading Settings...");
1244 // only reload settings if they chanced since the last reload
1245 if (settingsCache != entry.Summary)
1247 restoreDefaultSettings();
1248 var stringlist = entry.Summary.split(
"|");
1249 // skip the first two entries, those contain header and version info
1250 for(var i =
2; i < stringlist.length -
1; i++) {
1251 var pair = stringlist[i].split('=');
1253 var value = pair[
1];
1254 if (key == null || value == null || config[key] == null) {
1255 log('Warning: unknown or invalid setting: ' + stringlist[i]);
1258 log('stringlist: ' + key + '=\'' + value + '\'');
1259 if (config[key].Type == 'Int') {
1260 config[key].Value = Number(value);
1261 if (isNaN(config[key].Value))
1262 config[key].Value = config[key].Default;
1264 else if (config[key].Type == 'String')
1265 config[key].Value = value;
1266 else if (config[key].Type == 'Bool')
1267 config[key].Value = (value == 'true')
1268 else if (config[key].Type == 'Enum')
1269 config[key].Value = value;
1270 else if (config[key].Type == 'UID') {
1271 config[key].Value = Number(value);
1272 if (isNaN(config[key].Value))
1273 config[key].Value = config[key].Default;
1275 else if (config[key].Type == 'Array') {
1276 config[key].Value = value.split(
"^");
1277 if (config[key].Value.length ==
1 && config[key].Value[
0] ==
"") {
1278 config[key].Value = [];
1282 settingsCache = entry.Summary;
1286 log(
"Settings already cached and did not change");
1290 error(
"Failed to load settings, calendar entry could not be found");
1294 function saveSettings()
1296 getSettingsCalEntryId();
1297 var item = new Object();
1298 item.Type =
"DayEvent";
1299 item.StartTime = new Date(
2000,
0,
1);
1300 item.LocalId = settingsCalEntryId;
1301 item.Summary =
"ComingNext Settings|" + version +
"|";
1303 for (var key in config) {
1304 if (config[key].Type == 'Int')
1305 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1306 else if (config[key].Type == 'String')
1307 item.Summary += key +
"=" + config[key].Value +
"|";
1308 else if (config[key].Type == 'Bool')
1309 item.Summary += key +
"=" + (config[key].Value ? 'true' : 'false') +
"|";
1310 else if (config[key].Type == 'Enum')
1311 item.Summary += key +
"=" + config[key].Value +
"|";
1312 else if (config[key].Type == 'UID')
1313 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1314 else if (config[key].Type == 'Array')
1315 item.Summary += key +
"=" + config[key].Value.join(
"^") +
"|";
1317 settingsCache = item.Summary;
1319 var criteria = new Object();
1320 criteria.Type =
"CalendarEntry";
1321 criteria.Item = item;
1323 log(
"Saving settings to calendar entry: " + item.Summary);
1325 var result = calendarService.IDataSource.Add(criteria);
1326 if (result.ErrorCode)
1327 throw(result.ErrorMessage);
1329 error(
"saveSettings: " + e + ', line ' + e.line);
1332 lastReloadTime = null; // force calendar data reload on next update
1337 function toggleVisibility(elementId)
1339 if (document.getElementById(elementId).style.display ==
"none")
1340 document.getElementById(elementId).style.display =
"block";
1342 document.getElementById(elementId).style.display =
"none";
1346 function printHintBox(text)
1349 return '
<td width=
"1%" align=
"right" onclick=
"javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '
</td></tr></table>'+
1350 '
<div class=
"settingsInfo" id=
"info' + uniqueId + '">' + text + '
</div>';
1353 function showAbout()
1357 document.getElementById(
"aboutView").style.display =
"block";
1358 document.onclick = null;
1360 window.menu.setLeftSoftkeyLabel(
" ", function(){});
1361 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1367 //document.getElementById(
"aboutView").innerHTML = 'aboutView';
1368 document.getElementById(
"name").innerHTML =
"Coming Next " + version;
1371 function showHelp() {
1372 widget.openURL('http://comingnext.sf.net/help');
1375 function updateFullscreen()
1379 function showFullscreen()
1381 log(
"showFullscreen()");
1383 document.getElementById(
"fullscreenView").style.display =
"block";
1384 document.getElementById('body').className =
"backgroundFullscreen";
1386 document.onclick = launchCalendar;
1391 function getBackgroundImage()
1396 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[
0]) // internal
1397 bgImage = 'background_' + orientation + '.png';
1399 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
1403 function updateHomescreen()
1405 if (config['useBackgroundImage'].Value) {
1406 // check if we have a completely unknown screen resolution
1407 var screenHeight = screen.height;
1408 var screenWidth = screen.width;
1409 if (screenHeight !=
640 && screenHeight !=
480 && screenHeight !=
360)
1410 screenHeight =
360; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1411 if (screenWidth !=
640 && screenWidth !=
480 && screenWidth !=
360)
1412 screenWidth =
640; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1414 // check for screen rotation
1415 if (orientation != 'portrait' && ((screenWidth ==
360 && screenHeight ==
640) || (screenWidth ==
640 && screenHeight ==
480))) {
1416 window.widget.prepareForTransition(
"fade");
1417 orientation = 'portrait';
1418 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1419 document.getElementById('body').style.backgroundColor = 'none';
1420 window.widget.performTransition();
1421 } else if (orientation != 'landscape' && ((screenWidth ==
640 && screenHeight ==
360) || (screenWidth ==
480 && screenHeight ==
640))) {
1422 window.widget.prepareForTransition(
"fade");
1423 orientation = 'landscape';
1424 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1425 document.getElementById('body').style.backgroundColor = 'none';
1426 window.widget.performTransition();
1428 else if (document.getElementById('body').style.backgroundImage ==
"")
1430 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1435 function showHomescreen()
1437 log(
"showHomescreen()");
1439 document.getElementById(
"homescreenView").style.display =
"block";
1440 document.getElementById('body').className =
"background";
1441 document.onclick = null;
1445 function getLocalizedText(p_Txt)
1447 if (localizedText[p_Txt])
1448 return localizedText[p_Txt];
1450 return 'ERROR: missing translation for ' + p_Txt;
1453 function showUpdate()
1457 document.getElementById(
"updateView").style.display =
"block";
1458 document.onclick = null;
1460 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1463 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1469 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
1473 function checkForUpdate()
1475 // asynch XHR to server url
1476 reqV = new XMLHttpRequest();
1477 reqV.onreadystatechange = checkForUpdateCallback;
1478 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
1479 reqV.open(
"GET", versionURL, true);
1480 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1484 function checkForUpdateCallback()
1486 if (reqV.readyState ==
4) {
1487 if (reqV.status ==
200) {
1488 var resultXml = reqV.responseText;
1490 var div = document.getElementById(
"tmp");
1491 div.innerHTML = resultXml;
1492 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
1493 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
1495 if (version != newVersion) {
1496 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1499 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1504 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1509 function hideViews()
1511 document.getElementById(
"homescreenView").style.display =
"none";
1512 document.getElementById(
"fullscreenView").style.display =
"none";
1513 document.getElementById(
"aboutView").style.display =
"none";
1514 document.getElementById(
"settingsView").style.display =
"none";
1515 document.getElementById(
"updateView").style.display =
"none";
1518 function listCalendars()
1528 DefaultCalendar: false
1532 var calendarsResult = calendarService.IDataSource.GetList(criteria);
1533 if (calendarsResult.ErrorCode !=
0)
1534 throw(
"Error fetching list of calendars: " + calendarsResult.ErrorCode + ': ' + calendarsResult.ErrorMessage);
1535 var calendarListIterator = calendarsResult.ReturnValue;
1540 while (( item = calendarListIterator.getNext()) != undefined ) {
1541 calendars[count++] = item;
1543 log(
"Available Calendars: " + calendars.join(
", "));
1546 error('listing calendars:' + e + ', line ' + e.line);
1551 // Copies all objects and their properties to an array. Data is copied so nothing gets lost when the reference is removed
1552 // 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
1553 function listToArray(list, calendarName)
1555 var array = new Array();
1558 while (( item = list.getNext()) != undefined ) {
1559 var itemCopy = new Object();
1560 for(var i=
0; i < entryFields.length; i++) {
1561 itemCopy[entryFields[i]] = item[entryFields[i]];
1563 // for some reason, the CalendarName property is never correctly queried, so we assign it manually here
1564 if (!itemCopy['CalendarName']) {
1565 itemCopy['CalendarName'] = calendarName;
1567 array.push(itemCopy);
1568 txt += array[array.length -
1].Summary +
", ";
1570 log(
"listToArray(): " + txt);
1574 function sortCalendarEntries(a, b)
1577 log(
"sortCalendarEntries(" + a.Summary +
"," + b.Summary +
")");
1579 if (a.InstanceStartTime != null) {
1580 atime = a.InstanceStartTime;
1582 else if (a.StartTime != null) {
1583 atime = a.StartTime;
1585 else if (a.InstanceEndTime != null) {
1586 atime = a.InstanceEndTime;
1588 else if (a.EndTime != null) {
1592 if (b.InstanceStartTime != null) {
1593 btime = b.InstanceStartTime;
1595 else if (b.StartTime != null) {
1596 btime = b.StartTime;
1598 else if (b.InstanceEndTime != null) {
1599 btime = b.InstanceEndTime;
1601 else if (b.EndTime != null) {
1605 if (atime && btime) {
1607 atime = parseDate(atime);
1608 btime = parseDate(btime);
1610 // sort by date & time
1611 if (atime < btime) {
1614 else if (atime
> btime) {
1618 else if (a.Type != b.Type) {
1619 if (a.Type < b.Type) {
1622 else if (a.Type
> b.Type) {
1626 // sort by description
1627 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1628 if (a.Summary < b.Summary) {
1631 else if (a.Summary
> b.Summary) {
1636 // NOTE: events my have no date information at all. In that case, we list events without date first
1637 else if (atime && !btime) {
1640 else if (!atime && btime) {
1643 else if (!atime && !btime) {
1645 if (a.Type != b.Type) {
1646 if (a.Type < b.Type) {
1649 else if (a.Type
> b.Type) {
1653 // sort by description
1654 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1655 if (a.Summary < b.Summary) {
1658 else if (a.Summary
> b.Summary) {
1667 function updateCalendarColors()
1670 calendarColors = [];
1671 if (calendarList.length
> maxColors) {
1672 log(
"updateCalendarColors(): Warning: more calendars than available indicator colors");
1674 for(var i=
0; i < calendarList.length; i++) {
1675 calendarColors[calendarList[i]] = (i % maxColors) +
1;
1679 function log(message)
1681 if (config['enableLogging'].Value) {
1682 console.info(message);
1688 <style type=
"text/css">
1690 table { margin:
0px; padding:
0px; border-spacing:
0px; }
1691 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
1692 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1693 .settingsInfo { display:none; font-style:italic; }
1694 .title { font-weight:bold; font-size:
14pt; }
1695 .textInput { width:
90%; }
1696 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1697 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
1698 #calendarList { position:absolute; left:
5px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
1699 #name { text-align:center; }
1700 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1701 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1706 <body onload=
"javascript:setTimeout('init()', 10)" onresize=
"javascript:updateScreen()" id=
"body" class=
"background">
1707 <div id=
"homescreenView">
1708 <div id=
"calendarList">loading...
</div>
1710 <div id=
"fullscreenView" style=
"display:none;">
1711 <img src=
"Icon.png" id=
"smallappicon">
1712 <h1 class=
"title">Coming Next
</h1>
1714 <div id=
"fullscreenCalendarList">loading...
</div>
1716 <div id=
"settingsView" style=
"display:none">
1717 <img src=
"Icon.png" id=
"smallappicon">
1718 <h1 id=
"settingsTitle" class=
"title">Settings
</h1>
1720 <div id=
"settingsList"></div>
1722 <div id=
"aboutView" style=
"display:none">
1723 <img src=
"Icon.png" id=
"appicon">
1724 <h1 id=
"name">Coming Next
</h1>
1726 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1727 <p>Contributions:
</p>
1728 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1729 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1730 <p class=
"credits">Christophe Milsent (translation support & french translation)
</p>
1731 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation)
</p>
1732 <p class=
"credits">Tokeda (russian translation)
</p>
1733 <p class=
"credits">Marcella Ferrari (italian translation)
</p>
1734 <p class=
"credits">Venos (italian translation)
</p>
1735 <p>This software is open source and licensed under the GPLv3.
</p>
1736 <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>
1739 <div id=
"updateView" style=
"display:none">
1740 <img src=
"Icon.png" id=
"smallappicon">
1741 <h1 class=
"title">Check for update
</h1>
1743 <div id=
"currentVersion">Coming Next ??
</div>
1744 <div id=
"updateDiv"></div>
1745 <div id=
"tmp" style=
"display:none;"></div>