1 <?xml version=
"1.0" encoding=
"UTF-8"?>
2 <!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns=
"http://www.w3.org/1999/xhtml">
6 <title>Coming Next
</title>
8 <style type=
"text/css">
9 /* The following classes can be modified by widget settings */
10 .background { color:#ffffff; background-color:#
000000 }
11 .backgroundFullscreen { color:#ffffff; background-color:#
000000 }
14 .today { color:#ff0000 }
15 .tomorrow { color:#
0000ff }
17 .now { color:#ff00ff }
19 .icon { width:
15px; height:
15px }
20 .overdue { color:#ffff00 }
21 .calendar1 { background-color:#
0757cf }
22 .calendar2 { background-color:#
579f37 }
23 .calendar3 { background-color:#ff9f07 }
24 .calendar4 { background-color:#af8fef }
25 .calendar5 { background-color:#
57afbf }
26 .calendar6 { background-color:#
9fdf57 }
29 <script type=
"text/javascript" src=
"localizedTextStrings.js" charset=
"utf-8" />
32 // valid types for the config object are 'Int', 'Bool', 'String', 'Enum', 'UID', 'Array'
34 monthRange: { Type: 'Int', Default:
2, Value:
2,},
35 includeTodos: { Type: 'Bool', Default: true, Value: true,},
36 useBackgroundImage: { Type: 'Bool', Default: true, Value: true,},
37 backgroundImageLocation: { Type: 'Enum', Default: 'internal', Value: 'internal', ValidValues: ['internal', 'external']},
38 showCombinedDateTime: { Type: 'Bool', Default: false, Value: false,},
39 showLocation: { Type: 'Bool', Default: true, Value: true,},
40 showTodayAsText: { Type: 'Bool', Default: true, Value: true,},
41 todayText: { Type: 'String', Default: getLocalizedText('settings.default.todayText'), Value: getLocalizedText('settings.default.todayText'),},
42 tomorrowText: { Type: 'String', Default: getLocalizedText('settings.default.tomorrowText'), Value: getLocalizedText('settings.default.tomorrowText'),},
43 showNowAsText: { Type: 'Bool', Default: true, Value: true,},
44 nowText: { Type: 'String', Default: getLocalizedText('settings.default.nowText'), Value: getLocalizedText('settings.default.nowText'),},
45 markOverdueTodos: { Type: 'Bool', Default: true, Value: true,},
46 overdueText: {Type: 'String', Default: getLocalizedText('settings.default.overdueText'), Value: getLocalizedText('settings.default.overdueText'),},
47 dateSeparator: { Type: 'String', Default: getLocalizedText('settings.default.dateSeparator'), Value: getLocalizedText('settings.default.dateSeparator'),},
48 dateFormat: { Type: 'Enum', Default: 'auto', Value: 'auto', ValidValues: ['auto', 'DDMM', 'MMDD'],},
49 weekDayLength: { Type: 'Int', Default:
2, Value:
2,},
50 updateDataInterval: { Type: 'Int', Default:
5, Value:
5,},
51 calendarApp: { Type: 'UID', Default:
0x10005901, Value:
0x10005901,},
52 eventsPerWidget: { Type: 'Int', Default:
4, Value:
4,},
53 showNothingText: { Type: 'Bool', Default: true, Value: true,},
54 nothingText: { Type: 'String', Default: getLocalizedText('settings.default.nothingText'), Value: getLocalizedText('settings.default.nothingText'),},
55 enableDaylightSaving: { Type: 'Bool', Default: true, Value: true,},
56 daylightSavingOffset: { Type: 'Int', Default:
1, Value:
1,},
57 hideWidgetOnCalendarOpen: { Type: 'Bool', Default: false, Value: false,},
58 showCalendarIndicator: { Type: 'Bool', Default: true, Value: true,},
59 excludedCalendars: { Type: 'Array', Default: [], Value: [],},
60 enableLogging: { Type: 'Bool', Default: false, Value: false,},
61 cssStyle_background: { Type: 'String', Default: 'color:#ffffff; background-color:#
000000', Value: 'color:#ffffff; background-color:#
000000',},
62 cssStyle_backgroundFullscreen: { Type: 'String', Default: 'color:#ffffff; background-color:#
000000', Value: 'color:#ffffff; background-color:#
000000',},
63 cssStyle_weekDay: { Type: 'String', Default: '', Value: '',},
64 cssStyle_date: { Type: 'String', Default: '', Value: '',},
65 cssStyle_today: { Type: 'String', Default: 'color:#ff0000', Value: 'color:#ff0000',},
66 cssStyle_tomorrow: { Type: 'String', Default: 'color:#
0000ff', Value: 'color:#
0000ff',},
67 cssStyle_time: { Type: 'String', Default: '', Value: '',},
68 cssStyle_now: { Type: 'String', Default: 'color:#ff00ff', Value: 'color:#ff00ff',},
69 cssStyle_description: { Type: 'String', Default: '', Value: '',},
70 cssStyle_icon: { Type: 'String', Default: 'width:
15px; height:
15px', Value: 'width:
15px; height:
15px',},
71 cssStyle_overdue: { Type: 'String', Default: 'color:#ffff00', Value: 'color:#ffff00',},
72 cssStyle_calendar1: { Type: 'String', Default: 'background-color:#
0757cf', Value: 'background-color:#
0757cf',},
73 cssStyle_calendar2: { Type: 'String', Default: 'background-color:#
579f37', Value: 'background-color:#
579f37',},
74 cssStyle_calendar3: { Type: 'String', Default: 'background-color:#ff9f07', Value: 'background-color:#ff9f07',},
75 cssStyle_calendar4: { Type: 'String', Default: 'background-color:#af8fef', Value: 'background-color:#af8fef',},
76 cssStyle_calendar5: { Type: 'String', Default: 'background-color:#
57afbf', Value: 'background-color:#
57afbf',},
77 cssStyle_calendar6: { Type: 'String', Default: 'background-color:#
9fdf57', Value: 'background-color:#
9fdf57',},
82 //-------------------------------------------------------
83 // Nothing of interest from here on...
84 //-------------------------------------------------------
85 var panelNum =
0; // use
1 for second panel
87 var versionURL =
"http://comingnext.sourceforge.net/version.xml";
88 var calendarService = null;
89 var cacheEntriesHtml = [];
90 var months_translated = [];
93 var mode =
0; //
0 = homescreen,
1 = fullscreen,
2 = settings,
3 = about,
4 = check for update
95 var settingsCalEntryId = null;
96 var settingsCache = null;
97 var notificationRequests = new Array();
98 var calendarList = [];
99 var calendarColors = [];
100 var updateTimer = null;
101 var screenRotationTimer = null;
102 var lastUpdateTime = now; // last time we updated the display
103 var lastReloadTime = null; // last time we fetched calendar data
104 var reloadInterval =
6 *
60 *
60 *
1000; // =
6 hours; time interval for reloading calendar data
105 var errorOccured = false;
106 var entryLists = null; // stores all fetched calendar entries until data is refreshed
108 // vars for daylight saving time
109 var summertime = false; // true, if current date is in summer, false if in winter
110 var daylightSavingDates = new Object(); // caches calculated DST winter and summer time shift dates
112 // this is a list of data fields a calendar event can have
126 function isLeapYear( year ) {
127 if (( year %
4 ==
0 && year %
100 !=
0 ) || year %
400 ==
0 )
133 function calcLeapYear(year, days)
135 if (isLeapYear(year))
141 function subToSunday(myDate, year, days, prevMonthDays)
143 for (i = myDate.getDay(); i
> 0 ;i--)
145 days -= prevMonthDays;
146 days = isLeapYear(year) ? --days : days;
150 function isSummertime(curDate)
155 // if we already calculated DST summer and winter time dates for this year, use cached values
156 var dst = daylightSavingDates[curDate.getFullYear()];
158 var thisYearS = new Date(curDate.getFullYear(),
3,
0,
0,
0,
0 );
159 var thisYearW = new Date(curDate.getFullYear(),
10,
0,
0,
0,
0 );
160 var nextYearS = new Date(curDate.getFullYear() +
1,
3,
0,
0,
0,
0 );
161 var nextYearW = new Date(curDate.getFullYear() +
1,
10,
0,
0,
0,
0 );
163 thisYearSDays = nextYearSDays =
90;
164 thisYearWDays = nextYearWDays =
304;
166 thisYearSDays = calcLeapYear(curDate.getFullYear(), thisYearSDays);
167 thisYearWDays = calcLeapYear(curDate.getFullYear(), thisYearWDays);
168 nextYearSDays = calcLeapYear(curDate.getFullYear() +
1, nextYearSDays);
169 nextYearWDays = calcLeapYear(curDate.getFullYear() +
1, nextYearWDays);
171 thisYearSDays = subToSunday(thisYearS, curDate.getFullYear(), thisYearSDays,
59);
172 thisYearWDays = subToSunday(thisYearW, curDate.getFullYear(), thisYearWDays,
273);
173 nextYearSDays = subToSunday(nextYearS, curDate.getFullYear() +
1, nextYearSDays,
59);
174 nextYearWDays = subToSunday(nextYearW, curDate.getFullYear() +
1, nextYearWDays,
273);
177 Summer: new Date (curDate.getFullYear(),
03-
1, thisYearSDays,
2,
0,
0),
178 Winter: new Date (curDate.getFullYear(),
10-
1, thisYearWDays,
2,
0,
0),
180 daylightSavingDates[curDate.getFullYear()] = dst;
183 if (dst.Summer < curDate)
185 if (dst.Winter < curDate)
187 if (summer && !winter)
193 function error(message)
195 console.info('Error: ' + message);
196 document.getElementById(
"calendarList").innerHTML = 'Error: ' + message;
197 document.getElementById(
"fullscreenCalendarList").innerHTML = 'Error: ' + message;
199 document.onclick = null;
202 function areDatesEqual(date1, date2)
204 return (date1.getFullYear() == date2.getFullYear() &&
205 date1.getMonth() == date2.getMonth() &&
206 date1.getDate() == date2.getDate());
209 function isTomorrow(date)
211 // tommorow = now +
1 day
212 // ToDo: some days can be shorter as
24 hours(daylight saving change day)
213 return areDatesEqual(date, new Date (now.getTime() +
24*
60*
60*
1000));
216 function isToday(date)
218 return areDatesEqual(date, now);
221 function collectLocales()
223 var tmpyear =
2000 + panelNum;
226 if (months_translated.length
> 0)
228 for (month =
0; month <
12; month++) {
229 var startDate = new Date(tmpyear, month,
15);
231 var item = new Object();
232 item.Type =
"DayEvent";
233 item.StartTime = startDate;
234 item.Summary =
"__temp" + month;
236 var criteria = new Object();
237 criteria.Type =
"CalendarEntry";
238 criteria.Item = item;
241 var result = calendarService.IDataSource.Add(criteria);
242 if (result.ErrorCode)
243 error(result.ErrorMessage);
245 error(
"collectLocales: " + e + ', line ' + e.line);
249 var startTime = new Date(tmpyear,
0,
1);
250 var endTime = new Date(tmpyear,
11,
31);
251 var listFiltering = {
252 Type:'CalendarEntry',
254 StartRange: startTime,
256 SearchText: '__temp',
260 var result = calendarService.IDataSource.GetList(listFiltering);
261 if (result.ErrorCode)
262 throw(result.ErrorMessage);
263 var list = result.ReturnValue;
265 error(e + ', line ' + e.line);
268 var ids = new Array();
274 while (list && (entry = list.getNext()) != undefined) {
275 dateArr = entry.StartTime.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
276 var day = dateArr[
1];
277 var month = dateArr[
2];
278 var year = dateArr[
3];
280 // make sure month is set properly
281 if (isNaN(parseInt(day))) {
285 } else if (isNaN(parseInt(year))) {
291 log(entry.StartTime + ' -
> ' + month + ' ' + counter);
292 ids[counter] = entry.id;
293 months_translated[month] = counter +
1;
297 error(e + ', line ' + e.line);
302 var criteria = new Object();
303 criteria.Type =
"CalendarEntry";
308 var result = calendarService.IDataSource.Delete(criteria);
309 if (result.ErrorCode)
310 throw(result.ErrorMessage);
312 error('deleting temp calendar entries:' + e + ', line ' + e.line);
317 function requestNotification()
319 var criteria = new Object();
320 criteria.Type =
"CalendarEntry";
321 criteria.Filter = new Object();
322 for(var i=
0; i < calendarList.length; i++) {
323 criteria.Filter.CalendarName = calendarList[i];
325 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria, callback);
326 if (notificationRequest.ErrorCode)
327 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
328 notificationRequests.push(notificationRequest);
330 error(
"requestNotification: " + e + ', line ' + e.line);
334 var criteria2 = new Object();
335 criteria2.Type =
"CalendarEntry";
336 criteria2.Filter = new Object();
337 criteria2.Filter.LocalIdList = new Array();
338 criteria2.Filter.LocalIdList[
0] = settingsCalEntryId;
340 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria2, settingsCallback);
341 if (notificationRequest.ErrorCode)
342 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
343 notificationRequests.push(notificationRequest);
345 error(
"requestNotification: " + e + ', line ' + e.line);
349 function cancelNotification()
351 for(var i=
0; i < notificationRequests.length; i++) {
353 var result = calendarService.IDataSource.Cancel(notificationRequests[i]);
354 if (result.ErrorCode)
355 error('cancelNotification failed with error code ' + result.ErrorCode);
357 error(
"cancelNotification: " + e + ', line ' + e.line);
362 function callback(transId, eventCode, result)
364 log(
"callback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
365 lastReloadTime = null; // force calendar data reload on next update
369 function settingsCallback(transId, eventCode, result)
371 log(
"settingsCallback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
375 function parseDate(dateString)
378 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:
379 Wednesday,
26 August,
2009 24:
00:
00
380 Wednesday,
26 August,
2009 12:
00:
00 am
381 Wednesday, August
26,
2009 12:
00:
00 am
382 Wednesday,
2009 August,
26 12:
00:
00 am
383 Wednesday,
2009 August,
28 8.00.00 pm
384 Wednesday,
2009 August,
28 08:
00:
00 PM
387 if (dateString ==
"" || dateString == null)
389 var dateArr = dateString.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
390 if (dateArr.length !=
5 && dateArr.length !=
6)
394 var weekDay = dateArr[
0];
395 var day = dateArr[
1];
396 var month = dateArr[
2];
397 var year = dateArr[
3];
398 // make sure month is set properly
399 if (isNaN(parseInt(day))) {
403 } else if (isNaN(parseInt(year))) {
408 // make sure day and year are set properly
409 if (Number(day)
> Number(year)) {
414 month = months_translated[month];
417 var timeArr = dateArr[
4].split(':');
418 if (timeArr.length !=
3)
420 var hours = Number(timeArr[
0]);
421 var minutes = Number(timeArr[
1]);
422 var seconds = Number(timeArr[
2]);
423 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'pm' && hours <
12)
425 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'am' && hours ==
12)
428 var result = new Date(year, month -
1, day, hours, minutes, seconds);
430 // take care of daylight saving time
431 if (config['enableDaylightSaving'].Value) {
433 // determine if date is in summer or winter time
434 var dateSummerTime = isSummertime(result);
436 // work around bug in Nokias calendar api resulting in dates within a different DST to be off by
1 hour
437 if (summertime && !dateSummerTime) {
438 result = new Date(result.getTime() -
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // -
1 hour
439 log('parseDate(): fixing time -
1h: ' + result);
441 else if (!summertime && dateSummerTime) {
442 result = new Date(result.getTime() +
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // +
1 hour
443 log('parseDate(): fixing time +
1h: ' + result);
450 // 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"
451 function formatDate(date, format)
453 var day = date.getDate().toString();
454 var month = (date.getMonth() +
1).toString();
455 while (day.length <
2) { day = '
0' + day; }
456 while (month.length <
2) { month = '
0' + month; }
458 if (config['showTodayAsText'].Value && isToday(date))
459 return '
<span class=
"today">' + config['todayText'].Value + '
</span>';
460 if (config['showTodayAsText'].Value && isTomorrow(date))
461 return '
<span class=
"tomorrow">' + config['tomorrowText'].Value + '
</span>';
463 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
464 if (dateArr.length !=
5 && dateArr.length !=
6) {
465 // we don't know how to format this
466 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
467 return day + config['dateSeparator'].Value + month;
469 return month + config['dateSeparator'].Value + day;
473 if (config['dateFormat'].Value == 'MMDD')
475 else if (config['dateFormat'].Value == 'DDMM')
478 // config['dateFormat'].Value == 'auto', try to detect system setting
480 var day_ = dateArr[
1];
481 var month_ = dateArr[
2];
482 var year_ = dateArr[
3];
483 // make sure month is set properly
484 if (isNaN(parseInt(day_))) {
489 } else if (isNaN(parseInt(year_))) {
495 // make sure day and year are set properly
496 if (Number(day_)
> Number(year_))
501 return day + config['dateSeparator'].Value + month;
503 return month + config['dateSeparator'].Value + day;
506 function formatTime(date)
508 // date is a Date() object
509 date.setSeconds(
0); // we don't care about seconds
510 var time = date.toLocaleTimeString().replace(/[\.:]
00/, ''); // remove seconds from string
511 if (time.replace(/\./, ':').split(':')[
0].length <
2)
513 if (config['showNowAsText'].Value && date.getTime() == now.getTime())
514 time = '
<span class=
"now">' + config['nowText'].Value + '
</span>';
518 function updateData()
525 // check if we got additional or less calendars since our last update
526 var newCalendarList = listCalendars();
527 if (newCalendarList.length != calendarList.length) {
528 calendarList = newCalendarList;
529 updateCalendarColors();
530 cancelNotification();
531 requestNotification();
532 lastReloadTime = null; // force calendar data reload on this update
537 // only reload calendar data every
6 hours, visual updates occure more often
538 if (!lastReloadTime || now.getTime() - lastReloadTime.getTime()
> reloadInterval) {
539 log('updateData(): reloading calendar data');
541 // meetings have time
542 // 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
543 summertime = isSummertime(now); // cache summer time info for today
544 var meetingList = [];
545 for(var i=
0; i < calendarList.length; i++) {
546 // ignore excluded calendars
547 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
549 var meetingListFiltering = {
550 Type:'CalendarEntry',
552 CalendarName: calendarList[i],
553 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
554 EndRange: (new Date(now.getFullYear(), now.getMonth() + config['monthRange'].Value, now.getDate(),
0,
0,
0))
557 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
558 if (meetingResult.ErrorCode !=
0)
559 throw(
"Error fetching calendar data: " + meetingResult.ErrorCode + ': ' + meetingResult.ErrorMessage);
560 var list = meetingResult.ReturnValue;
561 meetingList = meetingList.concat(listToArray(list, calendarList[i]));
563 log(
"updateData(): meetingList.sort()");
564 meetingList.sort(sortCalendarEntries);
566 // todos don't, they start on
00:
00 hrs., but should be visible anyway
567 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
568 if (config['includeTodos'].Value) {
569 var todayTodoList = [];
570 for(var i=
0; i < calendarList.length; i++) {
571 // ignore excluded calendars
572 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
574 var todayTodoListFiltering = {
575 Type:'CalendarEntry',
577 CalendarName: calendarList[i],
579 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
580 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
583 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
584 var list = todayTodoResult.ReturnValue;
585 todayTodoList = todayTodoList.concat(listToArray(list, calendarList[i]));
587 log(
"updateData(): todayTodoList.sort()");
588 todayTodoList.sort(sortCalendarEntries);
589 entryLists = [todayTodoList, meetingList];
591 entryLists = [meetingList];
593 lastReloadTime = new Date();
595 error('loading Calendar items list:' + e + ', line ' + e.line);
605 var fontsize = 'normal';
607 if (config['eventsPerWidget'].Value ==
3) {
609 changeCssClass('.icon', 'width:
20px; height:
20px');
611 else if (config['eventsPerWidget'].Value ==
5) {
613 changeCssClass('.icon', 'width:
10px; height:
10px');
615 else if (config['eventsPerWidget'].Value ==
6) {
617 changeCssClass('.icon', 'width:
8px; height:
8px');
621 changeCssClass('.icon', config['cssStyle_icon'].Value);
622 var entriesHtml = '
<table style=
"font-size:' + fontsize + ';">';
626 max = (panelNum +
1) * config['eventsPerWidget'].Value;
628 max =
30; // we can display a lot more events in fullscreen mode
630 if (config['enableLogging'].Value) {
632 for (var i=
0; i < entryLists.length; i++) {
633 listinfo = listinfo +
" " + entryLists[i].length;
634 var entrieslist =
"";
635 for (var j=
0; j < entryLists[i].length; j++) {
636 entrieslist += entryLists[i][j].Summary +
", ";
638 log(
"updateData(): entrieslist: " + entrieslist);
640 log(
"updateData(): inner loop, " + entryLists.length +
" lists, [" + listinfo +
"] entries");
643 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
644 for (var i=
0; counter < max && i < entryLists.length; i++) {
645 for (var j=
0; (counter < max) && (j < entryLists[i].length); j++) {
646 entry = entryLists[i][j];
649 // output event info for debugging
650 var entryInfo =
"event: ";
651 for(var k=
0; k < entryFields.length; ++k) {
652 if (entry[entryFields[k]] != undefined) {
653 entryInfo += entryFields[k] +
"=" + entry[entryFields[k]] +
",";
658 // we don't want ToDos when includeTodos == false or when they are completed
659 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !config['includeTodos'].Value)) {
660 log('skipping ' + entry.id );
665 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
666 if (eventIds[entry.id] ==
1 && entry.Type == 'ToDo') {
667 log('skipped (already included) ' + entry.id);
671 eventIds[entry.id] =
1;
673 // summary can be undefined!
674 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
675 if (entry.Location != '' && entry.Location != undefined && config['showLocation'].Value)
676 Summary += ', ' + entry.Location;
678 // fix by yves: determine start and end dates/times
679 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
680 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
682 // there can be ToDos that have no date at all!
683 if (entry.Type == 'ToDo' && entry.EndTime == null)
684 entryDate =
""; // this will cause parseDate(entryDate) to return null;
686 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
688 // Convert date/time string to Date object
689 var date = parseDate(entryDate);
690 log('date: ' + date);
691 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
692 log('endDate: ' + endDate);
694 // check if meeting event has already passed
695 if (entry.Type == 'Meeting') {
696 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
697 if (now.getTime()
> compareTime) {
698 log('skipping Meeting (already passed) ' + entry.id);
700 eventIds[entry.id] =
0;
705 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
706 if (entry.Type == 'Anniversary') {
707 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
708 if (date.getTime() < tmp.getTime()) {
709 log('skipping Anniversary (already passed) ' + entry.id);
711 eventIds[entry.id] =
0;
716 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
717 if (entry.Type == 'DayEvent' && endDate != null) {
718 endDate.setMinutes(endDate.getMinutes() -
1);
719 log('fixing DayEvent endDate: ' + endDate);
720 if (now.getTime()
> endDate.getTime()) {
721 log('event already passed ' + entry.id);
723 eventIds[entry.id] =
0;
728 // check if the event is currently taking place
729 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
730 // check if we are between start and endtime
731 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
732 date = now; // change appointment date/time to now
733 log('event is currently taking place: ' + date);
737 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
738 if (mode ==
0 && panelNum
> 0 && counter < panelNum * config['eventsPerWidget'].Value +
1) {
739 log('skipping (already in first widget) ' + entry.id);
743 // mark overdue todos
745 if (entry.Type == 'ToDo' && date != null) {
746 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
0,
0,
0);
747 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
748 if (tmp1.getTime() < tmp2.getTime()) {
753 // generate html output
754 entriesHtml += '
<tr>';
755 if (config['showCalendarIndicator'].Value && calendarList.length - config['excludedCalendars'].Value.length
> 1) {
756 entriesHtml += '
<td><span class=
"calendar' + calendarColors[entry.CalendarName] + '"> </span></td>';
758 entriesHtml += '
<td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
760 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
761 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
763 var weekDay = date.toLocaleDateString().substr(
0,config['weekDayLength'].Value);
764 var time = formatTime(date);
765 var dateStr = formatDate(date, entryDate);
766 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
767 dateStr = '
<span class=
"overdue">' + config['overdueText'].Value + '
</span>';
768 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
769 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
770 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
771 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
773 entriesHtml += '
<td class=
"weekDay" width=
"1px">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
774 } else if (entry.Type == 'Meeting') {
775 if (config['showCombinedDateTime'].Value) {
777 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
778 else if (isTomorrow(date))
779 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
781 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
783 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
784 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
786 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
790 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
793 entriesHtml += '
</table>';
794 if (config['showNothingText'].Value && entriesHtml == '
<table></table>') {
795 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
796 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '
</div>';
798 if (cacheEntriesHtml != entriesHtml) {
800 document.getElementById('calendarList').innerHTML = entriesHtml;
802 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
803 cacheEntriesHtml = entriesHtml;
806 lastUpdateTime = new Date();
808 error('displaying list:' + e + ', line ' + e.line);
813 // called by handleOnShow() and onResize events
814 function updateScreen()
816 log('updateScreen()');
818 // check if opening fullscreen
819 if( window.innerHeight
> 91 && mode ==
0) {
821 cacheEntriesHtml = '';
822 document.getElementById('body').style.backgroundImage =
"";
825 else if (window.innerHeight <=
91 && mode !=
0) {
827 cacheEntriesHtml = '';
832 updateHomescreen(); // check for screen rotation
837 function handleOnShow()
841 var time = new Date();
842 if (time.getTime() - lastUpdateTime.getTime()
> config['updateDataInterval'].Value *
60 *
1000) {
843 log('updateScreen(): force updateData() because last update was too long ago (' + (time.getTime() - lastUpdateTime.getTime()) /
1000 + 's)');
846 setUpdateTimer(); // reinitialize update timer
850 function launchCalendar()
853 widget.openApplication(config['calendarApp'].Value,
"");
854 if (config['hideWidgetOnCalendarOpen'].Value)
857 error('starting Calendar App');
864 log('New widget instance starting up...');
867 // call calendar service
868 if (device !=
"undefined")
869 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
871 throw('device object does not exist');
873 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>');
877 calendarList = listCalendars();
879 updateCalendarColors();
882 requestNotification();
883 document.getElementById(
"settingsTitle").innerHTML = getLocalizedText('menu.settings');
885 if (window.innerHeight
> 91) {
886 mode =
0; // we're starting fullscreen, we set mode to homescreen in order to let updateScreen() do all the work for us
891 log(
"init(): updateScreen()");
893 if (config['useBackgroundImage'].Value)
894 // check for screen rotation every
1 secs
895 screenRotationTimer = window.setInterval('checkOrientation()',
1000 *
1);
897 // call updateScreen() when widget changes from background to forground
898 window.widget.onshow = handleOnShow;
900 log(
"init(): finished...");
903 function checkOrientation()
907 updateHomescreen(); // check for screen rotation
910 function setUpdateTimer()
912 updateTimer = window.setInterval('updateTimerCallback()',
1000 *
60 * config['updateDataInterval'].Value);
915 function clearUpdateTimer()
917 window.clearInterval(updateTimer);
920 function updateTimerCallback()
922 log(
"updateTimerCallback()");
926 function createMenu()
928 window.menu.setLeftSoftkeyLabel(
"",null);
929 window.menu.setRightSoftkeyLabel(
"",null);
931 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
932 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
933 var menuHelp = new MenuItem(getLocalizedText('menu.help'), id++);
934 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
935 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
936 menuSettings.onSelect = showSettings;
937 menuAbout.onSelect = showAbout;
938 menuCallApp.onSelect = launchCalendar;
939 menuUpdate.onSelect = showUpdate;
940 menuHelp.onSelect = showHelp;
942 window.menu.append(menuCallApp);
943 window.menu.append(menuSettings);
944 window.menu.append(menuHelp);
945 window.menu.append(menuUpdate);
946 window.menu.append(menuAbout);
949 function showSettings()
953 document.getElementById(
"settingsView").style.display =
"block";
954 document.onclick = null;
956 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
958 for (var key in config) {
959 if (config[key].Type == 'String')
960 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
961 else if (config[key].Type == 'Int') {
962 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
963 if (config[key].Value <
0 || isNaN(config[key].Value))
964 config[key].Value = config[key].Default;
966 else if (config[key].Type == 'Bool')
967 config[key].Value = document.forms[
0].elements[
"settings." + key].checked;
968 else if (config[key].Type == 'UID') {
969 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
970 if (isNaN(config[key].Value))
971 config[key].Value = config[key].Default;
973 else if (config[key].Type == 'Enum') {
974 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
975 if (config[key].ValidValues.indexOf(config[key].Value) == -
1)
976 config[key].Value = config[key].Default;
978 else if (config[key].Type == 'Array') {
979 if (key == 'excludedCalendars') {
980 config[key].Value = new Array();
981 for(var i=
0; i < calendarList.length; i++) {
982 var element = document.forms[
0].elements[
"settings." + key +
"." + calendarList[i]];
983 if (element != null && element.checked == false)
984 config[key].Value.push(calendarList[i]);
997 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
1003 var settingsHtml = '
<form>';
1004 for (var key in config) {
1005 if (config[key].Type == 'String') {
1007 if (key.substring(
0,
9) ==
"cssStyle_")
1008 prefix = getLocalizedText('settings.cssStyle_prefix');
1009 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 />';
1011 else if (config[key].Type == 'Int')
1012 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 />';
1013 else if (config[key].Type == 'Bool')
1014 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 />';
1015 else if (config[key].Type == 'UID')
1016 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 />';
1017 else if (config[key].Type == 'Enum') {
1018 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><select name=
"settings.' + key + '" size=
"1">';
1019 for(var i =
0; i < config[key].ValidValues.length; i++)
1020 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>';
1021 settingsHtml += '
</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1023 else if (config[key].Type == 'Array') {
1024 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br />';
1025 if (key == 'excludedCalendars') {
1026 for(var i=
0; i < calendarList.length; i++) {
1027 var checked = '
checked=
"checked"';
1028 if (config[key].Value.indexOf(calendarList[i]) != -
1)
1030 settingsHtml += '
<input name=
"settings.' + key + '.' + calendarList[i] + '" type=
"checkbox" value=
"' + calendarList[i] + '" ' + checked + '
/> ' + calendarList[i] + '
<br />';
1033 settingsHtml += '
</td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1036 settingsHtml += '
<input name=
"reset" type=
"button" value=
"' + getLocalizedText('settings.restoreDefaults') + '" onclick=
"javascript:restoreDefaultSettings();showSettings();" />';
1037 settingsHtml += '
</form>';
1038 document.getElementById(
"settingsList").innerHTML = settingsHtml;
1041 function changeCssClass(classname, properties)
1043 for(var i =
0; i < document.styleSheets[
0]['cssRules'].length; i++)
1045 if (document.styleSheets[
0]['cssRules'][i].selectorText == classname) {
1046 document.styleSheets[
0].deleteRule(i);
1047 document.styleSheets[
0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[
0]['cssRules'].length);
1053 function updateCssClasses()
1055 for(var key in config) {
1056 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
1060 function getSettingsCalEntryId()
1062 if (settingsCalEntryId == null) {
1063 // check if entry already exists
1064 var listFiltering = {
1065 Type:'CalendarEntry',
1067 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!
1068 EndRange: new Date(
2000,
0,
2),
1069 SearchText: 'ComingNext Settings|',
1073 var result = calendarService.IDataSource.GetList(listFiltering);
1074 if (result.ErrorCode) {
1075 error(result.ErrorMessage);
1078 var list = result.ReturnValue;
1079 var entry = list.getNext();
1080 if (entry != undefined) {
1081 settingsCalEntryId = entry.LocalId;
1082 log(
"settingsCalEntryId=" + settingsCalEntryId);
1084 else { // create settings item
1085 var item = new Object();
1086 item.Type =
"DayEvent";
1087 item.StartTime = new Date(
2000,
0,
1);
1088 item.Summary =
"ComingNext Settings|";
1090 var criteria = new Object();
1091 criteria.Type =
"CalendarEntry";
1092 criteria.Item = item;
1095 var result = calendarService.IDataSource.Add(criteria);
1096 if (result.ErrorCode)
1097 error(result.ErrorMessage);
1099 error(
"getSettingsCalEntryId: " + e + ', line ' + e.line);
1102 getSettingsCalEntryId();
1107 function restoreDefaultSettings()
1109 for (var key in config)
1110 config[key].Value = config[key].Default;
1113 function loadSettings()
1115 getSettingsCalEntryId();
1116 var listFiltering = {
1117 Type:'CalendarEntry',
1119 LocalId: settingsCalEntryId
1122 var result = calendarService.IDataSource.GetList(listFiltering);
1123 if (result.ErrorCode) {
1124 error(result.ErrorMessage);
1127 var entry = result.ReturnValue.getNext();
1128 if (entry != undefined) {
1129 log(
"Loading Settings...");
1130 // only reload settings if they chanced since the last reload
1131 if (settingsCache != entry.Summary)
1133 restoreDefaultSettings();
1134 var stringlist = entry.Summary.split(
"|");
1135 // skip the first two entries, those contain header and version info
1136 for(var i =
2; i < stringlist.length -
1; i++) {
1137 var pair = stringlist[i].split('=');
1139 var value = pair[
1];
1140 if (key == null || value == null || config[key] == null) {
1141 log('Warning: unknown or invalid setting: ' + stringlist[i]);
1144 log('stringlist: ' + key + '=\'' + value + '\'');
1145 if (config[key].Type == 'Int') {
1146 config[key].Value = Number(value);
1147 if (isNaN(config[key].Value))
1148 config[key].Value = config[key].Default;
1150 else if (config[key].Type == 'String')
1151 config[key].Value = value;
1152 else if (config[key].Type == 'Bool')
1153 config[key].Value = (value == 'true')
1154 else if (config[key].Type == 'Enum')
1155 config[key].Value = value;
1156 else if (config[key].Type == 'UID') {
1157 config[key].Value = Number(value);
1158 if (isNaN(config[key].Value))
1159 config[key].Value = config[key].Default;
1161 else if (config[key].Type == 'Array') {
1162 config[key].Value = value.split(
"^");
1163 if (config[key].Value.length ==
1 && config[key].Value[
0] ==
"") {
1164 config[key].Value = [];
1168 settingsCache = entry.Summary;
1172 log(
"Settings already cached and did not change");
1176 error(
"Failed to load settings, calendar entry could not be found");
1180 function saveSettings()
1182 getSettingsCalEntryId();
1183 var item = new Object();
1184 item.Type =
"DayEvent";
1185 item.StartTime = new Date(
2000,
0,
1);
1186 item.LocalId = settingsCalEntryId;
1187 item.Summary =
"ComingNext Settings|" + version +
"|";
1189 for (var key in config) {
1190 if (config[key].Type == 'Int')
1191 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1192 else if (config[key].Type == 'String')
1193 item.Summary += key +
"=" + config[key].Value +
"|";
1194 else if (config[key].Type == 'Bool')
1195 item.Summary += key +
"=" + (config[key].Value ? 'true' : 'false') +
"|";
1196 else if (config[key].Type == 'Enum')
1197 item.Summary += key +
"=" + config[key].Value +
"|";
1198 else if (config[key].Type == 'UID')
1199 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1200 else if (config[key].Type == 'Array')
1201 item.Summary += key +
"=" + config[key].Value.join(
"^") +
"|";
1203 settingsCache = item.Summary;
1205 var criteria = new Object();
1206 criteria.Type =
"CalendarEntry";
1207 criteria.Item = item;
1209 log(
"Saving settings to calendar entry: " + item.Summary);
1211 var result = calendarService.IDataSource.Add(criteria);
1212 if (result.ErrorCode)
1213 error(result.ErrorMessage);
1215 error(
"saveSettings: " + e + ', line ' + e.line);
1218 lastReloadTime = null; // force calendar data reload on next update
1223 function toggleVisibility(elementId)
1225 if (document.getElementById(elementId).style.display ==
"none")
1226 document.getElementById(elementId).style.display =
"block";
1228 document.getElementById(elementId).style.display =
"none";
1232 function printHintBox(text)
1235 return '
<td width=
"1%" align=
"right" onclick=
"javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '
</td></tr></table>'+
1236 '
<div class=
"settingsInfo" id=
"info' + uniqueId + '">' + text + '
</div>';
1239 function showAbout()
1243 document.getElementById(
"aboutView").style.display =
"block";
1244 document.onclick = null;
1246 window.menu.setLeftSoftkeyLabel(
" ", function(){});
1247 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1253 //document.getElementById(
"aboutView").innerHTML = 'aboutView';
1254 document.getElementById(
"name").innerHTML =
"Coming Next " + version;
1257 function showHelp() {
1258 widget.openURL('http://comingnext.sf.net/help');
1261 function updateFullscreen()
1265 function showFullscreen()
1267 log(
"showFullscreen()");
1269 document.getElementById(
"fullscreenView").style.display =
"block";
1270 document.getElementById('body').className =
"backgroundFullscreen";
1272 document.onclick = launchCalendar;
1277 function getBackgroundImage()
1282 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[
0]) // internal
1283 bgImage = 'background_' + orientation + '.png';
1285 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
1289 function updateHomescreen()
1291 if (config['useBackgroundImage'].Value) {
1292 // check if we have a completely unknown screen resolution
1293 var screenHeight = screen.height;
1294 var screenWidth = screen.width;
1295 if (screenHeight !=
640 && screenHeight !=
480 && screenHeight !=
360)
1296 screenHeight =
360; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1297 if (screenWidth !=
640 && screenWidth !=
480 && screenWidth !=
360)
1298 screenWidth =
640; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code
1300 // check for screen rotation
1301 if (orientation != 'portrait' && ((screenWidth ==
360 && screenHeight ==
640) || (screenWidth ==
640 && screenHeight ==
480))) {
1302 window.widget.prepareForTransition(
"fade");
1303 orientation = 'portrait';
1304 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1305 document.getElementById('body').style.backgroundColor = 'none';
1306 window.widget.performTransition();
1307 } else if (orientation != 'landscape' && ((screenWidth ==
640 && screenHeight ==
360) || (screenWidth ==
480 && screenHeight ==
640))) {
1308 window.widget.prepareForTransition(
"fade");
1309 orientation = 'landscape';
1310 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1311 document.getElementById('body').style.backgroundColor = 'none';
1312 window.widget.performTransition();
1314 else if (document.getElementById('body').style.backgroundImage ==
"")
1316 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1321 function showHomescreen()
1323 log(
"showHomescreen()");
1325 document.getElementById(
"homescreenView").style.display =
"block";
1326 document.getElementById('body').className =
"background";
1327 document.onclick = null;
1331 function getLocalizedText(p_Txt)
1333 if (localizedText[p_Txt])
1334 return localizedText[p_Txt];
1336 return 'ERROR: missing translation for ' + p_Txt;
1339 function showUpdate()
1343 document.getElementById(
"updateView").style.display =
"block";
1344 document.onclick = null;
1346 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1349 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1355 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
1359 function checkForUpdate()
1361 // asynch XHR to server url
1362 reqV = new XMLHttpRequest();
1363 reqV.onreadystatechange = checkForUpdateCallback;
1364 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
1365 reqV.open(
"GET", versionURL, true);
1366 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1370 function checkForUpdateCallback()
1372 if (reqV.readyState ==
4) {
1373 if (reqV.status ==
200) {
1374 var resultXml = reqV.responseText;
1376 var div = document.getElementById(
"tmp");
1377 div.innerHTML = resultXml;
1378 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
1379 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
1381 if (version != newVersion) {
1382 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1385 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1390 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1395 function hideViews()
1397 document.getElementById(
"homescreenView").style.display =
"none";
1398 document.getElementById(
"fullscreenView").style.display =
"none";
1399 document.getElementById(
"aboutView").style.display =
"none";
1400 document.getElementById(
"settingsView").style.display =
"none";
1401 document.getElementById(
"updateView").style.display =
"none";
1404 function listCalendars()
1414 DefaultCalendar: false
1418 var calendarsResult = calendarService.IDataSource.GetList(criteria);
1419 if (calendarsResult.ErrorCode !=
0)
1420 throw(
"Error fetching list of calendars: " + calendarsResult.ErrorCode + ': ' + calendarsResult.ErrorMessage);
1421 var calendarListIterator = calendarsResult.ReturnValue;
1426 while (( item = calendarListIterator.getNext()) != undefined ) {
1427 calendars[count++] = item;
1429 log(
"Available Calendars: " + calendars.join(
", "));
1432 error('listing calendars:' + e + ', line ' + e.line);
1437 // Copies all objects and their properties to an array. Data is copied so nothing gets lost when the reference is removed
1438 // 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
1439 function listToArray(list, calendarName)
1441 var array = new Array();
1444 while (( item = list.getNext()) != undefined ) {
1445 var itemCopy = new Object();
1446 for(var i=
0; i < entryFields.length; i++) {
1447 itemCopy[entryFields[i]] = item[entryFields[i]];
1449 // for some reason, the CalendarName property is never correctly queried, so we assign it manually here
1450 if (!itemCopy['CalendarName']) {
1451 itemCopy['CalendarName'] = calendarName;
1453 array.push(itemCopy);
1454 txt += array[array.length -
1].Summary +
", ";
1456 log(
"listToArray(): " + txt);
1460 function sortCalendarEntries(a, b)
1463 log(
"sortCalendarEntries(" + a.Summary +
"," + b.Summary +
")");
1465 if (a.InstanceStartTime != null) {
1466 atime = a.InstanceStartTime;
1468 else if (a.StartTime != null) {
1469 atime = a.StartTime;
1471 else if (a.InstanceEndTime != null) {
1472 atime = a.InstanceEndTime;
1474 else if (a.EndTime != null) {
1478 if (b.InstanceStartTime != null) {
1479 btime = b.InstanceStartTime;
1481 else if (b.StartTime != null) {
1482 btime = b.StartTime;
1484 else if (b.InstanceEndTime != null) {
1485 btime = b.InstanceEndTime;
1487 else if (b.EndTime != null) {
1491 if (atime && btime) {
1493 atime = parseDate(atime);
1494 btime = parseDate(btime);
1496 // sort by date & time
1497 if (atime < btime) {
1500 else if (atime
> btime) {
1504 else if (a.Type != b.Type) {
1505 if (a.Type < b.Type) {
1508 else if (a.Type
> b.Type) {
1512 // sort by description
1513 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1514 if (a.Summary < b.Summary) {
1517 else if (a.Summary
> b.Summary) {
1522 // NOTE: events my have no date information at all. In that case, we list events without date first
1523 else if (atime && !btime) {
1526 else if (!atime && btime) {
1529 else if (!atime && !btime) {
1531 if (a.Type != b.Type) {
1532 if (a.Type < b.Type) {
1535 else if (a.Type
> b.Type) {
1539 // sort by description
1540 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1541 if (a.Summary < b.Summary) {
1544 else if (a.Summary
> b.Summary) {
1553 function updateCalendarColors()
1556 calendarColors = [];
1557 if (calendarList.length
> maxColors) {
1558 log(
"updateCalendarColors(): Warning: more calendars than available indicator colors");
1560 for(var i=
0; i < calendarList.length; i++) {
1561 calendarColors[calendarList[i]] = (i % maxColors) +
1;
1565 function log(message)
1567 if (config['enableLogging'].Value) {
1568 console.info(message);
1574 <style type=
"text/css">
1576 table { margin:
0px; padding:
0px; border-spacing:
0px; }
1577 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
1578 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1579 .settingsInfo { display:none; font-style:italic; }
1580 .title { font-weight:bold; font-size:
14pt; }
1581 .textInput { width:
90%; }
1582 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1583 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
1584 #calendarList { position:absolute; left:
5px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
1585 #name { text-align:center; }
1586 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1587 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1592 <body onload=
"javascript:setTimeout('init()', 10)" onresize=
"javascript:updateScreen()" id=
"body" class=
"background">
1593 <div id=
"homescreenView">
1594 <div id=
"calendarList">loading...
</div>
1596 <div id=
"fullscreenView" style=
"display:none;">
1597 <img src=
"Icon.png" id=
"smallappicon">
1598 <h1 class=
"title">Coming Next
</h1>
1600 <div id=
"fullscreenCalendarList">loading...
</div>
1602 <div id=
"settingsView" style=
"display:none">
1603 <img src=
"Icon.png" id=
"smallappicon">
1604 <h1 id=
"settingsTitle" class=
"title">Settings
</h1>
1606 <div id=
"settingsList"></div>
1608 <div id=
"aboutView" style=
"display:none">
1609 <img src=
"Icon.png" id=
"appicon">
1610 <h1 id=
"name">Coming Next
</h1>
1612 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1613 <p>Contributions:
</p>
1614 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1615 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1616 <p class=
"credits">Christophe Milsent (translation support & french translation)
</p>
1617 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation)
</p>
1618 <p class=
"credits">Tokeda (russian translation)
</p>
1619 <p class=
"credits">Marcella Ferrari (italian translation)
</p>
1620 <p class=
"credits">Venos (italian translation)
</p>
1621 <p>This software is open source and licensed under the GPLv3.
</p>
1622 <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>
1625 <div id=
"updateView" style=
"display:none">
1626 <img src=
"Icon.png" id=
"smallappicon">
1627 <h1 class=
"title">Check for update
</h1>
1629 <div id=
"currentVersion">Coming Next ??
</div>
1630 <div id=
"updateDiv"></div>
1631 <div id=
"tmp" style=
"display:none;"></div>