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
111 // vars for daylight saving time
112 var summertime = false; // true, if current date is in summer, false if in winter
113 var daylightSavingDates = new Object(); // caches calculated DST winter and summer time shift dates
115 // this is a list of data fields a calendar event can have
129 function isLeapYear( year ) {
130 if (( year %
4 ==
0 && year %
100 !=
0 ) || year %
400 ==
0 )
136 function calcLeapYear(year, days)
138 if (isLeapYear(year))
144 function subToSunday(myDate, year, days, prevMonthDays)
146 for (i = myDate.getDay(); i
> 0 ;i--)
148 days -= prevMonthDays;
149 days = isLeapYear(year) ? --days : days;
153 function isSummertime(curDate)
158 // if we already calculated DST summer and winter time dates for this year, use cached values
159 var dst = daylightSavingDates[curDate.getFullYear()];
161 var thisYearS = new Date(curDate.getFullYear(),
3,
0,
0,
0,
0 );
162 var thisYearW = new Date(curDate.getFullYear(),
10,
0,
0,
0,
0 );
163 var nextYearS = new Date(curDate.getFullYear() +
1,
3,
0,
0,
0,
0 );
164 var nextYearW = new Date(curDate.getFullYear() +
1,
10,
0,
0,
0,
0 );
166 thisYearSDays = nextYearSDays =
90;
167 thisYearWDays = nextYearWDays =
304;
169 thisYearSDays = calcLeapYear(curDate.getFullYear(), thisYearSDays);
170 thisYearWDays = calcLeapYear(curDate.getFullYear(), thisYearWDays);
171 nextYearSDays = calcLeapYear(curDate.getFullYear() +
1, nextYearSDays);
172 nextYearWDays = calcLeapYear(curDate.getFullYear() +
1, nextYearWDays);
174 thisYearSDays = subToSunday(thisYearS, curDate.getFullYear(), thisYearSDays,
59);
175 thisYearWDays = subToSunday(thisYearW, curDate.getFullYear(), thisYearWDays,
273);
176 nextYearSDays = subToSunday(nextYearS, curDate.getFullYear() +
1, nextYearSDays,
59);
177 nextYearWDays = subToSunday(nextYearW, curDate.getFullYear() +
1, nextYearWDays,
273);
180 Summer: new Date (curDate.getFullYear(),
03-
1, thisYearSDays,
2,
0,
0),
181 Winter: new Date (curDate.getFullYear(),
10-
1, thisYearWDays,
2,
0,
0),
183 daylightSavingDates[curDate.getFullYear()] = dst;
186 if (dst.Summer < curDate)
188 if (dst.Winter < curDate)
190 if (summer && !winter)
196 function error(message)
198 console.info('Error: ' + message);
199 document.getElementById(
"calendarList").innerHTML = 'Error: ' + message;
200 document.getElementById(
"fullscreenCalendarList").innerHTML = 'Error: ' + message;
202 document.onclick = null;
205 function areDatesEqual(date1, date2)
207 return (date1.getFullYear() == date2.getFullYear() &&
208 date1.getMonth() == date2.getMonth() &&
209 date1.getDate() == date2.getDate());
212 function isTomorrow(date)
214 // tommorow = now +
1 day
215 // ToDo: some days can be shorter as
24 hours(daylight saving change day)
216 return areDatesEqual(date, new Date (now.getTime() +
24*
60*
60*
1000));
219 function isToday(date)
221 return areDatesEqual(date, now);
224 function collectLocales()
226 var tmpyear =
2000 + panelNum;
229 if (months_translated.length
> 0)
231 for (month =
0; month <
12; month++) {
232 var startDate = new Date(tmpyear, month,
15);
234 var item = new Object();
235 item.Type =
"DayEvent";
236 item.StartTime = startDate;
237 item.Summary =
"__temp" + month;
239 var criteria = new Object();
240 criteria.Type =
"CalendarEntry";
241 criteria.Item = item;
244 var result = calendarService.IDataSource.Add(criteria);
245 if (result.ErrorCode)
246 throw(result.ErrorMessage);
248 error(
"collectLocales: " + e + ', line ' + e.line);
251 for (weekday =
0; weekday <
7; weekday++) {
252 var startDate = new Date(
2000,
0,
2 + weekday); // date that we know for sure is a sunday
254 var item = new Object();
255 item.Type =
"DayEvent";
256 item.StartTime = startDate;
257 item.Summary =
"__weekday_temp" + weekday;
259 var criteria = new Object();
260 criteria.Type =
"CalendarEntry";
261 criteria.Item = item;
264 var result = calendarService.IDataSource.Add(criteria);
265 if (result.ErrorCode)
266 throw(result.ErrorMessage);
268 error(
"collectLocales: " + e + ', line ' + e.line);
272 var startTime = new Date(tmpyear,
0,
1);
273 var endTime = new Date(tmpyear,
11,
31);
274 var listFiltering = {
275 Type:'CalendarEntry',
277 StartRange: startTime,
279 SearchText: '__temp',
283 var result = calendarService.IDataSource.GetList(listFiltering);
284 if (result.ErrorCode)
285 throw(result.ErrorMessage);
286 var list = result.ReturnValue;
288 error(
"collectLocales: " + e + ', line ' + e.line);
291 var ids = new Array();
297 while (list && (entry = list.getNext()) != undefined) {
298 dateArr = (entry.StartTime + '').replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
299 var day = dateArr[
1];
300 var month = dateArr[
2];
301 var year = dateArr[
3];
303 // make sure month is set properly
304 if (isNaN(parseInt(day))) {
308 } else if (isNaN(parseInt(year))) {
314 log(entry.StartTime + ' -
> ' + month + ' ' + counter);
315 ids[counter] = entry.id;
316 months_translated[month] = counter +
1;
320 error(
"collectLocales: " + e + ', line ' + e.line);
324 var startTime = new Date(
2000,
0,
2);
325 var endTime = new Date(
2000,
0,
9);
326 var listFiltering = {
327 Type:'CalendarEntry',
329 StartRange: startTime,
331 SearchText: '__weekday_temp',
335 var result = calendarService.IDataSource.GetList(listFiltering);
336 if (result.ErrorCode)
337 throw(result.ErrorMessage);
338 var weekdaylist = result.ReturnValue;
340 error(
"collectLocales: " + e + ', line ' + e.line);
348 while (weekdaylist && (entry = weekdaylist.getNext()) != undefined) {
349 curWeekday = (entry.StartTime + '').split(',')[
0];
350 log(entry.StartTime + ' -
> ' + curWeekday + ' ' + counter2);
351 ids[counter + counter2] = entry.id;
352 weekdays_translated[counter2] = curWeekday;
356 error(
"collectLocales: " + e + ', line ' + e.line);
361 var criteria = new Object();
362 criteria.Type =
"CalendarEntry";
367 var result = calendarService.IDataSource.Delete(criteria);
368 if (result.ErrorCode)
369 throw(result.ErrorMessage);
371 error('deleting temp calendar entries:' + e + ', line ' + e.line);
376 function requestNotification()
378 var criteria = new Object();
379 criteria.Type =
"CalendarEntry";
380 criteria.Filter = new Object();
381 for(var i=
0; i < calendarList.length; i++) {
382 criteria.Filter.CalendarName = calendarList[i];
384 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria, callback);
385 if (notificationRequest.ErrorCode)
386 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
387 notificationRequests.push(notificationRequest);
389 error(
"requestNotification: " + e + ', line ' + e.line);
393 var criteria2 = new Object();
394 criteria2.Type =
"CalendarEntry";
395 criteria2.Filter = new Object();
396 criteria2.Filter.LocalIdList = new Array();
397 criteria2.Filter.LocalIdList[
0] = settingsCalEntryId;
399 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria2, settingsCallback);
400 if (notificationRequest.ErrorCode)
401 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
402 notificationRequests.push(notificationRequest);
404 error(
"requestNotification: " + e + ', line ' + e.line);
408 function cancelNotification()
410 for(var i=
0; i < notificationRequests.length; i++) {
412 var result = calendarService.IDataSource.Cancel(notificationRequests[i]);
413 if (result.ErrorCode)
414 error('cancelNotification failed with error code ' + result.ErrorCode);
416 error(
"cancelNotification: " + e + ', line ' + e.line);
421 function callback(transId, eventCode, result)
423 log(
"callback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
424 lastReloadTime = null; // force calendar data reload on next update
428 function settingsCallback(transId, eventCode, result)
430 log(
"settingsCallback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
434 function parseDate(dateString)
437 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:
438 Wednesday,
26 August,
2009 24:
00:
00
439 Wednesday,
26 August,
2009 12:
00:
00 am
440 Wednesday, August
26,
2009 12:
00:
00 am
441 Wednesday,
2009 August,
26 12:
00:
00 am
442 Wednesday,
2009 August,
28 8.00.00 pm
443 Wednesday,
2009 August,
28 08:
00:
00 PM
447 if (dateString ==
"" || dateString == null || dateString == undefined)
449 if (dateString instanceof Date) {
450 // we already have a date object, no need to parse string here
454 var dateArr = (dateString + '').replace(/,/g, '').replace(/\./g, ':').replace(/ /g, ' ').split(' ');
455 if (dateArr.length !=
5 && dateArr.length !=
6)
459 var weekDay = dateArr[
0];
460 var day = dateArr[
1];
461 var month = dateArr[
2];
462 var year = dateArr[
3];
463 // make sure month is set properly
464 if (isNaN(parseInt(day))) {
470 if (isNaN(parseInt(year))) {
475 // make sure day and year are set properly
476 if (Number(day)
> Number(year)) {
481 month = months_translated[month];
484 var timeArr = dateArr[
4].split(':');
485 if (timeArr.length !=
3)
487 var hours = Number(timeArr[
0]);
488 var minutes = Number(timeArr[
1]);
489 var seconds = Number(timeArr[
2]);
490 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'pm' && hours <
12)
492 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'am' && hours ==
12)
495 // remember if date was formated using
12h time format, we need to use this information later when formating time
496 if (dateArr.length ==
6 && (dateArr[
5].toLowerCase() == 'am' || dateArr[
5].toLowerCase() == 'pm'))
497 use12hoursTimeFormat = true;
499 result = new Date(year, month -
1, day, hours, minutes, seconds);
502 // take care of daylight saving time
503 if (config['enableDaylightSaving'].Value) {
505 // determine if date is in summer or winter time
506 var dateSummerTime = isSummertime(result);
508 // work around bug in Nokias calendar api resulting in dates within a different DST to be off by
1 hour
509 if (summertime && !dateSummerTime) {
510 result = new Date(result.getTime() -
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // -
1 hour
511 log('parseDate(): fixing time -
1h: ' + result);
513 else if (!summertime && dateSummerTime) {
514 result = new Date(result.getTime() +
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // +
1 hour
515 log('parseDate(): fixing time +
1h: ' + result);
522 function getWeekdayLocalized(date) {
523 var localizedString = date.toLocaleDateString();
524 if (localizedString.match(/\d\d\/\d\d\/\d\d/)) {
525 return weekdays_translated[date.getDay()];
527 return localizedString.split(',')[
0];
530 // 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"
531 function formatDate(date, format)
533 var day = date.getDate().toString();
534 var month = (date.getMonth() +
1).toString();
535 while (day.length <
2) { day = '
0' + day; }
536 while (month.length <
2) { month = '
0' + month; }
538 if (config['showTodayAsText'].Value && isToday(date))
539 return '
<span class=
"today">' + config['todayText'].Value + '
</span>';
540 if (config['showTodayAsText'].Value && isTomorrow(date))
541 return '
<span class=
"tomorrow">' + config['tomorrowText'].Value + '
</span>';
543 if (format instanceof Date) {
544 // we don't know how to format this
545 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
546 return day + config['dateSeparator'].Value + month;
548 return month + config['dateSeparator'].Value + day;
550 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
551 if (dateArr.length !=
5 && dateArr.length !=
6) {
552 // we don't know how to format this
553 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
554 return day + config['dateSeparator'].Value + month;
556 return month + config['dateSeparator'].Value + day;
560 if (config['dateFormat'].Value == 'MMDD')
562 else if (config['dateFormat'].Value == 'DDMM')
565 // config['dateFormat'].Value == 'auto', try to detect system setting
567 var day_ = dateArr[
1];
568 var month_ = dateArr[
2];
569 var year_ = dateArr[
3];
570 // make sure month is set properly
571 if (isNaN(parseInt(day_))) {
576 } else if (isNaN(parseInt(year_))) {
582 // make sure day and year are set properly
583 if (Number(day_)
> Number(year_))
588 return day + config['dateSeparator'].Value + month;
590 return month + config['dateSeparator'].Value + day;
593 function formatTime(date)
595 // date is a Date() object
596 date.setSeconds(
0); // we don't care about seconds
597 var time = date.toLocaleTimeString().replace(/[\.:]
00/, ''); // remove seconds from string
598 if (time.replace(/\./, ':').split(':')[
0].length <
2)
601 // workaround for bug introduced by Anna firmwares, which causes Date().toLocaleTimeString() to no longer return time in
12h format even though this has been defined in system settings
602 if (use12hoursTimeFormat && time.toLowerCase().indexOf('am') == -
1 && time.toLowerCase().indexOf('pm') == -
1) {
603 var hour = date.getHours();
604 var minute = date.getMinutes();
615 minute =
"0" + minute;
616 time = hour +
":" + minute +
" " + ap;
619 if (config['showNowAsText'].Value && date.getTime() == now.getTime())
620 time = '
<span class=
"now">' + config['nowText'].Value + '
</span>';
624 function updateData()
631 // check if we got additional or less calendars since our last update
632 var newCalendarList = listCalendars();
633 if (newCalendarList == null) {
634 // Something went wrong fetching the calendars list.
635 // This usually happens when a backup is being made.
636 // Retry the next time updateData() is called by
637 // resetting errorOccured
638 log('updateData(): listCalendars() failed, trying again later...');
639 cacheEntriesHtml = ''; // make sure we replace the currently shown error message on the next update
640 errorOccured = false;
643 if (newCalendarList.length != calendarList.length) {
644 calendarList = newCalendarList;
645 updateCalendarColors();
646 cancelNotification();
647 requestNotification();
648 lastReloadTime = null; // force calendar data reload on this update
653 // only reload calendar data every
6 hours, visual updates occure more often
654 if (!lastReloadTime || now.getTime() - lastReloadTime.getTime()
> reloadInterval) {
655 log('updateData(): reloading calendar data');
657 // meetings have time
658 // 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
659 summertime = isSummertime(now); // cache summer time info for today
660 var meetingList = [];
661 for(var i=
0; i < calendarList.length; i++) {
662 // ignore excluded calendars
663 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
665 var meetingListFiltering = {
666 Type:'CalendarEntry',
668 CalendarName: calendarList[i],
669 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
670 EndRange: (new Date(now.getFullYear(), now.getMonth() + config['monthRange'].Value, now.getDate(),
0,
0,
0))
673 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
674 if (meetingResult.ErrorCode !=
0)
675 throw(
"Error fetching calendar data: " + meetingResult.ErrorCode + ': ' + meetingResult.ErrorMessage);
676 var list = meetingResult.ReturnValue;
677 meetingList = meetingList.concat(listToArray(list, calendarList[i]));
679 log(
"updateData(): meetingList.sort()");
680 meetingList.sort(sortCalendarEntries);
682 // todos don't, they start on
00:
00 hrs., but should be visible anyway
683 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
684 if (config['includeTodos'].Value) {
685 var todayTodoList = [];
686 for(var i=
0; i < calendarList.length; i++) {
687 // ignore excluded calendars
688 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
690 var todayTodoListFiltering = {
691 Type:'CalendarEntry',
693 CalendarName: calendarList[i],
695 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
696 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
699 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
700 var list = todayTodoResult.ReturnValue;
701 todayTodoList = todayTodoList.concat(listToArray(list, calendarList[i]));
703 log(
"updateData(): todayTodoList.sort()");
704 todayTodoList.sort(sortCalendarEntries);
705 entryLists = [todayTodoList, meetingList];
707 entryLists = [meetingList];
709 lastReloadTime = new Date();
711 error('loading Calendar items list:' + e + ', line ' + e.line);
721 var fontsize = 'normal';
723 if (config['eventsPerWidget'].Value ==
3) {
725 changeCssClass('.icon', 'width:
20px; height:
20px');
727 else if (config['eventsPerWidget'].Value ==
5) {
729 changeCssClass('.icon', 'width:
10px; height:
10px');
731 else if (config['eventsPerWidget'].Value ==
6) {
733 changeCssClass('.icon', 'width:
8px; height:
8px');
737 changeCssClass('.icon', config['cssStyle_icon'].Value);
738 var entriesHtml = '
<table style=
"font-size:' + fontsize + ';">';
742 max = (panelNum +
1) * config['eventsPerWidget'].Value;
744 max =
30; // we can display a lot more events in fullscreen mode
746 if (config['enableLogging'].Value) {
748 for (var i=
0; i < entryLists.length; i++) {
749 listinfo = listinfo +
" " + entryLists[i].length;
750 var entrieslist =
"";
751 for (var j=
0; j < entryLists[i].length; j++) {
752 entrieslist += entryLists[i][j].Summary +
", ";
754 log(
"updateData(): entrieslist: " + entrieslist);
756 log(
"updateData(): inner loop, " + entryLists.length +
" lists, [" + listinfo +
"] entries");
759 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
760 for (var i=
0; counter < max && i < entryLists.length; i++) {
761 for (var j=
0; (counter < max) && (j < entryLists[i].length); j++) {
762 entry = entryLists[i][j];
765 // output event info for debugging
766 var entryInfo =
"event: ";
767 for(var k=
0; k < entryFields.length; ++k) {
768 if (entry[entryFields[k]] != undefined) {
769 entryInfo += entryFields[k] +
"=" + entry[entryFields[k]] +
",";
774 // we don't want ToDos when includeTodos == false or when they are completed
775 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !config['includeTodos'].Value)) {
776 log('skipping ' + entry.id );
781 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
782 if (eventIds[entry.id] ==
1 && entry.Type == 'ToDo') {
783 log('skipped (already included) ' + entry.id);
787 eventIds[entry.id] =
1;
789 // summary can be undefined!
790 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
791 if (entry.Location != '' && entry.Location != undefined && config['showLocation'].Value)
792 Summary += ', ' + entry.Location;
794 // fix by yves: determine start and end dates/times
795 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
796 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
798 // there can be ToDos that have no date at all!
799 if (entry.Type == 'ToDo' && entry.EndTime == null)
800 entryDate =
""; // this will cause parseDate(entryDate) to return null;
802 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
804 // Convert date/time string to Date object
805 var date = parseDate(entryDate);
806 log('date: ' + date);
807 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
808 log('endDate: ' + endDate);
810 // check if Meeting is actually a DayEvent. Bug introduced by
"Anna" updates to various Symbian^
3 devices.
811 // Note that this workaround is not
100% save! It might missinterpret some meetings as dayevents of starting and ending on
00:
00
812 if (entry.Type == 'Meeting' && date.getHours() ==
0 && date.getMinutes() ==
0 &&
813 endDate != null && endDate.getHours() ==
0 && endDate.getMinutes() ==
0) {
814 log('fixing event type: changed from
"Meeting" to
"DayEvent".');
815 entry.Type = 'DayEvent';
818 // check if meeting event has already passed
819 if (entry.Type == 'Meeting') {
820 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
821 if (now.getTime()
> compareTime) {
822 log('skipping Meeting (already passed) ' + entry.id);
824 eventIds[entry.id] =
0;
829 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
830 if (entry.Type == 'Anniversary') {
831 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
832 if (date.getTime() < tmp.getTime()) {
833 log('skipping Anniversary (already passed) ' + entry.id);
835 eventIds[entry.id] =
0;
840 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
841 if (entry.Type == 'DayEvent' && endDate != null) {
842 endDate.setMinutes(endDate.getMinutes() -
1);
843 log('fixing DayEvent endDate: ' + endDate);
844 if (now.getTime()
> endDate.getTime()) {
845 log('event already passed ' + entry.id);
847 eventIds[entry.id] =
0;
852 // check if the event is currently taking place
853 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
854 // check if we are between start and endtime
855 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
856 date = now; // change appointment date/time to now
857 log('event is currently taking place: ' + date);
861 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
862 if (mode ==
0 && panelNum
> 0 && counter < panelNum * config['eventsPerWidget'].Value +
1) {
863 log('skipping (already in first widget) ' + entry.id);
867 // mark overdue todos
869 if (entry.Type == 'ToDo' && date != null) {
870 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
0,
0,
0);
871 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
872 if (tmp1.getTime() < tmp2.getTime()) {
877 // generate html output
878 entriesHtml += '
<tr>';
879 if (config['showCalendarIndicator'].Value && calendarList.length - config['excludedCalendars'].Value.length
> 1) {
880 entriesHtml += '
<td><span class=
"calendar' + calendarColors[entry.CalendarName] + '"> </span></td>';
882 entriesHtml += '
<td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
884 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
885 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
887 var weekDay = getWeekdayLocalized(date).substr(
0,config['weekDayLength'].Value);
888 log('date.toLocaleDateString(): ' + date.toLocaleDateString());
889 log('weekDay: ' + weekDay);
890 var time = formatTime(date);
891 var dateStr = formatDate(date, entryDate);
892 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
893 dateStr = '
<span class=
"overdue">' + config['overdueText'].Value + '
</span>';
894 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
895 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
896 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
897 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
899 entriesHtml += '
<td class=
"weekDay" width=
"1px">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
900 } else if (entry.Type == 'Meeting') {
901 if (config['showCombinedDateTime'].Value) {
903 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
904 else if (isTomorrow(date))
905 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
907 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
909 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
910 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
912 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
916 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
919 entriesHtml += '
</table>';
920 if (config['showNothingText'].Value && entriesHtml == '
<table></table>') {
921 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
922 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '
</div>';
924 if (cacheEntriesHtml != entriesHtml) {
926 document.getElementById('calendarList').innerHTML = entriesHtml;
928 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
929 cacheEntriesHtml = entriesHtml;
932 lastUpdateTime = new Date();
934 error('displaying list:' + e + ', line ' + e.line);
939 // called by handleOnShow() and onResize events
940 function updateScreen()
942 log('updateScreen()');
944 // check if opening fullscreen
945 if( window.innerHeight
> 91 && mode ==
0) {
947 cacheEntriesHtml = '';
948 document.getElementById('body').style.backgroundImage =
"";
951 else if (window.innerHeight <=
91 && mode !=
0) {
953 cacheEntriesHtml = '';
958 updateHomescreen(); // check for screen rotation
963 function handleOnShow()
967 var time = new Date();
968 if (time.getTime() - lastUpdateTime.getTime()
> config['updateDataInterval'].Value *
60 *
1000) {
969 log('updateScreen(): force updateData() because last update was too long ago (' + (time.getTime() - lastUpdateTime.getTime()) /
1000 + 's)');
972 setUpdateTimer(); // reinitialize update timer
976 function launchCalendar()
979 widget.openApplication(config['calendarApp'].Value,
"");
980 if (config['hideWidgetOnCalendarOpen'].Value)
983 error('starting Calendar App');
990 log('New widget instance starting up...');
993 // call calendar service
994 if (device !=
"undefined")
995 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
997 throw('device object does not exist');
999 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>');
1003 calendarList = listCalendars();
1005 updateCalendarColors();
1008 requestNotification();
1009 document.getElementById(
"settingsTitle").innerHTML = getLocalizedText('menu.settings');
1011 if (window.innerHeight
> 91) {
1012 mode =
0; // we're starting fullscreen, we set mode to homescreen in order to let updateScreen() do all the work for us
1017 log(
"init(): updateScreen()");
1019 if (config['useBackgroundImage'].Value)
1020 // check for screen rotation every
1 secs
1021 screenRotationTimer = window.setInterval('checkOrientation()',
1000 *
1);
1023 // call updateScreen() when widget changes from background to forground
1024 window.widget.onshow = handleOnShow;
1026 log(
"init(): finished...");
1028 statupSuccessful = true;
1031 function checkOrientation()
1035 updateHomescreen(); // check for screen rotation
1038 function setUpdateTimer()
1040 updateTimer = window.setInterval('updateTimerCallback()',
1000 *
60 * config['updateDataInterval'].Value);
1043 function clearUpdateTimer()
1045 window.clearInterval(updateTimer);
1048 function updateTimerCallback()
1050 log(
"updateTimerCallback()");
1054 function createMenu()
1056 window.menu.setLeftSoftkeyLabel(
"",null);
1057 window.menu.setRightSoftkeyLabel(
"",null);
1059 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
1060 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
1061 var menuHelp = new MenuItem(getLocalizedText('menu.help'), id++);
1062 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
1063 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
1064 menuSettings.onSelect = showSettings;
1065 menuAbout.onSelect = showAbout;
1066 menuCallApp.onSelect = launchCalendar;
1067 menuUpdate.onSelect = showUpdate;
1068 menuHelp.onSelect = showHelp;
1069 window.menu.clear();
1070 window.menu.append(menuCallApp);
1071 window.menu.append(menuSettings);
1072 window.menu.append(menuHelp);
1073 window.menu.append(menuUpdate);
1074 window.menu.append(menuAbout);
1077 function showSettings()
1081 document.getElementById(
"settingsView").style.display =
"block";
1082 document.onclick = null;
1084 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
1086 for (var key in config) {
1087 if (config[key].Type == 'String')
1088 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
1089 else if (config[key].Type == 'Int') {
1090 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
1091 if (config[key].Value <
0 || isNaN(config[key].Value))
1092 config[key].Value = config[key].Default;
1094 else if (config[key].Type == 'Bool')
1095 config[key].Value = document.forms[
0].elements[
"settings." + key].checked;
1096 else if (config[key].Type == 'UID') {
1097 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
1098 if (isNaN(config[key].Value))
1099 config[key].Value = config[key].Default;
1101 else if (config[key].Type == 'Enum') {
1102 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
1103 if (config[key].ValidValues.indexOf(config[key].Value) == -
1)
1104 config[key].Value = config[key].Default;
1106 else if (config[key].Type == 'Array') {
1107 if (key == 'excludedCalendars') {
1108 config[key].Value = new Array();
1109 for(var i=
0; i < calendarList.length; i++) {
1110 var element = document.forms[
0].elements[
"settings." + key +
"." + calendarList[i]];
1111 if (element != null && element.checked == false)
1112 config[key].Value.push(calendarList[i]);
1125 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
1131 var settingsHtml = '
<form>';
1132 for (var key in config) {
1133 if (config[key].Type == 'String') {
1135 if (key.substring(
0,
9) ==
"cssStyle_")
1136 prefix = getLocalizedText('settings.cssStyle_prefix');
1137 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 />';
1139 else if (config[key].Type == 'Int')
1140 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 />';
1141 else if (config[key].Type == 'Bool')
1142 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 />';
1143 else if (config[key].Type == 'UID')
1144 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 />';
1145 else if (config[key].Type == 'Enum') {
1146 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><select name=
"settings.' + key + '" size=
"1">';
1147 for(var i =
0; i < config[key].ValidValues.length; i++)
1148 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>';
1149 settingsHtml += '
</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1151 else if (config[key].Type == 'Array') {
1152 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br />';
1153 if (key == 'excludedCalendars') {
1154 for(var i=
0; i < calendarList.length; i++) {
1155 var checked = '
checked=
"checked"';
1156 if (config[key].Value.indexOf(calendarList[i]) != -
1)
1158 settingsHtml += '
<input name=
"settings.' + key + '.' + calendarList[i] + '" type=
"checkbox" value=
"' + calendarList[i] + '" ' + checked + '
/> ' + calendarList[i] + '
<br />';
1161 settingsHtml += '
</td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1164 settingsHtml += '
<input name=
"reset" type=
"button" value=
"' + getLocalizedText('settings.restoreDefaults') + '" onclick=
"javascript:restoreDefaultSettings();showSettings();" />';
1165 settingsHtml += '
</form>';
1166 document.getElementById(
"settingsList").innerHTML = settingsHtml;
1169 function changeCssClass(classname, properties)
1171 for(var i =
0; i < document.styleSheets[
0]['cssRules'].length; i++)
1173 if (document.styleSheets[
0]['cssRules'][i].selectorText == classname) {
1174 document.styleSheets[
0].deleteRule(i);
1175 document.styleSheets[
0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[
0]['cssRules'].length);
1181 function updateCssClasses()
1183 for(var key in config) {
1184 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
1188 function getSettingsCalEntryId()
1190 if (settingsCalEntryId == null) {
1191 // check if entry already exists
1192 var listFiltering = {
1193 Type:'CalendarEntry',
1195 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!
1196 EndRange: new Date(
2000,
0,
2),
1197 SearchText: 'ComingNext Settings|',
1203 result = calendarService.IDataSource.GetList(listFiltering);
1204 if (result.ErrorCode)
1205 throw(result.ErrorMessage);
1208 error(
"getSettingsCalEntryId: GetList() failed: " + e + ', line ' + e.line);
1211 var list = result.ReturnValue;
1212 var entry = list.getNext();
1213 if (entry != undefined) {
1214 settingsCalEntryId = entry.LocalId;
1215 log(
"settingsCalEntryId=" + settingsCalEntryId);
1217 else { // create settings item
1218 var item = new Object();
1219 item.Type =
"DayEvent";
1220 item.StartTime = new Date(
2000,
0,
1);
1221 item.Summary =
"ComingNext Settings|";
1223 var criteria = new Object();
1224 criteria.Type =
"CalendarEntry";
1225 criteria.Item = item;
1228 var result = calendarService.IDataSource.Add(criteria);
1229 if (result.ErrorCode)
1230 throw(result.ErrorMessage);
1232 error(
"getSettingsCalEntryId: " + e + ', line ' + e.line);
1235 getSettingsCalEntryId();
1240 function restoreDefaultSettings()
1242 for (var key in config)
1243 config[key].Value = config[key].Default;
1246 function loadSettings()
1248 getSettingsCalEntryId();
1249 var listFiltering = {
1250 Type:'CalendarEntry',
1252 LocalId: settingsCalEntryId
1257 result = calendarService.IDataSource.GetList(listFiltering);
1258 if (result.ErrorCode)
1259 throw(result.ErrorMessage);
1262 error(
"loadSettings: GetList() failed: " + e + ', line ' + e.line);
1265 var entry = result.ReturnValue.getNext();
1266 if (entry != undefined) {
1267 log(
"Loading Settings...");
1268 // only reload settings if they chanced since the last reload
1269 if (settingsCache != entry.Summary)
1271 restoreDefaultSettings();
1272 var stringlist = entry.Summary.split(
"|");
1273 // skip the first two entries, those contain header and version info
1274 for(var i =
2; i < stringlist.length -
1; i++) {
1275 var pair = stringlist[i].split('=');
1277 var value = pair[
1];
1278 if (key == null || value == null || config[key] == null) {
1279 log('Warning: unknown or invalid setting: ' + stringlist[i]);
1282 log('stringlist: ' + key + '=\'' + value + '\'');
1283 if (config[key].Type == 'Int') {
1284 config[key].Value = Number(value);
1285 if (isNaN(config[key].Value))
1286 config[key].Value = config[key].Default;
1288 else if (config[key].Type == 'String')
1289 config[key].Value = value;
1290 else if (config[key].Type == 'Bool')
1291 config[key].Value = (value == 'true')
1292 else if (config[key].Type == 'Enum')
1293 config[key].Value = value;
1294 else if (config[key].Type == 'UID') {
1295 config[key].Value = Number(value);
1296 if (isNaN(config[key].Value))
1297 config[key].Value = config[key].Default;
1299 else if (config[key].Type == 'Array') {
1300 config[key].Value = value.split(
"^");
1301 if (config[key].Value.length ==
1 && config[key].Value[
0] ==
"") {
1302 config[key].Value = [];
1306 settingsCache = entry.Summary;
1310 log(
"Settings already cached and did not change");
1314 error(
"Failed to load settings, calendar entry could not be found");
1318 function saveSettings()
1320 getSettingsCalEntryId();
1321 var item = new Object();
1322 item.Type =
"DayEvent";
1323 item.StartTime = new Date(
2000,
0,
1);
1324 item.LocalId = settingsCalEntryId;
1325 item.Summary =
"ComingNext Settings|" + version +
"|";
1327 for (var key in config) {
1328 if (config[key].Type == 'Int')
1329 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1330 else if (config[key].Type == 'String')
1331 item.Summary += key +
"=" + config[key].Value +
"|";
1332 else if (config[key].Type == 'Bool')
1333 item.Summary += key +
"=" + (config[key].Value ? 'true' : 'false') +
"|";
1334 else if (config[key].Type == 'Enum')
1335 item.Summary += key +
"=" + config[key].Value +
"|";
1336 else if (config[key].Type == 'UID')
1337 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1338 else if (config[key].Type == 'Array')
1339 item.Summary += key +
"=" + config[key].Value.join(
"^") +
"|";
1341 settingsCache = item.Summary;
1343 var criteria = new Object();
1344 criteria.Type =
"CalendarEntry";
1345 criteria.Item = item;
1347 log(
"Saving settings to calendar entry: " + item.Summary);
1349 var result = calendarService.IDataSource.Add(criteria);
1350 if (result.ErrorCode)
1351 throw(result.ErrorMessage);
1353 error(
"saveSettings: " + e + ', line ' + e.line);
1356 lastReloadTime = null; // force calendar data reload on next update
1361 function toggleVisibility(elementId)
1363 if (document.getElementById(elementId).style.display ==
"none")
1364 document.getElementById(elementId).style.display =
"block";
1366 document.getElementById(elementId).style.display =
"none";
1370 function printHintBox(text)
1373 return '
<td width=
"1%" align=
"right" onclick=
"javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '
</td></tr></table>'+
1374 '
<div class=
"settingsInfo" id=
"info' + uniqueId + '">' + text + '
</div>';
1377 function showAbout()
1381 document.getElementById(
"aboutView").style.display =
"block";
1382 document.onclick = null;
1384 window.menu.setLeftSoftkeyLabel(
" ", function(){});
1385 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1391 //document.getElementById(
"aboutView").innerHTML = 'aboutView';
1392 document.getElementById(
"name").innerHTML =
"Coming Next " + version;
1395 function showHelp() {
1396 widget.openURL('http://comingnext.sf.net/help');
1399 function updateFullscreen()
1403 function showFullscreen()
1405 log(
"showFullscreen()");
1407 document.getElementById(
"fullscreenView").style.display =
"block";
1408 document.getElementById('body').className =
"backgroundFullscreen";
1410 document.onclick = launchCalendar;
1415 function getBackgroundImage()
1420 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[
0]) // internal
1421 bgImage = 'background_' + orientation + '.png';
1423 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
1427 function updateHomescreen()
1429 if (config['useBackgroundImage'].Value) {
1430 // check if we have a completely unknown screen resolution
1431 var screenHeight = screen.height;
1432 var screenWidth = screen.width;
1433 if (screenHeight !=
640 && screenHeight !=
480 && screenHeight !=
360)
1434 screenHeight =
360; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1435 if (screenWidth !=
640 && screenWidth !=
480 && screenWidth !=
360)
1436 screenWidth =
640; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1438 // check for screen rotation
1439 if (orientation != 'portrait' && ((screenWidth ==
360 && screenHeight ==
640) || (screenWidth ==
640 && screenHeight ==
480))) {
1440 window.widget.prepareForTransition(
"fade");
1441 orientation = 'portrait';
1442 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1443 document.getElementById('body').style.backgroundColor = 'none';
1444 window.widget.performTransition();
1445 } else if (orientation != 'landscape' && ((screenWidth ==
640 && screenHeight ==
360) || (screenWidth ==
480 && screenHeight ==
640))) {
1446 window.widget.prepareForTransition(
"fade");
1447 orientation = 'landscape';
1448 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1449 document.getElementById('body').style.backgroundColor = 'none';
1450 window.widget.performTransition();
1452 else if (document.getElementById('body').style.backgroundImage ==
"")
1454 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1459 function showHomescreen()
1461 log(
"showHomescreen()");
1463 document.getElementById(
"homescreenView").style.display =
"block";
1464 document.getElementById('body').className =
"background";
1465 document.onclick = null;
1469 function getLocalizedText(p_Txt)
1471 if (localizedText[p_Txt])
1472 return localizedText[p_Txt];
1474 return 'ERROR: missing translation for ' + p_Txt;
1477 function showUpdate()
1481 document.getElementById(
"updateView").style.display =
"block";
1482 document.onclick = null;
1484 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1487 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1493 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
1497 function checkForUpdate()
1499 // asynch XHR to server url
1500 reqV = new XMLHttpRequest();
1501 reqV.onreadystatechange = checkForUpdateCallback;
1502 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
1503 reqV.open(
"GET", versionURL, true);
1504 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1508 function checkForUpdateCallback()
1510 if (reqV.readyState ==
4) {
1511 if (reqV.status ==
200) {
1512 var resultXml = reqV.responseText;
1514 var div = document.getElementById(
"tmp");
1515 div.innerHTML = resultXml;
1516 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
1517 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
1519 if (version != newVersion) {
1520 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1523 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1528 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1533 function hideViews()
1535 document.getElementById(
"homescreenView").style.display =
"none";
1536 document.getElementById(
"fullscreenView").style.display =
"none";
1537 document.getElementById(
"aboutView").style.display =
"none";
1538 document.getElementById(
"settingsView").style.display =
"none";
1539 document.getElementById(
"updateView").style.display =
"none";
1542 function listCalendars()
1552 DefaultCalendar: false
1556 var calendarsResult = calendarService.IDataSource.GetList(criteria);
1557 if (calendarsResult.ErrorCode !=
0)
1558 throw(
"Error fetching list of calendars: " + calendarsResult.ErrorCode + ': ' + calendarsResult.ErrorMessage);
1559 var calendarListIterator = calendarsResult.ReturnValue;
1564 while (( item = calendarListIterator.getNext()) != undefined ) {
1565 calendars[count++] = item;
1567 log(
"Available Calendars: " + calendars.join(
", "));
1570 error('listing calendars:' + e + ', line ' + e.line);
1575 // Copies all objects and their properties to an array. Data is copied so nothing gets lost when the reference is removed
1576 // 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
1577 function listToArray(list, calendarName)
1579 var array = new Array();
1582 while (( item = list.getNext()) != undefined ) {
1583 var itemCopy = new Object();
1584 for(var i=
0; i < entryFields.length; i++) {
1585 itemCopy[entryFields[i]] = item[entryFields[i]];
1587 // for some reason, the CalendarName property is never correctly queried, so we assign it manually here
1588 if (!itemCopy['CalendarName']) {
1589 itemCopy['CalendarName'] = calendarName;
1591 array.push(itemCopy);
1592 txt += array[array.length -
1].Summary +
", ";
1594 log(
"listToArray(): " + txt);
1598 function sortCalendarEntries(a, b)
1601 log(
"sortCalendarEntries(" + a.Summary +
"," + b.Summary +
")");
1603 if (a.InstanceStartTime != null) {
1604 atime = a.InstanceStartTime;
1606 else if (a.StartTime != null) {
1607 atime = a.StartTime;
1609 else if (a.InstanceEndTime != null) {
1610 atime = a.InstanceEndTime;
1612 else if (a.EndTime != null) {
1616 if (b.InstanceStartTime != null) {
1617 btime = b.InstanceStartTime;
1619 else if (b.StartTime != null) {
1620 btime = b.StartTime;
1622 else if (b.InstanceEndTime != null) {
1623 btime = b.InstanceEndTime;
1625 else if (b.EndTime != null) {
1629 if (atime && btime) {
1631 atime = parseDate(atime);
1632 btime = parseDate(btime);
1634 // sort by date & time
1635 if (atime < btime) {
1638 else if (atime
> btime) {
1642 else if (a.Type != b.Type) {
1643 if (a.Type < b.Type) {
1646 else if (a.Type
> b.Type) {
1650 // sort by description
1651 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1652 if (a.Summary < b.Summary) {
1655 else if (a.Summary
> b.Summary) {
1660 // NOTE: events my have no date information at all. In that case, we list events without date first
1661 else if (atime && !btime) {
1664 else if (!atime && btime) {
1667 else if (!atime && !btime) {
1669 if (a.Type != b.Type) {
1670 if (a.Type < b.Type) {
1673 else if (a.Type
> b.Type) {
1677 // sort by description
1678 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1679 if (a.Summary < b.Summary) {
1682 else if (a.Summary
> b.Summary) {
1691 function updateCalendarColors()
1694 calendarColors = [];
1695 if (calendarList.length
> maxColors) {
1696 log(
"updateCalendarColors(): Warning: more calendars than available indicator colors");
1698 for(var i=
0; i < calendarList.length; i++) {
1699 calendarColors[calendarList[i]] = (i % maxColors) +
1;
1703 function log(message)
1705 if (config['enableLogging'].Value) {
1706 console.info(message);
1712 <style type=
"text/css">
1714 table { margin:
0px; padding:
0px; border-spacing:
0px; }
1715 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
1716 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1717 .settingsInfo { display:none; font-style:italic; }
1718 .title { font-weight:bold; font-size:
14pt; }
1719 .textInput { width:
90%; }
1720 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1721 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
1722 #calendarList { position:absolute; left:
5px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
1723 #name { text-align:center; }
1724 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1725 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1730 <body onload=
"javascript:setTimeout('init()', 10)" onresize=
"javascript:updateScreen()" id=
"body" class=
"background">
1731 <div id=
"homescreenView">
1732 <div id=
"calendarList">loading...
</div>
1734 <div id=
"fullscreenView" style=
"display:none;">
1735 <img src=
"Icon.png" id=
"smallappicon">
1736 <h1 class=
"title">Coming Next
</h1>
1738 <div id=
"fullscreenCalendarList">loading...
</div>
1740 <div id=
"settingsView" style=
"display:none">
1741 <img src=
"Icon.png" id=
"smallappicon">
1742 <h1 id=
"settingsTitle" class=
"title">Settings
</h1>
1744 <div id=
"settingsList"></div>
1746 <div id=
"aboutView" style=
"display:none">
1747 <img src=
"Icon.png" id=
"appicon">
1748 <h1 id=
"name">Coming Next
</h1>
1750 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1751 <p>Contributions:
</p>
1752 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1753 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1754 <p class=
"credits">Christophe Milsent (translation support & french translation)
</p>
1755 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation)
</p>
1756 <p class=
"credits">Tokeda (russian translation)
</p>
1757 <p class=
"credits">Marcella Ferrari (italian translation)
</p>
1758 <p class=
"credits">Venos (italian translation)
</p>
1759 <p>This software is open source and licensed under the GPLv3.
</p>
1760 <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>
1763 <div id=
"updateView" style=
"display:none">
1764 <img src=
"Icon.png" id=
"smallappicon">
1765 <h1 class=
"title">Check for update
</h1>
1767 <div id=
"currentVersion">Coming Next ??
</div>
1768 <div id=
"updateDiv"></div>
1769 <div id=
"tmp" style=
"display:none;"></div>