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 error(result.ErrorMessage);
265 var list = result.ReturnValue;
267 error(e + ', line ' + e.line);
270 var ids = new Array();
276 while (list && (entry = list.getNext()) != undefined) {
277 dateArr = entry.StartTime.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
278 var day = dateArr[
1];
279 var month = dateArr[
2];
280 var year = dateArr[
3];
282 // make sure month is set properly
283 if (isNaN(parseInt(day))) {
287 } else if (isNaN(parseInt(year))) {
293 log(entry.StartTime + ' -
> ' + month + ' ' + counter);
294 ids[counter] = entry.id;
295 months_translated[month] = counter +
1;
299 error(e + ', line ' + e.line);
304 var criteria = new Object();
305 criteria.Type =
"CalendarEntry";
310 var result = calendarService.IDataSource.Delete(criteria);
311 if (result.ErrorCode)
312 error(result.ErrorMessage);
314 error('deleting temp calendar entries:' + e + ', line ' + e.line);
319 function requestNotification()
321 var criteria = new Object();
322 criteria.Type =
"CalendarEntry";
323 criteria.Filter = new Object();
324 for(var i=
0; i < calendarList.length; i++) {
325 criteria.Filter.CalendarName = calendarList[i];
327 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria, callback);
328 if (notificationRequest.ErrorCode)
329 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
330 notificationRequests.push(notificationRequest);
332 error(
"requestNotification: " + e + ', line ' + e.line);
336 var criteria2 = new Object();
337 criteria2.Type =
"CalendarEntry";
338 criteria2.Filter = new Object();
339 criteria2.Filter.LocalIdList = new Array();
340 criteria2.Filter.LocalIdList[
0] = settingsCalEntryId;
342 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria2, settingsCallback);
343 if (notificationRequest.ErrorCode)
344 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
345 notificationRequests.push(notificationRequest);
347 error(
"requestNotification: " + e + ', line ' + e.line);
351 function cancelNotification()
353 for(var i=
0; i < notificationRequests.length; i++) {
355 var result = calendarService.IDataSource.Cancel(notificationRequests[i]);
356 if (result.ErrorCode)
357 error('cancelNotification failed with error code ' + result.ErrorCode);
359 error(
"cancelNotification: " + e + ', line ' + e.line);
364 function callback(transId, eventCode, result)
366 log(
"callback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
367 lastReloadTime = null; // force calendar data reload on next update
371 function settingsCallback(transId, eventCode, result)
373 log(
"settingsCallback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
377 function parseDate(dateString)
380 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:
381 Wednesday,
26 August,
2009 24:
00:
00
382 Wednesday,
26 August,
2009 12:
00:
00 am
383 Wednesday, August
26,
2009 12:
00:
00 am
384 Wednesday,
2009 August,
26 12:
00:
00 am
385 Wednesday,
2009 August,
28 8.00.00 pm
386 Wednesday,
2009 August,
28 08:
00:
00 PM
389 if (dateString ==
"" || dateString == null)
391 var dateArr = dateString.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
392 if (dateArr.length !=
5 && dateArr.length !=
6)
396 var weekDay = dateArr[
0];
397 var day = dateArr[
1];
398 var month = dateArr[
2];
399 var year = dateArr[
3];
400 // make sure month is set properly
401 if (isNaN(parseInt(day))) {
405 } else if (isNaN(parseInt(year))) {
410 // make sure day and year are set properly
411 if (Number(day)
> Number(year)) {
416 month = months_translated[month];
419 var timeArr = dateArr[
4].split(':');
420 if (timeArr.length !=
3)
422 var hours = Number(timeArr[
0]);
423 var minutes = Number(timeArr[
1]);
424 var seconds = Number(timeArr[
2]);
425 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'pm' && hours <
12)
427 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'am' && hours ==
12)
430 var result = new Date(year, month -
1, day, hours, minutes, seconds);
432 // take care of daylight saving time
433 if (config['enableDaylightSaving'].Value) {
435 // determine if date is in summer or winter time
436 var dateSummerTime = isSummertime(result);
438 // work around bug in Nokias calendar api resulting in dates within a different DST to be off by
1 hour
439 if (summertime && !dateSummerTime) {
440 result = new Date(result.getTime() -
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // -
1 hour
441 log('parseDate(): fixing time -
1h: ' + result);
443 else if (!summertime && dateSummerTime) {
444 result = new Date(result.getTime() +
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // +
1 hour
445 log('parseDate(): fixing time +
1h: ' + result);
452 // 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"
453 function formatDate(date, format)
455 var day = date.getDate().toString();
456 var month = (date.getMonth() +
1).toString();
457 while (day.length <
2) { day = '
0' + day; }
458 while (month.length <
2) { month = '
0' + month; }
460 if (config['showTodayAsText'].Value && isToday(date))
461 return '
<span class=
"today">' + config['todayText'].Value + '
</span>';
462 if (config['showTodayAsText'].Value && isTomorrow(date))
463 return '
<span class=
"tomorrow">' + config['tomorrowText'].Value + '
</span>';
465 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
466 if (dateArr.length !=
5 && dateArr.length !=
6) {
467 // we don't know how to format this
468 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
469 return day + config['dateSeparator'].Value + month;
471 return month + config['dateSeparator'].Value + day;
475 if (config['dateFormat'].Value == 'MMDD')
477 else if (config['dateFormat'].Value == 'DDMM')
480 // config['dateFormat'].Value == 'auto', try to detect system setting
482 var day_ = dateArr[
1];
483 var month_ = dateArr[
2];
484 var year_ = dateArr[
3];
485 // make sure month is set properly
486 if (isNaN(parseInt(day_))) {
491 } else if (isNaN(parseInt(year_))) {
497 // make sure day and year are set properly
498 if (Number(day_)
> Number(year_))
503 return day + config['dateSeparator'].Value + month;
505 return month + config['dateSeparator'].Value + day;
508 function formatTime(date)
510 // date is a Date() object
511 date.setSeconds(
0); // we don't care about seconds
512 var time = date.toLocaleTimeString().replace(/[\.:]
00/, ''); // remove seconds from string
513 if (time.replace(/\./, ':').split(':')[
0].length <
2)
515 if (config['showNowAsText'].Value && date.getTime() == now.getTime())
516 time = '
<span class=
"now">' + config['nowText'].Value + '
</span>';
520 function updateData()
527 // check if we got additional or less calendars since our last update
528 var newCalendarList = listCalendars();
529 if (newCalendarList.length != calendarList.length) {
530 calendarList = newCalendarList;
531 updateCalendarColors();
532 cancelNotification();
533 requestNotification();
534 lastReloadTime = null; // force calendar data reload on this update
539 // only reload calendar data every
6 hours, visual updates occure more often
540 if (!lastReloadTime || now.getTime() - lastReloadTime.getTime()
> reloadInterval) {
541 log('updateData(): reloading calendar data');
543 // meetings have time
544 // 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
545 summertime = isSummertime(now); // cache summer time info for today
546 var meetingList = [];
547 for(var i=
0; i < calendarList.length; i++) {
548 // ignore excluded calendars
549 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
551 var meetingListFiltering = {
552 Type:'CalendarEntry',
554 CalendarName: calendarList[i],
555 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
556 EndRange: (new Date(now.getFullYear(), now.getMonth() + config['monthRange'].Value, now.getDate(),
0,
0,
0))
559 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
560 if (meetingResult.ErrorCode !=
0)
561 throw(
"Error fetching calendar data: " + meetingResult.ErrorCode + ': ' + meetingResult.ErrorMessage);
562 var list = meetingResult.ReturnValue;
563 meetingList = meetingList.concat(listToArray(list, calendarList[i]));
565 log(
"updateData(): meetingList.sort()");
566 meetingList.sort(sortCalendarEntries);
568 // todos don't, they start on
00:
00 hrs., but should be visible anyway
569 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
570 if (config['includeTodos'].Value) {
571 var todayTodoList = [];
572 for(var i=
0; i < calendarList.length; i++) {
573 // ignore excluded calendars
574 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
576 var todayTodoListFiltering = {
577 Type:'CalendarEntry',
579 CalendarName: calendarList[i],
581 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
582 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
585 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
586 var list = todayTodoResult.ReturnValue;
587 todayTodoList = todayTodoList.concat(listToArray(list, calendarList[i]));
589 log(
"updateData(): todayTodoList.sort()");
590 todayTodoList.sort(sortCalendarEntries);
591 entryLists = [todayTodoList, meetingList];
593 entryLists = [meetingList];
595 lastReloadTime = new Date();
597 error('loading Calendar items list:' + e + ', line ' + e.line);
607 var fontsize = 'normal';
609 if (config['eventsPerWidget'].Value ==
3) {
611 changeCssClass('.icon', 'width:
20px; height:
20px');
613 else if (config['eventsPerWidget'].Value ==
5) {
615 changeCssClass('.icon', 'width:
10px; height:
10px');
617 else if (config['eventsPerWidget'].Value ==
6) {
619 changeCssClass('.icon', 'width:
8px; height:
8px');
623 changeCssClass('.icon', config['cssStyle_icon'].Value);
624 var entriesHtml = '
<table style=
"font-size:' + fontsize + ';">';
628 max = (panelNum +
1) * config['eventsPerWidget'].Value;
630 max =
30; // we can display a lot more events in fullscreen mode
632 if (config['enableLogging'].Value) {
634 for (var i=
0; i < entryLists.length; i++) {
635 listinfo = listinfo +
" " + entryLists[i].length;
636 var entrieslist =
"";
637 for (var j=
0; j < entryLists[i].length; j++) {
638 entrieslist += entryLists[i][j].Summary +
", ";
640 log(
"updateData(): entrieslist: " + entrieslist);
642 log(
"updateData(): inner loop, " + entryLists.length +
" lists, [" + listinfo +
"] entries");
645 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
646 for (var i=
0; counter < max && i < entryLists.length; i++) {
647 for (var j=
0; (counter < max) && (j < entryLists[i].length); j++) {
648 entry = entryLists[i][j];
651 // output event info for debugging
652 var entryInfo =
"event: ";
653 for(var k=
0; k < entryFields.length; ++k) {
654 if (entry[entryFields[k]] != undefined) {
655 entryInfo += entryFields[k] +
"=" + entry[entryFields[k]] +
",";
660 // we don't want ToDos when includeTodos == false or when they are completed
661 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !config['includeTodos'].Value)) {
662 log('skipping ' + entry.id );
667 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
668 if (eventIds[entry.id] ==
1 && entry.Type == 'ToDo') {
669 log('skipped (already included) ' + entry.id);
673 eventIds[entry.id] =
1;
675 // summary can be undefined!
676 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
677 if (entry.Type == 'Meeting' && entry.Location != '' && config['showLocation'].Value)
678 Summary += ', ' + entry.Location;
680 // fix by yves: determine start and end dates/times
681 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
682 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
684 // there can be ToDos that have no date at all!
685 if (entry.Type == 'ToDo' && entry.EndTime == null)
686 entryDate =
""; // this will cause parseDate(entryDate) to return null;
688 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
690 // Convert date/time string to Date object
691 var date = parseDate(entryDate);
692 log('date: ' + date);
693 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
694 log('endDate: ' + endDate);
696 // check if meeting event has already passed
697 if (entry.Type == 'Meeting') {
698 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
699 if (now.getTime()
> compareTime) {
700 log('skipping Meeting (already passed) ' + entry.id);
702 eventIds[entry.id] =
0;
707 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
708 if (entry.Type == 'Anniversary') {
709 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
710 if (date.getTime() < tmp.getTime()) {
711 log('skipping Anniversary (already passed) ' + entry.id);
713 eventIds[entry.id] =
0;
718 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
719 if (entry.Type == 'DayEvent' && endDate != null) {
720 endDate.setMinutes(endDate.getMinutes() -
1);
721 log('fixing DayEvent endDate: ' + endDate);
722 if (now.getTime()
> endDate.getTime()) {
723 log('event already passed ' + entry.id);
725 eventIds[entry.id] =
0;
730 // check if the event is currently taking place
731 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
732 // check if we are between start and endtime
733 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
734 date = now; // change appointment date/time to now
735 log('event is currently taking place: ' + date);
739 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
740 if (mode ==
0 && panelNum
> 0 && counter < panelNum * config['eventsPerWidget'].Value +
1) {
741 log('skipping (already in first widget) ' + entry.id);
745 // mark overdue todos
747 if (entry.Type == 'ToDo' && date != null) {
748 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
0,
0,
0);
749 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
750 if (tmp1.getTime() < tmp2.getTime()) {
755 // generate html output
756 entriesHtml += '
<tr>';
757 if (config['showCalendarIndicator'].Value && calendarList.length - config['excludedCalendars'].Value.length
> 1) {
758 entriesHtml += '
<td><span class=
"calendar' + calendarColors[entry.CalendarName] + '"> </span></td>';
760 entriesHtml += '
<td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
762 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
763 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
765 var weekDay = date.toLocaleDateString().substr(
0,config['weekDayLength'].Value);
766 var time = formatTime(date);
767 var dateStr = formatDate(date, entryDate);
768 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
769 dateStr = '
<span class=
"overdue">' + config['overdueText'].Value + '
</span>';
770 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
771 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
772 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
773 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
775 entriesHtml += '
<td class=
"weekDay" width=
"1px">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
776 } else if (entry.Type == 'Meeting') {
777 if (config['showCombinedDateTime'].Value) {
779 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
780 else if (isTomorrow(date))
781 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
783 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
785 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
786 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
788 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
792 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
795 entriesHtml += '
</table>';
796 if (config['showNothingText'].Value && entriesHtml == '
<table></table>') {
797 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
798 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '
</div>';
800 if (cacheEntriesHtml != entriesHtml) {
802 document.getElementById('calendarList').innerHTML = entriesHtml;
804 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
805 cacheEntriesHtml = entriesHtml;
808 lastUpdateTime = new Date();
810 error('displaying list:' + e + ', line ' + e.line);
815 // called by handleOnShow() and onResize events
816 function updateScreen()
818 log('updateScreen()');
820 // check if opening fullscreen
821 if( window.innerHeight
> 91 && mode ==
0) {
823 cacheEntriesHtml = '';
824 document.getElementById('body').style.backgroundImage =
"";
827 else if (window.innerHeight <=
91 && mode !=
0) {
829 cacheEntriesHtml = '';
834 updateHomescreen(); // check for screen rotation
839 function handleOnShow()
843 var time = new Date();
844 if (time.getTime() - lastUpdateTime.getTime()
> config['updateDataInterval'].Value *
60 *
1000) {
845 log('updateScreen(): force updateData() because last update was too long ago (' + (time.getTime() - lastUpdateTime.getTime()) /
1000 + 's)');
848 setUpdateTimer(); // reinitialize update timer
852 function launchCalendar()
855 widget.openApplication(config['calendarApp'].Value,
"");
856 if (config['hideWidgetOnCalendarOpen'].Value)
859 error('starting Calendar App');
866 log('New widget instance starting up...');
869 // call calendar service
870 if (device !=
"undefined")
871 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
873 throw('device object does not exist');
875 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>');
879 calendarList = listCalendars();
881 updateCalendarColors();
884 requestNotification();
885 document.getElementById(
"settingsTitle").innerHTML = getLocalizedText('menu.settings');
887 if (window.innerHeight
> 91) {
888 mode =
0; // we're starting fullscreen, we set mode to homescreen in order to let updateScreen() do all the work for us
893 log(
"init(): updateScreen()");
895 if (config['useBackgroundImage'].Value)
896 // check for screen rotation every
1 secs
897 screenRotationTimer = window.setInterval('checkOrientation()',
1000 *
1);
899 // call updateScreen() when widget changes from background to forground
900 window.widget.onshow = handleOnShow;
902 log(
"init(): finished...");
905 function checkOrientation()
909 updateHomescreen(); // check for screen rotation
912 function setUpdateTimer()
914 updateTimer = window.setInterval('updateTimerCallback()',
1000 *
60 * config['updateDataInterval'].Value);
917 function clearUpdateTimer()
919 window.clearInterval(updateTimer);
922 function updateTimerCallback()
924 log(
"updateTimerCallback()");
928 function createMenu()
930 window.menu.setLeftSoftkeyLabel(
"",null);
931 window.menu.setRightSoftkeyLabel(
"",null);
933 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
934 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
935 var menuHelp = new MenuItem(getLocalizedText('menu.help'), id++);
936 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
937 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
938 menuSettings.onSelect = showSettings;
939 menuAbout.onSelect = showAbout;
940 menuCallApp.onSelect = launchCalendar;
941 menuUpdate.onSelect = showUpdate;
942 menuHelp.onSelect = showHelp;
944 window.menu.append(menuCallApp);
945 window.menu.append(menuSettings);
946 window.menu.append(menuHelp);
947 window.menu.append(menuUpdate);
948 window.menu.append(menuAbout);
951 function showSettings()
955 document.getElementById(
"settingsView").style.display =
"block";
956 document.onclick = null;
958 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
960 for (var key in config) {
961 if (config[key].Type == 'String')
962 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
963 else if (config[key].Type == 'Int') {
964 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
965 if (config[key].Value <
0)
966 config[key].Value = config[key].Default;
968 else if (config[key].Type == 'Bool')
969 config[key].Value = document.forms[
0].elements[
"settings." + key].checked;
970 else if (config[key].Type == 'UID')
971 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
972 else if (config[key].Type == 'Enum') {
973 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
974 if (config[key].ValidValues.indexOf(config[key].Value) == -
1)
975 config[key].Value = config[key].Default;
977 else if (config[key].Type == 'Array') {
978 if (key == 'excludedCalendars') {
979 config[key].Value = new Array();
980 for(var i=
0; i < calendarList.length; i++) {
981 var element = document.forms[
0].elements[
"settings." + key +
"." + calendarList[i]];
982 if (element != null && element.checked == false)
983 config[key].Value.push(calendarList[i]);
996 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
1002 var settingsHtml = '
<form>';
1003 for (var key in config) {
1004 if (config[key].Type == 'String') {
1006 if (key.substring(
0,
9) ==
"cssStyle_")
1007 prefix = getLocalizedText('settings.cssStyle_prefix');
1008 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 />';
1010 else if (config[key].Type == 'Int')
1011 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 />';
1012 else if (config[key].Type == 'Bool')
1013 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 />';
1014 else if (config[key].Type == 'UID')
1015 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 />';
1016 else if (config[key].Type == 'Enum') {
1017 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><select name=
"settings.' + key + '" size=
"1">';
1018 for(var i =
0; i < config[key].ValidValues.length; i++)
1019 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>';
1020 settingsHtml += '
</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1022 else if (config[key].Type == 'Array') {
1023 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br />';
1024 if (key == 'excludedCalendars') {
1025 for(var i=
0; i < calendarList.length; i++) {
1026 var checked = '
checked=
"checked"';
1027 if (config[key].Value.indexOf(calendarList[i]) != -
1)
1029 settingsHtml += '
<input name=
"settings.' + key + '.' + calendarList[i] + '" type=
"checkbox" value=
"' + calendarList[i] + '" ' + checked + '
/> ' + calendarList[i] + '
<br />';
1032 settingsHtml += '
</td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1035 settingsHtml += '
<input name=
"reset" type=
"button" value=
"' + getLocalizedText('settings.restoreDefaults') + '" onclick=
"javascript:restoreDefaultSettings();showSettings();" />';
1036 settingsHtml += '
</form>';
1037 document.getElementById(
"settingsList").innerHTML = settingsHtml;
1040 function changeCssClass(classname, properties)
1042 for(var i =
0; i < document.styleSheets[
0]['cssRules'].length; i++)
1044 if (document.styleSheets[
0]['cssRules'][i].selectorText == classname) {
1045 document.styleSheets[
0].deleteRule(i);
1046 document.styleSheets[
0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[
0]['cssRules'].length);
1052 function updateCssClasses()
1054 for(var key in config) {
1055 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
1059 function getSettingsCalEntryId()
1061 if (settingsCalEntryId == null) {
1062 // check if entry already exists
1063 var listFiltering = {
1064 Type:'CalendarEntry',
1066 StartRange: new Date(
2000,
0,
1),
1067 EndRange: new Date(
2000,
0,
1),
1068 SearchText: 'ComingNext Settings|',
1072 var result = calendarService.IDataSource.GetList(listFiltering);
1073 if (result.ErrorCode) {
1074 error(result.ErrorMessage);
1077 var list = result.ReturnValue;
1078 var entry = list.getNext();
1079 if (entry != undefined) {
1080 settingsCalEntryId = entry.LocalId;
1081 log(
"settingsCalEntryId=" + settingsCalEntryId);
1083 else { // create settings item
1084 var item = new Object();
1085 item.Type =
"DayEvent";
1086 item.StartTime = new Date(
2000,
0,
1);
1087 item.Summary =
"ComingNext Settings|";
1089 var criteria = new Object();
1090 criteria.Type =
"CalendarEntry";
1091 criteria.Item = item;
1094 var result = calendarService.IDataSource.Add(criteria);
1095 if (result.ErrorCode)
1096 error(result.ErrorMessage);
1098 error(
"getSettingsCalEntryId: " + e + ', line ' + e.line);
1101 getSettingsCalEntryId();
1106 function restoreDefaultSettings()
1108 for (var key in config)
1109 config[key].Value = config[key].Default;
1112 function loadSettings()
1114 getSettingsCalEntryId();
1115 var listFiltering = {
1116 Type:'CalendarEntry',
1118 LocalId: settingsCalEntryId
1121 var result = calendarService.IDataSource.GetList(listFiltering);
1122 if (result.ErrorCode) {
1123 error(result.ErrorMessage);
1126 var entry = result.ReturnValue.getNext();
1127 if (entry != undefined) {
1128 log(
"Loading Settings...");
1129 // only reload settings if they chanced since the last reload
1130 if (settingsCache != entry.Summary)
1132 restoreDefaultSettings();
1133 var stringlist = entry.Summary.split(
"|");
1134 // skip the first two entries, those contain header and version info
1135 for(var i =
2; i < stringlist.length -
1; i++) {
1136 var pair = stringlist[i].split('=');
1138 var value = pair[
1];
1139 log('stringlist: ' + key + '=\'' + value + '\'');
1140 if (config[key].Type == 'Int')
1141 config[key].Value = Number(value);
1142 else if (config[key].Type == 'String')
1143 config[key].Value = value;
1144 else if (config[key].Type == 'Bool')
1145 config[key].Value = (value == 'true')
1146 else if (config[key].Type == 'Enum')
1147 config[key].Value = value;
1148 else if (config[key].Type == 'UID')
1149 config[key].Value = Number(value);
1150 else if (config[key].Type == 'Array') {
1151 config[key].Value = value.split(
"^");
1152 if (config[key].Value.length ==
1 && config[key].Value[
0] ==
"") {
1153 config[key].Value = [];
1157 settingsCache = entry.Summary;
1161 log(
"Settings already cached and did not change");
1165 error(
"Failed to load settings, calendar entry could not be found");
1169 function saveSettings()
1171 getSettingsCalEntryId();
1172 var item = new Object();
1173 item.Type =
"DayEvent";
1174 item.StartTime = new Date(
2000,
0,
1);
1175 item.LocalId = settingsCalEntryId;
1176 item.Summary =
"ComingNext Settings|" + version +
"|";
1178 for (var key in config) {
1179 if (config[key].Type == 'Int')
1180 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1181 else if (config[key].Type == 'String')
1182 item.Summary += key +
"=" + config[key].Value +
"|";
1183 else if (config[key].Type == 'Bool')
1184 item.Summary += key +
"=" + (config[key].Value ? 'true' : 'false') +
"|";
1185 else if (config[key].Type == 'Enum')
1186 item.Summary += key +
"=" + config[key].Value +
"|";
1187 else if (config[key].Type == 'UID')
1188 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1189 else if (config[key].Type == 'Array')
1190 item.Summary += key +
"=" + config[key].Value.join(
"^") +
"|";
1192 settingsCache = item.Summary;
1194 var criteria = new Object();
1195 criteria.Type =
"CalendarEntry";
1196 criteria.Item = item;
1198 log(
"Saving settings to calendar entry: " + item.Summary);
1200 var result = calendarService.IDataSource.Add(criteria);
1201 if (result.ErrorCode)
1202 error(result.ErrorMessage);
1204 error(
"saveSettings: " + e + ', line ' + e.line);
1207 lastReloadTime = null; // force calendar data reload on next update
1212 function toggleVisibility(elementId)
1214 if (document.getElementById(elementId).style.display ==
"none")
1215 document.getElementById(elementId).style.display =
"block";
1217 document.getElementById(elementId).style.display =
"none";
1221 function printHintBox(text)
1224 return '
<td width=
"1%" align=
"right" onclick=
"javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '
</td></tr></table>'+
1225 '
<div class=
"settingsInfo" id=
"info' + uniqueId + '">' + text + '
</div>';
1228 function showAbout()
1232 document.getElementById(
"aboutView").style.display =
"block";
1233 document.onclick = null;
1235 window.menu.setLeftSoftkeyLabel(
" ", function(){});
1236 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1242 //document.getElementById(
"aboutView").innerHTML = 'aboutView';
1243 document.getElementById(
"name").innerHTML =
"Coming Next " + version;
1246 function showHelp() {
1247 widget.openURL('http://comingnext.sf.net/help');
1250 function updateFullscreen()
1254 function showFullscreen()
1256 log(
"showFullscreen()");
1258 document.getElementById(
"fullscreenView").style.display =
"block";
1259 document.getElementById('body').className =
"backgroundFullscreen";
1261 document.onclick = launchCalendar;
1266 function getBackgroundImage()
1271 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[
0]) // internal
1272 bgImage = 'background_' + orientation + '.png';
1274 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
1278 function updateHomescreen()
1280 if (config['useBackgroundImage'].Value) {
1281 // check for screen rotation
1282 if (orientation != 'portrait' && screen.width ==
360 && screen.height ==
640) {
1283 window.widget.prepareForTransition(
"fade");
1284 orientation = 'portrait';
1285 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1286 document.getElementById('body').style.backgroundColor = 'none';
1287 window.widget.performTransition();
1288 } else if (orientation != 'landscape' && screen.width ==
640 && screen.height ==
360) {
1289 window.widget.prepareForTransition(
"fade");
1290 orientation = 'landscape';
1291 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1292 document.getElementById('body').style.backgroundColor = 'none';
1293 window.widget.performTransition();
1295 else if (document.getElementById('body').style.backgroundImage ==
"")
1297 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1302 function showHomescreen()
1304 log(
"showHomescreen()");
1306 document.getElementById(
"homescreenView").style.display =
"block";
1307 document.getElementById('body').className =
"background";
1308 document.onclick = null;
1312 function getLocalizedText(p_Txt)
1314 if (localizedText[p_Txt])
1315 return localizedText[p_Txt];
1317 return 'ERROR: missing translation for ' + p_Txt;
1320 function showUpdate()
1324 document.getElementById(
"updateView").style.display =
"block";
1325 document.onclick = null;
1327 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1330 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1336 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
1340 function checkForUpdate()
1342 // asynch XHR to server url
1343 reqV = new XMLHttpRequest();
1344 reqV.onreadystatechange = checkForUpdateCallback;
1345 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
1346 reqV.open(
"GET", versionURL, true);
1347 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1351 function checkForUpdateCallback()
1353 if (reqV.readyState ==
4) {
1354 if (reqV.status ==
200) {
1355 var resultXml = reqV.responseText;
1357 var div = document.getElementById(
"tmp");
1358 div.innerHTML = resultXml;
1359 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
1360 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
1362 if (version != newVersion) {
1363 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1366 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1371 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1376 function hideViews()
1378 document.getElementById(
"homescreenView").style.display =
"none";
1379 document.getElementById(
"fullscreenView").style.display =
"none";
1380 document.getElementById(
"aboutView").style.display =
"none";
1381 document.getElementById(
"settingsView").style.display =
"none";
1382 document.getElementById(
"updateView").style.display =
"none";
1385 function listCalendars()
1391 DefaultCalendar: false
1395 var calendarsResult = calendarService.IDataSource.GetList(criteria);
1396 if (calendarsResult.ErrorCode !=
0)
1397 throw(
"Error fetching list of calendars: " + calendarsResult.ErrorCode + ': ' + calendarsResult.ErrorMessage);
1398 var calendarListIterator = calendarsResult.ReturnValue;
1403 while (( item = calendarListIterator.getNext()) != undefined ) {
1404 calendars[count++] = item;
1406 log(
"Available Calendars: " + calendars.join(
", "));
1409 error('listing calendars:' + e + ', line ' + e.line);
1414 // Copies all objects and their properties to an array. Data is copied so nothing gets lost when the reference is removed
1415 // 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
1416 function listToArray(list, calendarName)
1418 var array = new Array();
1421 while (( item = list.getNext()) != undefined ) {
1422 var itemCopy = new Object();
1423 for(var i=
0; i < entryFields.length; i++) {
1424 itemCopy[entryFields[i]] = item[entryFields[i]];
1426 // for some reason, the CalendarName property is never correctly queried, so we assign it manually here
1427 if (!itemCopy['CalendarName']) {
1428 itemCopy['CalendarName'] = calendarName;
1430 array.push(itemCopy);
1431 txt += array[array.length -
1].Summary +
", ";
1433 log(
"listToArray(): " + txt);
1437 function sortCalendarEntries(a, b)
1440 log(
"sortCalendarEntries(" + a.Summary +
"," + b.Summary +
")");
1442 if (a.InstanceStartTime != null) {
1443 atime = a.InstanceStartTime;
1445 else if (a.StartTime != null) {
1446 atime = a.StartTime;
1448 else if (a.InstanceEndTime != null) {
1449 atime = a.InstanceEndTime;
1451 else if (a.EndTime != null) {
1455 if (b.InstanceStartTime != null) {
1456 btime = b.InstanceStartTime;
1458 else if (b.StartTime != null) {
1459 btime = b.StartTime;
1461 else if (b.InstanceEndTime != null) {
1462 btime = b.InstanceEndTime;
1464 else if (b.EndTime != null) {
1468 if (atime && btime) {
1470 atime = parseDate(atime);
1471 btime = parseDate(btime);
1473 // sort by date & time
1474 if (atime < btime) {
1477 else if (atime
> btime) {
1481 else if (a.Type != b.Type) {
1482 if (a.Type < b.Type) {
1485 else if (a.Type
> b.Type) {
1489 // sort by description
1490 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1491 if (a.Summary < b.Summary) {
1494 else if (a.Summary
> b.Summary) {
1499 // NOTE: events my have no date information at all. In that case, we list events without date first
1500 else if (atime && !btime) {
1503 else if (!atime && btime) {
1506 else if (!atime && !btime) {
1508 if (a.Type != b.Type) {
1509 if (a.Type < b.Type) {
1512 else if (a.Type
> b.Type) {
1516 // sort by description
1517 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1518 if (a.Summary < b.Summary) {
1521 else if (a.Summary
> b.Summary) {
1530 function updateCalendarColors()
1533 calendarColors = [];
1534 if (calendarList.length
> maxColors) {
1535 log(
"updateCalendarColors(): Warning: more calendars than available indicator colors");
1537 for(var i=
0; i < calendarList.length; i++) {
1538 calendarColors[calendarList[i]] = (i % maxColors) +
1;
1542 function log(message) {
1543 if (config['enableLogging'].Value) {
1544 console.info(message);
1550 <style type=
"text/css">
1552 table { margin:
0px; padding:
0px; border-spacing:
0px; }
1553 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
1554 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1555 .settingsInfo { display:none; font-style:italic; }
1556 .title { font-weight:bold; font-size:
14pt; }
1557 .textInput { width:
90%; }
1558 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1559 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
1560 #calendarList { position:absolute; left:
5px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
1561 #name { text-align:center; }
1562 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1563 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1568 <body onload=
"javascript:setTimeout('init()', 10)" onresize=
"javascript:updateScreen()" id=
"body" class=
"background">
1569 <div id=
"homescreenView">
1570 <div id=
"calendarList"></div>
1572 <div id=
"fullscreenView" style=
"display:none;">
1573 <img src=
"Icon.png" id=
"smallappicon">
1574 <h1 class=
"title">Coming Next
</h1>
1576 <div id=
"fullscreenCalendarList">loading...
</div>
1578 <div id=
"settingsView" style=
"display:none">
1579 <img src=
"Icon.png" id=
"smallappicon">
1580 <h1 id=
"settingsTitle" class=
"title">Settings
</h1>
1582 <div id=
"settingsList"></div>
1584 <div id=
"aboutView" style=
"display:none">
1585 <img src=
"Icon.png" id=
"appicon">
1586 <h1 id=
"name">Coming Next
</h1>
1588 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1589 <p>Contributions:
</p>
1590 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1591 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1592 <p class=
"credits">Christophe Milsent (translation support & french translation)
</p>
1593 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation)
</p>
1594 <p class=
"credits">Tokeda (russian translation)
</p>
1595 <p class=
"credits">Marcella Ferrari (italian translation)
</p>
1596 <p class=
"credits">Venos (italian translation)
</p>
1597 <p>This software is open source and licensed under the GPLv3.
</p>
1598 <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>
1601 <div id=
"updateView" style=
"display:none">
1602 <img src=
"Icon.png" id=
"smallappicon">
1603 <h1 class=
"title">Check for update
</h1>
1605 <div id=
"currentVersion">Coming Next ??
</div>
1606 <div id=
"updateDiv"></div>
1607 <div id=
"tmp" style=
"display:none;"></div>