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 for screen rotation
1293 if (orientation != 'portrait' && screen.width ==
360 && screen.height ==
640) {
1294 window.widget.prepareForTransition(
"fade");
1295 orientation = 'portrait';
1296 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1297 document.getElementById('body').style.backgroundColor = 'none';
1298 window.widget.performTransition();
1299 } else if (orientation != 'landscape' && screen.width ==
640 && screen.height ==
360) {
1300 window.widget.prepareForTransition(
"fade");
1301 orientation = 'landscape';
1302 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1303 document.getElementById('body').style.backgroundColor = 'none';
1304 window.widget.performTransition();
1306 else if (document.getElementById('body').style.backgroundImage ==
"")
1308 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1313 function showHomescreen()
1315 log(
"showHomescreen()");
1317 document.getElementById(
"homescreenView").style.display =
"block";
1318 document.getElementById('body').className =
"background";
1319 document.onclick = null;
1323 function getLocalizedText(p_Txt)
1325 if (localizedText[p_Txt])
1326 return localizedText[p_Txt];
1328 return 'ERROR: missing translation for ' + p_Txt;
1331 function showUpdate()
1335 document.getElementById(
"updateView").style.display =
"block";
1336 document.onclick = null;
1338 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1341 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1347 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
1351 function checkForUpdate()
1353 // asynch XHR to server url
1354 reqV = new XMLHttpRequest();
1355 reqV.onreadystatechange = checkForUpdateCallback;
1356 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
1357 reqV.open(
"GET", versionURL, true);
1358 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1362 function checkForUpdateCallback()
1364 if (reqV.readyState ==
4) {
1365 if (reqV.status ==
200) {
1366 var resultXml = reqV.responseText;
1368 var div = document.getElementById(
"tmp");
1369 div.innerHTML = resultXml;
1370 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
1371 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
1373 if (version != newVersion) {
1374 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1377 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1382 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1387 function hideViews()
1389 document.getElementById(
"homescreenView").style.display =
"none";
1390 document.getElementById(
"fullscreenView").style.display =
"none";
1391 document.getElementById(
"aboutView").style.display =
"none";
1392 document.getElementById(
"settingsView").style.display =
"none";
1393 document.getElementById(
"updateView").style.display =
"none";
1396 function listCalendars()
1406 DefaultCalendar: false
1410 var calendarsResult = calendarService.IDataSource.GetList(criteria);
1411 if (calendarsResult.ErrorCode !=
0)
1412 throw(
"Error fetching list of calendars: " + calendarsResult.ErrorCode + ': ' + calendarsResult.ErrorMessage);
1413 var calendarListIterator = calendarsResult.ReturnValue;
1418 while (( item = calendarListIterator.getNext()) != undefined ) {
1419 calendars[count++] = item;
1421 log(
"Available Calendars: " + calendars.join(
", "));
1424 error('listing calendars:' + e + ', line ' + e.line);
1429 // Copies all objects and their properties to an array. Data is copied so nothing gets lost when the reference is removed
1430 // 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
1431 function listToArray(list, calendarName)
1433 var array = new Array();
1436 while (( item = list.getNext()) != undefined ) {
1437 var itemCopy = new Object();
1438 for(var i=
0; i < entryFields.length; i++) {
1439 itemCopy[entryFields[i]] = item[entryFields[i]];
1441 // for some reason, the CalendarName property is never correctly queried, so we assign it manually here
1442 if (!itemCopy['CalendarName']) {
1443 itemCopy['CalendarName'] = calendarName;
1445 array.push(itemCopy);
1446 txt += array[array.length -
1].Summary +
", ";
1448 log(
"listToArray(): " + txt);
1452 function sortCalendarEntries(a, b)
1455 log(
"sortCalendarEntries(" + a.Summary +
"," + b.Summary +
")");
1457 if (a.InstanceStartTime != null) {
1458 atime = a.InstanceStartTime;
1460 else if (a.StartTime != null) {
1461 atime = a.StartTime;
1463 else if (a.InstanceEndTime != null) {
1464 atime = a.InstanceEndTime;
1466 else if (a.EndTime != null) {
1470 if (b.InstanceStartTime != null) {
1471 btime = b.InstanceStartTime;
1473 else if (b.StartTime != null) {
1474 btime = b.StartTime;
1476 else if (b.InstanceEndTime != null) {
1477 btime = b.InstanceEndTime;
1479 else if (b.EndTime != null) {
1483 if (atime && btime) {
1485 atime = parseDate(atime);
1486 btime = parseDate(btime);
1488 // sort by date & time
1489 if (atime < btime) {
1492 else if (atime
> btime) {
1496 else if (a.Type != b.Type) {
1497 if (a.Type < b.Type) {
1500 else if (a.Type
> b.Type) {
1504 // sort by description
1505 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1506 if (a.Summary < b.Summary) {
1509 else if (a.Summary
> b.Summary) {
1514 // NOTE: events my have no date information at all. In that case, we list events without date first
1515 else if (atime && !btime) {
1518 else if (!atime && btime) {
1521 else if (!atime && !btime) {
1523 if (a.Type != b.Type) {
1524 if (a.Type < b.Type) {
1527 else if (a.Type
> b.Type) {
1531 // sort by description
1532 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1533 if (a.Summary < b.Summary) {
1536 else if (a.Summary
> b.Summary) {
1545 function updateCalendarColors()
1548 calendarColors = [];
1549 if (calendarList.length
> maxColors) {
1550 log(
"updateCalendarColors(): Warning: more calendars than available indicator colors");
1552 for(var i=
0; i < calendarList.length; i++) {
1553 calendarColors[calendarList[i]] = (i % maxColors) +
1;
1557 function log(message)
1559 if (config['enableLogging'].Value) {
1560 console.info(message);
1566 <style type=
"text/css">
1568 table { margin:
0px; padding:
0px; border-spacing:
0px; }
1569 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
1570 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1571 .settingsInfo { display:none; font-style:italic; }
1572 .title { font-weight:bold; font-size:
14pt; }
1573 .textInput { width:
90%; }
1574 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1575 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
1576 #calendarList { position:absolute; left:
5px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
1577 #name { text-align:center; }
1578 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1579 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1584 <body onload=
"javascript:setTimeout('init()', 10)" onresize=
"javascript:updateScreen()" id=
"body" class=
"background">
1585 <div id=
"homescreenView">
1586 <div id=
"calendarList">loading...
</div>
1588 <div id=
"fullscreenView" style=
"display:none;">
1589 <img src=
"Icon.png" id=
"smallappicon">
1590 <h1 class=
"title">Coming Next
</h1>
1592 <div id=
"fullscreenCalendarList">loading...
</div>
1594 <div id=
"settingsView" style=
"display:none">
1595 <img src=
"Icon.png" id=
"smallappicon">
1596 <h1 id=
"settingsTitle" class=
"title">Settings
</h1>
1598 <div id=
"settingsList"></div>
1600 <div id=
"aboutView" style=
"display:none">
1601 <img src=
"Icon.png" id=
"appicon">
1602 <h1 id=
"name">Coming Next
</h1>
1604 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1605 <p>Contributions:
</p>
1606 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1607 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1608 <p class=
"credits">Christophe Milsent (translation support & french translation)
</p>
1609 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation)
</p>
1610 <p class=
"credits">Tokeda (russian translation)
</p>
1611 <p class=
"credits">Marcella Ferrari (italian translation)
</p>
1612 <p class=
"credits">Venos (italian translation)
</p>
1613 <p>This software is open source and licensed under the GPLv3.
</p>
1614 <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>
1617 <div id=
"updateView" style=
"display:none">
1618 <img src=
"Icon.png" id=
"smallappicon">
1619 <h1 class=
"title">Check for update
</h1>
1621 <div id=
"currentVersion">Coming Next ??
</div>
1622 <div id=
"updateDiv"></div>
1623 <div id=
"tmp" style=
"display:none;"></div>