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.
109 var use12hoursTimeFormat = false; // defines how time should be formated:
19:
00 or
07:
00 pm
110 var timeFormatSeparator =
":"; // format time
19:
00 or
19.00 depending on system setting
112 // vars for daylight saving time
113 var summertime = false; // true, if current date is in summer, false if in winter
114 var daylightSavingDates = new Object(); // caches calculated DST winter and summer time shift dates
116 // this is a list of data fields a calendar event can have
130 function isLeapYear( year ) {
131 if (( year %
4 ==
0 && year %
100 !=
0 ) || year %
400 ==
0 )
137 function calcLeapYear(year, days)
139 if (isLeapYear(year))
145 function subToSunday(myDate, year, days, prevMonthDays)
147 for (i = myDate.getDay(); i
> 0 ;i--)
149 days -= prevMonthDays;
150 days = isLeapYear(year) ? --days : days;
154 function isSummertime(curDate)
159 // if we already calculated DST summer and winter time dates for this year, use cached values
160 var dst = daylightSavingDates[curDate.getFullYear()];
162 var thisYearS = new Date(curDate.getFullYear(),
3,
0,
0,
0,
0 );
163 var thisYearW = new Date(curDate.getFullYear(),
10,
0,
0,
0,
0 );
164 var nextYearS = new Date(curDate.getFullYear() +
1,
3,
0,
0,
0,
0 );
165 var nextYearW = new Date(curDate.getFullYear() +
1,
10,
0,
0,
0,
0 );
167 thisYearSDays = nextYearSDays =
90;
168 thisYearWDays = nextYearWDays =
304;
170 thisYearSDays = calcLeapYear(curDate.getFullYear(), thisYearSDays);
171 thisYearWDays = calcLeapYear(curDate.getFullYear(), thisYearWDays);
172 nextYearSDays = calcLeapYear(curDate.getFullYear() +
1, nextYearSDays);
173 nextYearWDays = calcLeapYear(curDate.getFullYear() +
1, nextYearWDays);
175 thisYearSDays = subToSunday(thisYearS, curDate.getFullYear(), thisYearSDays,
59);
176 thisYearWDays = subToSunday(thisYearW, curDate.getFullYear(), thisYearWDays,
273);
177 nextYearSDays = subToSunday(nextYearS, curDate.getFullYear() +
1, nextYearSDays,
59);
178 nextYearWDays = subToSunday(nextYearW, curDate.getFullYear() +
1, nextYearWDays,
273);
181 Summer: new Date (curDate.getFullYear(),
03-
1, thisYearSDays,
2,
0,
0),
182 Winter: new Date (curDate.getFullYear(),
10-
1, thisYearWDays,
2,
0,
0),
184 daylightSavingDates[curDate.getFullYear()] = dst;
187 if (dst.Summer < curDate)
189 if (dst.Winter < curDate)
191 if (summer && !winter)
197 function error(message)
199 console.info('Error: ' + message);
200 document.getElementById(
"calendarList").innerHTML = 'Error: ' + message;
201 document.getElementById(
"fullscreenCalendarList").innerHTML = 'Error: ' + message;
203 document.onclick = null;
206 function areDatesEqual(date1, date2)
208 return (date1.getFullYear() == date2.getFullYear() &&
209 date1.getMonth() == date2.getMonth() &&
210 date1.getDate() == date2.getDate());
213 function isTomorrow(date)
215 // tommorow = now +
1 day
216 // ToDo: some days can be shorter as
24 hours(daylight saving change day)
217 return areDatesEqual(date, new Date (now.getTime() +
24*
60*
60*
1000));
220 function isToday(date)
222 return areDatesEqual(date, now);
225 function collectLocales()
227 var tmpyear =
2000 + panelNum;
230 if (months_translated.length
> 0)
232 for (month =
0; month <
12; month++) {
233 var startDate = new Date(tmpyear, month,
15);
235 var item = new Object();
236 item.Type =
"DayEvent";
237 item.StartTime = startDate;
238 item.Summary =
"__temp" + month;
240 var criteria = new Object();
241 criteria.Type =
"CalendarEntry";
242 criteria.Item = item;
245 var result = calendarService.IDataSource.Add(criteria);
246 if (result.ErrorCode)
247 throw(result.ErrorMessage);
249 error(
"collectLocales: " + e + ', line ' + e.line);
252 for (weekday =
0; weekday <
7; weekday++) {
253 var startDate = new Date(
2000,
0,
2 + weekday); // date that we know for sure is a sunday
255 var item = new Object();
256 item.Type =
"DayEvent";
257 item.StartTime = startDate;
258 item.Summary =
"__weekday_temp" + weekday;
260 var criteria = new Object();
261 criteria.Type =
"CalendarEntry";
262 criteria.Item = item;
265 var result = calendarService.IDataSource.Add(criteria);
266 if (result.ErrorCode)
267 throw(result.ErrorMessage);
269 error(
"collectLocales: " + e + ', line ' + e.line);
273 var startTime = new Date(tmpyear,
0,
1);
274 var endTime = new Date(tmpyear,
11,
31);
275 var listFiltering = {
276 Type:'CalendarEntry',
278 StartRange: startTime,
280 SearchText: '__temp',
284 var result = calendarService.IDataSource.GetList(listFiltering);
285 if (result.ErrorCode)
286 throw(result.ErrorMessage);
287 var list = result.ReturnValue;
289 error(
"collectLocales: " + e + ', line ' + e.line);
292 var ids = new Array();
298 while (list && (entry = list.getNext()) != undefined) {
299 dateArr = (entry.StartTime + '').replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
300 var day = dateArr[
1];
301 var month = dateArr[
2];
302 var year = dateArr[
3];
304 // make sure month is set properly
305 if (isNaN(parseInt(day))) {
309 } else if (isNaN(parseInt(year))) {
315 log(entry.StartTime + ' -
> ' + month + ' ' + counter);
316 ids[counter] = entry.id;
317 months_translated[month] = counter +
1;
321 error(
"collectLocales: " + e + ', line ' + e.line);
325 var startTime = new Date(
2000,
0,
2);
326 var endTime = new Date(
2000,
0,
9);
327 var listFiltering = {
328 Type:'CalendarEntry',
330 StartRange: startTime,
332 SearchText: '__weekday_temp',
336 var result = calendarService.IDataSource.GetList(listFiltering);
337 if (result.ErrorCode)
338 throw(result.ErrorMessage);
339 var weekdaylist = result.ReturnValue;
341 error(
"collectLocales: " + e + ', line ' + e.line);
349 while (weekdaylist && (entry = weekdaylist.getNext()) != undefined) {
350 detectTimeFormat(entry.StartTime + '');
351 curWeekday = (entry.StartTime + '').split(',')[
0];
352 log(entry.StartTime + ' -
> ' + curWeekday + ' ' + counter2);
353 ids[counter + counter2] = entry.id;
354 weekdays_translated[counter2] = curWeekday;
358 error(
"collectLocales: " + e + ', line ' + e.line);
363 var criteria = new Object();
364 criteria.Type =
"CalendarEntry";
369 var result = calendarService.IDataSource.Delete(criteria);
370 if (result.ErrorCode)
371 throw(result.ErrorMessage);
373 error('deleting temp calendar entries:' + e + ', line ' + e.line);
378 // detects the system's current time format by parsing a native calendar timestamp (this is the only reliable formating across all devices and firmwares)
379 function detectTimeFormat(localeTimeString)
381 localeTimeString = localeTimeString.toLowerCase();
382 use12hoursTimeFormat = localeTimeString.indexOf(
"am") != -
1 || localeTimeString.indexOf(
"pm") != -
1 ? true : false;
383 timeFormatSeparator = localeTimeString.indexOf(
":") != -
1 ?
":" :
".";
386 function requestNotification()
388 var criteria = new Object();
389 criteria.Type =
"CalendarEntry";
390 criteria.Filter = new Object();
391 for(var i=
0; i < calendarList.length; i++) {
392 criteria.Filter.CalendarName = calendarList[i];
394 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria, callback);
395 if (notificationRequest.ErrorCode)
396 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
397 notificationRequests.push(notificationRequest);
399 error(
"requestNotification: " + e + ', line ' + e.line);
403 var criteria2 = new Object();
404 criteria2.Type =
"CalendarEntry";
405 criteria2.Filter = new Object();
406 criteria2.Filter.LocalIdList = new Array();
407 criteria2.Filter.LocalIdList[
0] = settingsCalEntryId;
409 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria2, settingsCallback);
410 if (notificationRequest.ErrorCode)
411 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
412 notificationRequests.push(notificationRequest);
414 error(
"requestNotification: " + e + ', line ' + e.line);
418 function cancelNotification()
420 for(var i=
0; i < notificationRequests.length; i++) {
422 var result = calendarService.IDataSource.Cancel(notificationRequests[i]);
423 if (result.ErrorCode)
424 error('cancelNotification failed with error code ' + result.ErrorCode);
426 error(
"cancelNotification: " + e + ', line ' + e.line);
431 function callback(transId, eventCode, result)
433 log(
"callback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
434 lastReloadTime = null; // force calendar data reload on next update
438 function settingsCallback(transId, eventCode, result)
440 log(
"settingsCallback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
444 function parseDate(dateString)
447 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:
448 Wednesday,
26 August,
2009 24:
00:
00
449 Wednesday,
26 August,
2009 12:
00:
00 am
450 Wednesday, August
26,
2009 12:
00:
00 am
451 Wednesday,
2009 August,
26 12:
00:
00 am
452 Wednesday,
2009 August,
28 8.00.00 pm
453 Wednesday,
2009 August,
28 08:
00:
00 PM
457 if (dateString ==
"" || dateString == null || dateString == undefined)
459 if (dateString instanceof Date) {
460 // we already have a date object, no need to parse string here
464 var dateArr = (dateString + '').replace(/,/g, '').replace(/\./g, ':').replace(/ /g, ' ').split(' ');
465 if (dateArr.length !=
5 && dateArr.length !=
6)
469 var weekDay = dateArr[
0];
470 var day = dateArr[
1];
471 var month = dateArr[
2];
472 var year = dateArr[
3];
473 // make sure month is set properly
474 if (isNaN(parseInt(day))) {
480 if (isNaN(parseInt(year))) {
485 // make sure day and year are set properly
486 if (Number(day)
> Number(year)) {
491 month = months_translated[month];
494 var timeArr = dateArr[
4].split(':');
495 if (timeArr.length !=
3)
497 var hours = Number(timeArr[
0]);
498 var minutes = Number(timeArr[
1]);
499 var seconds = Number(timeArr[
2]);
500 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'pm' && hours <
12)
502 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'am' && hours ==
12)
505 result = new Date(year, month -
1, day, hours, minutes, seconds);
508 // take care of daylight saving time
509 if (config['enableDaylightSaving'].Value) {
511 // determine if date is in summer or winter time
512 var dateSummerTime = isSummertime(result);
514 // work around bug in Nokias calendar api resulting in dates within a different DST to be off by
1 hour
515 if (summertime && !dateSummerTime) {
516 result = new Date(result.getTime() -
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // -
1 hour
517 log('parseDate(): fixing time -
1h: ' + result);
519 else if (!summertime && dateSummerTime) {
520 result = new Date(result.getTime() +
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // +
1 hour
521 log('parseDate(): fixing time +
1h: ' + result);
528 function getWeekdayLocalized(date) {
529 var localizedString = date.toLocaleDateString();
530 if (localizedString.indexOf(
",") == -
1) {
531 return weekdays_translated[date.getDay()];
533 return localizedString.split(',')[
0];
536 // 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"
537 function formatDate(date, format)
539 var day = date.getDate().toString();
540 var month = (date.getMonth() +
1).toString();
541 while (day.length <
2) { day = '
0' + day; }
542 while (month.length <
2) { month = '
0' + month; }
544 if (config['showTodayAsText'].Value && isToday(date))
545 return '
<span class=
"today">' + config['todayText'].Value + '
</span>';
546 if (config['showTodayAsText'].Value && isTomorrow(date))
547 return '
<span class=
"tomorrow">' + config['tomorrowText'].Value + '
</span>';
549 if (format instanceof Date) {
550 // we don't know how to format this
551 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
552 return day + config['dateSeparator'].Value + month;
554 return month + config['dateSeparator'].Value + day;
556 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
557 if (dateArr.length !=
5 && dateArr.length !=
6) {
558 // we don't know how to format this
559 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
560 return day + config['dateSeparator'].Value + month;
562 return month + config['dateSeparator'].Value + day;
566 if (config['dateFormat'].Value == 'MMDD')
568 else if (config['dateFormat'].Value == 'DDMM')
571 // config['dateFormat'].Value == 'auto', try to detect system setting
573 var day_ = dateArr[
1];
574 var month_ = dateArr[
2];
575 var year_ = dateArr[
3];
576 // make sure month is set properly
577 if (isNaN(parseInt(day_))) {
582 } else if (isNaN(parseInt(year_))) {
588 // make sure day and year are set properly
589 if (Number(day_)
> Number(year_))
594 return day + config['dateSeparator'].Value + month;
596 return month + config['dateSeparator'].Value + day;
599 function formatTime(date)
601 // date is a Date() object
602 var hour = date.getHours();
603 var minute = date.getMinutes();
605 // don't use Date().toLocaleTimeString() as it is utterly broken on newer firmwares
606 if (use12hoursTimeFormat) {
617 minute =
"0" + minute;
618 time = hour + timeFormatSeparator + minute +
" " + ap;
624 minute =
"0" + minute;
625 time = hour + timeFormatSeparator + minute;
628 if (config['showNowAsText'].Value && date.getTime() == now.getTime())
629 time = '
<span class=
"now">' + config['nowText'].Value + '
</span>';
630 log(
"formatTime(): " + time +
", use12hoursTimeFormat=" + use12hoursTimeFormat +
", timeFormatSeparator=" + timeFormatSeparator +
", date.toLocateTimeString(): " + date.toLocaleTimeString());
634 function updateData()
641 // check if we got additional or less calendars since our last update
642 var newCalendarList = listCalendars();
643 if (newCalendarList == null) {
644 // Something went wrong fetching the calendars list.
645 // This usually happens when a backup is being made.
646 // Retry the next time updateData() is called by
647 // resetting errorOccured
648 log('updateData(): listCalendars() failed, trying again later...');
649 cacheEntriesHtml = ''; // make sure we replace the currently shown error message on the next update
650 errorOccured = false;
653 if (newCalendarList.length != calendarList.length) {
654 calendarList = newCalendarList;
655 updateCalendarColors();
656 cancelNotification();
657 requestNotification();
658 lastReloadTime = null; // force calendar data reload on this update
663 // only reload calendar data every
6 hours, visual updates occure more often
664 if (!lastReloadTime || now.getTime() - lastReloadTime.getTime()
> reloadInterval) {
665 log('updateData(): reloading calendar data');
667 // meetings have time
668 // 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
669 summertime = isSummertime(now); // cache summer time info for today
670 var meetingList = [];
671 for(var i=
0; i < calendarList.length; i++) {
672 // ignore excluded calendars
673 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
675 var meetingListFiltering = {
676 Type:'CalendarEntry',
678 CalendarName: calendarList[i],
679 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
680 EndRange: (new Date(now.getFullYear(), now.getMonth() + config['monthRange'].Value, now.getDate(),
0,
0,
0))
683 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
684 if (meetingResult.ErrorCode !=
0)
685 throw(
"Error fetching calendar data: " + meetingResult.ErrorCode + ': ' + meetingResult.ErrorMessage);
686 var list = meetingResult.ReturnValue;
687 meetingList = meetingList.concat(listToArray(list, calendarList[i]));
689 log(
"updateData(): meetingList.sort()");
690 meetingList.sort(sortCalendarEntries);
692 // todos don't, they start on
00:
00 hrs., but should be visible anyway
693 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
694 if (config['includeTodos'].Value) {
695 var todayTodoList = [];
696 for(var i=
0; i < calendarList.length; i++) {
697 // ignore excluded calendars
698 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
700 var todayTodoListFiltering = {
701 Type:'CalendarEntry',
703 CalendarName: calendarList[i],
705 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
706 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
709 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
710 var list = todayTodoResult.ReturnValue;
711 todayTodoList = todayTodoList.concat(listToArray(list, calendarList[i]));
713 log(
"updateData(): todayTodoList.sort()");
714 todayTodoList.sort(sortCalendarEntries);
715 entryLists = [todayTodoList, meetingList];
717 entryLists = [meetingList];
719 lastReloadTime = new Date();
721 error('loading Calendar items list:' + e + ', line ' + e.line);
731 var fontsize = 'normal';
732 var lineheight = 'normal';
734 fontsize = parseInt(
72 / config['eventsPerWidget'].Value) + 'px';
735 lineheight = parseInt(
82 / config['eventsPerWidget'].Value) + 'px';
737 if (config['eventsPerWidget'].Value ==
3) {
738 changeCssClass('.icon', 'width:
20px; height:
20px');
740 else if (config['eventsPerWidget'].Value ==
5) {
741 changeCssClass('.icon', 'width:
10px; height:
10px');
743 else if (config['eventsPerWidget'].Value ==
6) {
744 changeCssClass('.icon', 'width:
8px; height:
8px');
748 changeCssClass('.icon', config['cssStyle_icon'].Value);
749 var entriesHtml = '
<table style=
"font-size:' + fontsize + '; line-height:' + lineheight + ';">';
751 entriesHtml = '
<table width=
"307" height=
"82"><tr><td>' + entriesHtml; // this is needed to center the actual content vertically
755 max = (panelNum +
1) * config['eventsPerWidget'].Value;
757 max =
30; // we can display a lot more events in fullscreen mode
759 if (config['enableLogging'].Value) {
761 for (var i=
0; i < entryLists.length; i++) {
762 listinfo = listinfo +
" " + entryLists[i].length;
763 var entrieslist =
"";
764 for (var j=
0; j < entryLists[i].length; j++) {
765 entrieslist += entryLists[i][j].Summary +
", ";
767 log(
"updateData(): entrieslist: " + entrieslist);
769 log(
"updateData(): inner loop, " + entryLists.length +
" lists, [" + listinfo +
"] entries");
772 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
773 for (var i=
0; counter < max && i < entryLists.length; i++) {
774 for (var j=
0; (counter < max) && (j < entryLists[i].length); j++) {
775 entry = entryLists[i][j];
778 // output event info for debugging
779 var entryInfo =
"event: ";
780 for(var k=
0; k < entryFields.length; ++k) {
781 if (entry[entryFields[k]] != undefined) {
782 entryInfo += entryFields[k] +
"=" + entry[entryFields[k]] +
",";
787 // we don't want ToDos when includeTodos == false or when they are completed
788 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !config['includeTodos'].Value)) {
789 log('skipping ' + entry.id );
794 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
795 if (eventIds[entry.id] ==
1 && entry.Type == 'ToDo') {
796 log('skipped (already included) ' + entry.id);
800 eventIds[entry.id] =
1;
802 // summary can be undefined!
803 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
804 if (entry.Location != '' && entry.Location != undefined && config['showLocation'].Value)
805 Summary += ', ' + entry.Location;
807 // fix by yves: determine start and end dates/times
808 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
809 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
811 // there can be ToDos that have no date at all!
812 if (entry.Type == 'ToDo' && entry.EndTime == null)
813 entryDate =
""; // this will cause parseDate(entryDate) to return null;
815 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
817 // Convert date/time string to Date object
818 var date = parseDate(entryDate);
819 log('date: ' + date);
820 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
821 log('endDate: ' + endDate);
823 // check if Meeting is actually a DayEvent. Bug introduced by
"Anna" updates to various Symbian^
3 devices.
824 // Note that this workaround is not
100% save! It might missinterpret some meetings as dayevents of starting and ending on
00:
00
825 if (entry.Type == 'Meeting' && date.getHours() ==
0 && date.getMinutes() ==
0 &&
826 endDate != null && endDate.getHours() ==
0 && endDate.getMinutes() ==
0) {
827 log('fixing event type: changed from
"Meeting" to
"DayEvent".');
828 entry.Type = 'DayEvent';
831 // check if meeting event has already passed
832 if (entry.Type == 'Meeting') {
833 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
834 if (now.getTime()
> compareTime) {
835 log('skipping Meeting (already passed) ' + entry.id);
837 eventIds[entry.id] =
0;
842 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
843 if (entry.Type == 'Anniversary') {
844 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
845 if (date.getTime() < tmp.getTime()) {
846 log('skipping Anniversary (already passed) ' + entry.id);
848 eventIds[entry.id] =
0;
853 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
854 if (entry.Type == 'DayEvent' && endDate != null) {
855 endDate.setMinutes(endDate.getMinutes() -
1);
856 log('fixing DayEvent endDate: ' + endDate);
857 if (now.getTime()
> endDate.getTime()) {
858 log('event already passed ' + entry.id);
860 eventIds[entry.id] =
0;
865 // check if the event is currently taking place
866 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
867 // check if we are between start and endtime
868 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
869 date = now; // change appointment date/time to now
870 log('event is currently taking place: ' + date);
874 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
875 if (mode ==
0 && panelNum
> 0 && counter < panelNum * config['eventsPerWidget'].Value +
1) {
876 log('skipping (already in first widget) ' + entry.id);
880 // mark overdue todos
882 if (entry.Type == 'ToDo' && date != null) {
883 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
0,
0,
0);
884 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
885 if (tmp1.getTime() < tmp2.getTime()) {
890 // generate html output
891 entriesHtml += '
<tr>';
892 if (config['showCalendarIndicator'].Value && calendarList.length - config['excludedCalendars'].Value.length
> 1) {
893 entriesHtml += '
<td><span class=
"calendar' + calendarColors[entry.CalendarName] + '"> </span></td>';
895 entriesHtml += '
<td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
897 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
898 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
900 var weekDay = getWeekdayLocalized(date).substr(
0,config['weekDayLength'].Value);
901 log('date.toLocaleDateString(): ' + date.toLocaleDateString());
902 log('weekDay: ' + weekDay);
903 var time = formatTime(date);
904 var dateStr = formatDate(date, entryDate);
905 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
906 dateStr = '
<span class=
"overdue">' + config['overdueText'].Value + '
</span>';
907 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
908 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
909 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
910 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
912 entriesHtml += '
<td class=
"weekDay" width=
"1px">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
913 } else if (entry.Type == 'Meeting') {
914 if (config['showCombinedDateTime'].Value) {
916 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
917 else if (isTomorrow(date))
918 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
920 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
922 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
923 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
925 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
929 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
932 entriesHtml += '
</table>';
934 entriesHtml = entriesHtml + '
</td></tr></table>';
935 if (config['showNothingText'].Value && entriesHtml == '
<table></table>') {
936 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
937 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '
</div>';
939 if (cacheEntriesHtml != entriesHtml) {
941 document.getElementById('calendarList').innerHTML = entriesHtml;
943 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
944 cacheEntriesHtml = entriesHtml;
947 lastUpdateTime = new Date();
949 error('displaying list:' + e + ', line ' + e.line);
954 // called by handleOnShow() and onResize events
955 function updateScreen()
957 log('updateScreen()');
959 // check if opening fullscreen
960 if( window.innerHeight
> 91 && mode ==
0) {
962 cacheEntriesHtml = '';
963 document.getElementById('body').style.backgroundImage =
"";
966 else if (window.innerHeight <=
91 && mode !=
0) {
968 cacheEntriesHtml = '';
973 updateHomescreen(); // check for screen rotation
978 function handleOnShow()
982 var time = new Date();
983 if (time.getTime() - lastUpdateTime.getTime()
> config['updateDataInterval'].Value *
60 *
1000) {
984 log('updateScreen(): force updateData() because last update was too long ago (' + (time.getTime() - lastUpdateTime.getTime()) /
1000 + 's)');
987 setUpdateTimer(); // reinitialize update timer
991 function launchCalendar()
994 widget.openApplication(config['calendarApp'].Value,
"");
995 if (config['hideWidgetOnCalendarOpen'].Value)
998 error('starting Calendar App');
1005 log('New widget instance starting up...');
1008 // call calendar service
1009 if (device !=
"undefined")
1010 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
1012 throw('device object does not exist');
1014 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>');
1018 calendarList = listCalendars();
1020 updateCalendarColors();
1023 requestNotification();
1024 document.getElementById(
"settingsTitle").innerHTML = getLocalizedText('menu.settings');
1026 if (window.innerHeight
> 91) {
1027 mode =
0; // we're starting fullscreen, we set mode to homescreen in order to let updateScreen() do all the work for us
1032 log(
"init(): updateScreen()");
1034 if (config['useBackgroundImage'].Value)
1035 // check for screen rotation every
1 secs
1036 screenRotationTimer = window.setInterval('checkOrientation()',
1000 *
1);
1038 // call updateScreen() when widget changes from background to forground
1039 window.widget.onshow = handleOnShow;
1041 log(
"init(): finished...");
1043 statupSuccessful = true;
1046 function checkOrientation()
1050 updateHomescreen(); // check for screen rotation
1053 function setUpdateTimer()
1055 updateTimer = window.setInterval('updateTimerCallback()',
1000 *
60 * config['updateDataInterval'].Value);
1058 function clearUpdateTimer()
1060 window.clearInterval(updateTimer);
1063 function updateTimerCallback()
1065 log(
"updateTimerCallback()");
1069 function createMenu()
1071 window.menu.setLeftSoftkeyLabel(
"",null);
1072 window.menu.setRightSoftkeyLabel(
"",null);
1074 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
1075 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
1076 var menuHelp = new MenuItem(getLocalizedText('menu.help'), id++);
1077 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
1078 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
1079 menuSettings.onSelect = showSettings;
1080 menuAbout.onSelect = showAbout;
1081 menuCallApp.onSelect = launchCalendar;
1082 menuUpdate.onSelect = showUpdate;
1083 menuHelp.onSelect = showHelp;
1084 window.menu.clear();
1085 window.menu.append(menuCallApp);
1086 window.menu.append(menuSettings);
1087 window.menu.append(menuHelp);
1088 window.menu.append(menuUpdate);
1089 window.menu.append(menuAbout);
1092 function showSettings()
1096 document.getElementById(
"settingsView").style.display =
"block";
1097 document.onclick = null;
1099 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
1101 for (var key in config) {
1102 if (config[key].Type == 'String')
1103 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
1104 else if (config[key].Type == 'Int') {
1105 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
1106 if (config[key].Value <
0 || isNaN(config[key].Value))
1107 config[key].Value = config[key].Default;
1109 else if (config[key].Type == 'Bool')
1110 config[key].Value = document.forms[
0].elements[
"settings." + key].checked;
1111 else if (config[key].Type == 'UID') {
1112 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
1113 if (isNaN(config[key].Value))
1114 config[key].Value = config[key].Default;
1116 else if (config[key].Type == 'Enum') {
1117 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
1118 if (config[key].ValidValues.indexOf(config[key].Value) == -
1)
1119 config[key].Value = config[key].Default;
1121 else if (config[key].Type == 'Array') {
1122 if (key == 'excludedCalendars') {
1123 config[key].Value = new Array();
1124 for(var i=
0; i < calendarList.length; i++) {
1125 var element = document.forms[
0].elements[
"settings." + key +
"." + calendarList[i]];
1126 if (element != null && element.checked == false)
1127 config[key].Value.push(calendarList[i]);
1140 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
1146 var settingsHtml = '
<form>';
1147 for (var key in config) {
1148 if (config[key].Type == 'String') {
1150 if (key.substring(
0,
9) ==
"cssStyle_")
1151 prefix = getLocalizedText('settings.cssStyle_prefix');
1152 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 />';
1154 else if (config[key].Type == 'Int')
1155 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 />';
1156 else if (config[key].Type == 'Bool')
1157 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 />';
1158 else if (config[key].Type == 'UID')
1159 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 />';
1160 else if (config[key].Type == 'Enum') {
1161 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><select name=
"settings.' + key + '" size=
"1">';
1162 for(var i =
0; i < config[key].ValidValues.length; i++)
1163 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>';
1164 settingsHtml += '
</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1166 else if (config[key].Type == 'Array') {
1167 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br />';
1168 if (key == 'excludedCalendars') {
1169 for(var i=
0; i < calendarList.length; i++) {
1170 var checked = '
checked=
"checked"';
1171 if (config[key].Value.indexOf(calendarList[i]) != -
1)
1173 settingsHtml += '
<input name=
"settings.' + key + '.' + calendarList[i] + '" type=
"checkbox" value=
"' + calendarList[i] + '" ' + checked + '
/> ' + calendarList[i] + '
<br />';
1176 settingsHtml += '
</td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1179 settingsHtml += '
<input name=
"reset" type=
"button" value=
"' + getLocalizedText('settings.restoreDefaults') + '" onclick=
"javascript:restoreDefaultSettings();showSettings();" />';
1180 settingsHtml += '
</form>';
1181 document.getElementById(
"settingsList").innerHTML = settingsHtml;
1184 function changeCssClass(classname, properties)
1186 for(var i =
0; i < document.styleSheets[
0]['cssRules'].length; i++)
1188 if (document.styleSheets[
0]['cssRules'][i].selectorText == classname) {
1189 document.styleSheets[
0].deleteRule(i);
1190 document.styleSheets[
0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[
0]['cssRules'].length);
1196 function updateCssClasses()
1198 for(var key in config) {
1199 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
1203 function getSettingsCalEntryId()
1205 if (settingsCalEntryId == null) {
1206 // check if entry already exists
1207 var listFiltering = {
1208 Type:'CalendarEntry',
1210 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!
1211 EndRange: new Date(
2000,
0,
2),
1212 SearchText: 'ComingNext Settings|',
1218 result = calendarService.IDataSource.GetList(listFiltering);
1219 if (result.ErrorCode)
1220 throw(result.ErrorMessage);
1223 error(
"getSettingsCalEntryId: GetList() failed: " + e + ', line ' + e.line);
1226 var list = result.ReturnValue;
1227 var entry = list.getNext();
1228 if (entry != undefined) {
1229 settingsCalEntryId = entry.LocalId;
1230 log(
"settingsCalEntryId=" + settingsCalEntryId);
1232 else { // create settings item
1233 var item = new Object();
1234 item.Type =
"DayEvent";
1235 item.StartTime = new Date(
2000,
0,
1);
1236 item.Summary =
"ComingNext Settings|";
1238 var criteria = new Object();
1239 criteria.Type =
"CalendarEntry";
1240 criteria.Item = item;
1243 var result = calendarService.IDataSource.Add(criteria);
1244 if (result.ErrorCode)
1245 throw(result.ErrorMessage);
1247 error(
"getSettingsCalEntryId: " + e + ', line ' + e.line);
1250 getSettingsCalEntryId();
1255 function restoreDefaultSettings()
1257 for (var key in config)
1258 config[key].Value = config[key].Default;
1261 function loadSettings()
1263 getSettingsCalEntryId();
1264 var listFiltering = {
1265 Type:'CalendarEntry',
1267 LocalId: settingsCalEntryId
1272 result = calendarService.IDataSource.GetList(listFiltering);
1273 if (result.ErrorCode)
1274 throw(result.ErrorMessage);
1277 error(
"loadSettings: GetList() failed: " + e + ', line ' + e.line);
1280 var entry = result.ReturnValue.getNext();
1281 if (entry != undefined) {
1282 log(
"Loading Settings...");
1283 // only reload settings if they chanced since the last reload
1284 if (settingsCache != entry.Summary)
1286 restoreDefaultSettings();
1287 var stringlist = entry.Summary.split(
"|");
1288 // skip the first two entries, those contain header and version info
1289 for(var i =
2; i < stringlist.length -
1; i++) {
1290 var pair = stringlist[i].split('=');
1292 var value = pair[
1];
1293 if (key == null || value == null || config[key] == null) {
1294 log('Warning: unknown or invalid setting: ' + stringlist[i]);
1297 log('stringlist: ' + key + '=\'' + value + '\'');
1298 if (config[key].Type == 'Int') {
1299 config[key].Value = Number(value);
1300 if (isNaN(config[key].Value))
1301 config[key].Value = config[key].Default;
1303 else if (config[key].Type == 'String')
1304 config[key].Value = value;
1305 else if (config[key].Type == 'Bool')
1306 config[key].Value = (value == 'true')
1307 else if (config[key].Type == 'Enum')
1308 config[key].Value = value;
1309 else if (config[key].Type == 'UID') {
1310 config[key].Value = Number(value);
1311 if (isNaN(config[key].Value))
1312 config[key].Value = config[key].Default;
1314 else if (config[key].Type == 'Array') {
1315 config[key].Value = value.split(
"^");
1316 if (config[key].Value.length ==
1 && config[key].Value[
0] ==
"") {
1317 config[key].Value = [];
1321 settingsCache = entry.Summary;
1325 log(
"Settings already cached and did not change");
1329 error(
"Failed to load settings, calendar entry could not be found");
1333 function saveSettings()
1335 getSettingsCalEntryId();
1336 var item = new Object();
1337 item.Type =
"DayEvent";
1338 item.StartTime = new Date(
2000,
0,
1);
1339 item.LocalId = settingsCalEntryId;
1340 item.Summary =
"ComingNext Settings|" + version +
"|";
1342 for (var key in config) {
1343 if (config[key].Type == 'Int')
1344 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1345 else if (config[key].Type == 'String')
1346 item.Summary += key +
"=" + config[key].Value +
"|";
1347 else if (config[key].Type == 'Bool')
1348 item.Summary += key +
"=" + (config[key].Value ? 'true' : 'false') +
"|";
1349 else if (config[key].Type == 'Enum')
1350 item.Summary += key +
"=" + config[key].Value +
"|";
1351 else if (config[key].Type == 'UID')
1352 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1353 else if (config[key].Type == 'Array')
1354 item.Summary += key +
"=" + config[key].Value.join(
"^") +
"|";
1356 settingsCache = item.Summary;
1358 var criteria = new Object();
1359 criteria.Type =
"CalendarEntry";
1360 criteria.Item = item;
1362 log(
"Saving settings to calendar entry: " + item.Summary);
1364 var result = calendarService.IDataSource.Add(criteria);
1365 if (result.ErrorCode)
1366 throw(result.ErrorMessage);
1368 error(
"saveSettings: " + e + ', line ' + e.line);
1371 lastReloadTime = null; // force calendar data reload on next update
1376 function toggleVisibility(elementId)
1378 if (document.getElementById(elementId).style.display ==
"none")
1379 document.getElementById(elementId).style.display =
"block";
1381 document.getElementById(elementId).style.display =
"none";
1385 function printHintBox(text)
1388 return '
<td width=
"1%" align=
"right" onclick=
"javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '
</td></tr></table>'+
1389 '
<div class=
"settingsInfo" id=
"info' + uniqueId + '">' + text + '
</div>';
1392 function showAbout()
1396 document.getElementById(
"aboutView").style.display =
"block";
1397 document.onclick = null;
1399 window.menu.setLeftSoftkeyLabel(
" ", function(){});
1400 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1406 //document.getElementById(
"aboutView").innerHTML = 'aboutView';
1407 document.getElementById(
"name").innerHTML =
"Coming Next " + version;
1410 function showHelp() {
1411 widget.openURL('http://comingnext.sf.net/help');
1414 function updateFullscreen()
1418 function showFullscreen()
1420 log(
"showFullscreen()");
1422 document.getElementById(
"fullscreenView").style.display =
"block";
1423 document.getElementById('body').className =
"backgroundFullscreen";
1425 document.onclick = launchCalendar;
1430 function getBackgroundImage()
1435 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[
0]) // internal
1436 bgImage = 'background_' + orientation + '.png';
1438 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
1442 function updateHomescreen()
1444 if (config['useBackgroundImage'].Value) {
1445 // check if we have a completely unknown screen resolution
1446 var screenHeight = screen.height;
1447 var screenWidth = screen.width;
1448 if (screenHeight !=
640 && screenHeight !=
480 && screenHeight !=
360)
1449 screenHeight =
360; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1450 if (screenWidth !=
640 && screenWidth !=
480 && screenWidth !=
360)
1451 screenWidth =
640; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1453 // check for screen rotation
1454 if (orientation != 'portrait' && ((screenWidth ==
360 && screenHeight ==
640) || (screenWidth ==
640 && screenHeight ==
480))) {
1455 window.widget.prepareForTransition(
"fade");
1456 orientation = 'portrait';
1457 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1458 document.getElementById('body').style.backgroundColor = 'none';
1459 window.widget.performTransition();
1460 } else if (orientation != 'landscape' && ((screenWidth ==
640 && screenHeight ==
360) || (screenWidth ==
480 && screenHeight ==
640))) {
1461 window.widget.prepareForTransition(
"fade");
1462 orientation = 'landscape';
1463 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1464 document.getElementById('body').style.backgroundColor = 'none';
1465 window.widget.performTransition();
1467 else if (document.getElementById('body').style.backgroundImage ==
"")
1469 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1474 function showHomescreen()
1476 log(
"showHomescreen()");
1478 document.getElementById(
"homescreenView").style.display =
"block";
1479 document.getElementById('body').className =
"background";
1480 document.onclick = null;
1484 function getLocalizedText(p_Txt)
1486 if (localizedText[p_Txt])
1487 return localizedText[p_Txt];
1489 return 'ERROR: missing translation for ' + p_Txt;
1492 function showUpdate()
1496 document.getElementById(
"updateView").style.display =
"block";
1497 document.onclick = null;
1499 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1502 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1508 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
1512 function checkForUpdate()
1514 // asynch XHR to server url
1515 reqV = new XMLHttpRequest();
1516 reqV.onreadystatechange = checkForUpdateCallback;
1517 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
1518 reqV.open(
"GET", versionURL, true);
1519 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1523 function checkForUpdateCallback()
1525 if (reqV.readyState ==
4) {
1526 if (reqV.status ==
200) {
1527 var resultXml = reqV.responseText;
1529 var div = document.getElementById(
"tmp");
1530 div.innerHTML = resultXml;
1531 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
1532 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
1534 if (version != newVersion) {
1535 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1538 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1543 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1548 function hideViews()
1550 document.getElementById(
"homescreenView").style.display =
"none";
1551 document.getElementById(
"fullscreenView").style.display =
"none";
1552 document.getElementById(
"aboutView").style.display =
"none";
1553 document.getElementById(
"settingsView").style.display =
"none";
1554 document.getElementById(
"updateView").style.display =
"none";
1557 function listCalendars()
1567 DefaultCalendar: false
1571 var calendarsResult = calendarService.IDataSource.GetList(criteria);
1572 if (calendarsResult.ErrorCode !=
0)
1573 throw(
"Error fetching list of calendars: " + calendarsResult.ErrorCode + ': ' + calendarsResult.ErrorMessage);
1574 var calendarListIterator = calendarsResult.ReturnValue;
1579 while (( item = calendarListIterator.getNext()) != undefined ) {
1580 calendars[count++] = item;
1582 log(
"Available Calendars: " + calendars.join(
", "));
1585 error('listing calendars:' + e + ', line ' + e.line);
1590 // Copies all objects and their properties to an array. Data is copied so nothing gets lost when the reference is removed
1591 // 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
1592 function listToArray(list, calendarName)
1594 var array = new Array();
1597 while (( item = list.getNext()) != undefined ) {
1598 var itemCopy = new Object();
1599 for(var i=
0; i < entryFields.length; i++) {
1600 itemCopy[entryFields[i]] = item[entryFields[i]];
1602 // for some reason, the CalendarName property is never correctly queried, so we assign it manually here
1603 if (!itemCopy['CalendarName']) {
1604 itemCopy['CalendarName'] = calendarName;
1606 array.push(itemCopy);
1607 txt += array[array.length -
1].Summary +
", ";
1609 log(
"listToArray(): " + txt);
1613 function sortCalendarEntries(a, b)
1616 log(
"sortCalendarEntries(" + a.Summary +
"," + b.Summary +
")");
1618 if (a.InstanceStartTime != null) {
1619 atime = a.InstanceStartTime;
1621 else if (a.StartTime != null) {
1622 atime = a.StartTime;
1624 else if (a.InstanceEndTime != null) {
1625 atime = a.InstanceEndTime;
1627 else if (a.EndTime != null) {
1631 if (b.InstanceStartTime != null) {
1632 btime = b.InstanceStartTime;
1634 else if (b.StartTime != null) {
1635 btime = b.StartTime;
1637 else if (b.InstanceEndTime != null) {
1638 btime = b.InstanceEndTime;
1640 else if (b.EndTime != null) {
1644 if (atime && btime) {
1646 atime = parseDate(atime);
1647 btime = parseDate(btime);
1649 // sort by date & time
1650 if (atime < btime) {
1653 else if (atime
> btime) {
1657 else if (a.Type != b.Type) {
1658 if (a.Type < b.Type) {
1661 else if (a.Type
> b.Type) {
1665 // sort by description
1666 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1667 if (a.Summary < b.Summary) {
1670 else if (a.Summary
> b.Summary) {
1675 // NOTE: events my have no date information at all. In that case, we list events without date first
1676 else if (atime && !btime) {
1679 else if (!atime && btime) {
1682 else if (!atime && !btime) {
1684 if (a.Type != b.Type) {
1685 if (a.Type < b.Type) {
1688 else if (a.Type
> b.Type) {
1692 // sort by description
1693 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1694 if (a.Summary < b.Summary) {
1697 else if (a.Summary
> b.Summary) {
1706 function updateCalendarColors()
1709 calendarColors = [];
1710 if (calendarList.length
> maxColors) {
1711 log(
"updateCalendarColors(): Warning: more calendars than available indicator colors");
1713 for(var i=
0; i < calendarList.length; i++) {
1714 calendarColors[calendarList[i]] = (i % maxColors) +
1;
1718 function log(message)
1720 if (config['enableLogging'].Value) {
1721 console.info(message);
1727 <style type=
"text/css">
1729 table { margin:
0px; padding:
0px; border-spacing:
0px; border-collapse: collapse; }
1730 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; margin:
0px; }
1731 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1732 .settingsInfo { display:none; font-style:italic; }
1733 .title { font-weight:bold; font-size:
14pt; }
1734 .textInput { width:
90%; }
1735 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1736 #homescreenView { width:
312px; height:
82px; overflow:hidden; }
1737 #calendarList { position:absolute; left:
5px; top:
0px; width:
307px; height:
82px; overflow:hidden; }
1738 #name { text-align:center; }
1739 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1740 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1745 <body onload=
"javascript:setTimeout('init()', 10)" onresize=
"javascript:updateScreen()" id=
"body" class=
"background">
1746 <div id=
"homescreenView">
1747 <div id=
"calendarList">loading...
</div>
1749 <div id=
"fullscreenView" style=
"display:none;">
1750 <img src=
"Icon.png" id=
"smallappicon">
1751 <h1 class=
"title">Coming Next
</h1>
1753 <div id=
"fullscreenCalendarList">loading...
</div>
1755 <div id=
"settingsView" style=
"display:none">
1756 <img src=
"Icon.png" id=
"smallappicon">
1757 <h1 id=
"settingsTitle" class=
"title">Settings
</h1>
1759 <div id=
"settingsList"></div>
1761 <div id=
"aboutView" style=
"display:none">
1762 <img src=
"Icon.png" id=
"appicon">
1763 <h1 id=
"name">Coming Next
</h1>
1765 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1766 <p>Contributions:
</p>
1767 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1768 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1769 <p class=
"credits">Christophe Milsent (translation support & french translation)
</p>
1770 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation)
</p>
1771 <p class=
"credits">Tokeda (russian translation)
</p>
1772 <p class=
"credits">Marcella Ferrari (italian translation)
</p>
1773 <p class=
"credits">Venos (italian translation)
</p>
1774 <p>This software is open source and licensed under the GPLv3.
</p>
1775 <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>
1778 <div id=
"updateView" style=
"display:none">
1779 <img src=
"Icon.png" id=
"smallappicon">
1780 <h1 class=
"title">Check for update
</h1>
1782 <div id=
"currentVersion">Coming Next ??
</div>
1783 <div id=
"updateDiv"></div>
1784 <div id=
"tmp" style=
"display:none;"></div>