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 */
11 .backgroundFullscreen { }
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 cssStyle_background: { Type: 'String', Default: 'color:#ffffff; background-color:#
000000', Value: 'color:#ffffff; background-color:#
000000',},
61 cssStyle_backgroundFullscreen: { Type: 'String', Default: 'color:#ffffff; background-color:#
000000', Value: 'color:#ffffff; background-color:#
000000',},
62 cssStyle_weekDay: { Type: 'String', Default: '', Value: '',},
63 cssStyle_date: { Type: 'String', Default: '', Value: '',},
64 cssStyle_today: { Type: 'String', Default: 'color:#ff0000', Value: 'color:#ff0000',},
65 cssStyle_tomorrow: { Type: 'String', Default: 'color:#
0000ff', Value: 'color:#
0000ff',},
66 cssStyle_time: { Type: 'String', Default: '', Value: '',},
67 cssStyle_now: { Type: 'String', Default: 'color:#ff00ff', Value: 'color:#ff00ff',},
68 cssStyle_description: { Type: 'String', Default: '', Value: '',},
69 cssStyle_icon: { Type: 'String', Default: 'width:
15px; height:
15px', Value: 'width:
15px; height:
15px',},
70 cssStyle_overdue: { Type: 'String', Default: 'color:#ffff00', Value: 'color:#ffff00',},
71 cssStyle_calendar1: { Type: 'String', Default: 'background-color:#
0757cf', Value: 'background-color:#
0757cf',},
72 cssStyle_calendar2: { Type: 'String', Default: 'background-color:#
579f37', Value: 'background-color:#
579f37',},
73 cssStyle_calendar3: { Type: 'String', Default: 'background-color:#ff9f07', Value: 'background-color:#ff9f07',},
74 cssStyle_calendar4: { Type: 'String', Default: 'background-color:#af8fef', Value: 'background-color:#af8fef',},
75 cssStyle_calendar5: { Type: 'String', Default: 'background-color:#
57afbf', Value: 'background-color:#
57afbf',},
76 cssStyle_calendar6: { Type: 'String', Default: 'background-color:#
9fdf57', Value: 'background-color:#
9fdf57',},
81 //-------------------------------------------------------
82 // Nothing of interest from here on...
83 //-------------------------------------------------------
84 var panelNum =
0; // use
1 for second panel
86 var versionURL =
"http://comingnext.sourceforge.net/version.xml";
87 var calendarService = null;
88 var cacheEntriesHtml = [];
89 var months_translated = [];
92 var mode =
0; //
0 = homescreen,
1 = fullscreen,
2 = settings,
3 = about,
4 = check for update
94 var settingsCalEntryId = null;
95 var settingsCache = null;
96 var notificationRequests = new Array();
97 var calendarList = [];
98 var calendarColors = [];
99 var updateTimer = null;
100 var screenRotationTimer = null;
101 var lastUpdateTime = now;
102 var errorOccured = false;
104 // vars for daylight saving time
105 var summertime = false; // true, if current date is in summer, false if in winter
106 var daylightSavingDates = new Object(); // caches calculated DST winter and summer time shift dates
108 // this is a list of data fields a calendar event can have
122 window.onload = init;
123 window.onresize = updateScreen;
124 window.onshow = updateScreen;
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 console.info(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 console.info(
"callback(): panelNum: %d transId: %d eventCode: %d result.ErrorCode: %d", panelNum, transId, eventCode, result.ErrorCode);
370 function settingsCallback(transId, eventCode, result)
372 console.info(
"settingsCallback(): panelNum: %d transId: %d eventCode: %d result.ErrorCode: %d", panelNum, transId, eventCode, result.ErrorCode);
376 function parseDate(dateString)
379 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:
380 Wednesday,
26 August,
2009 24:
00:
00
381 Wednesday,
26 August,
2009 12:
00:
00 am
382 Wednesday, August
26,
2009 12:
00:
00 am
383 Wednesday,
2009 August,
26 12:
00:
00 am
384 Wednesday,
2009 August,
28 8.00.00 pm
385 Wednesday,
2009 August,
28 08:
00:
00 PM
388 if (dateString ==
"" || dateString == null)
390 var dateArr = dateString.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
391 if (dateArr.length !=
5 && dateArr.length !=
6)
395 var weekDay = dateArr[
0];
396 var day = dateArr[
1];
397 var month = dateArr[
2];
398 var year = dateArr[
3];
399 // make sure month is set properly
400 if (isNaN(parseInt(day))) {
404 } else if (isNaN(parseInt(year))) {
409 // make sure day and year are set properly
410 if (Number(day)
> Number(year)) {
415 month = months_translated[month];
418 var timeArr = dateArr[
4].split(':');
419 if (timeArr.length !=
3)
421 var hours = Number(timeArr[
0]);
422 var minutes = Number(timeArr[
1]);
423 var seconds = Number(timeArr[
2]);
424 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'pm' && hours <
12)
426 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'am' && hours ==
12)
429 var result = new Date(year, month -
1, day, hours, minutes, seconds);
431 // take care of daylight saving time
432 if (config['enableDaylightSaving'].Value) {
434 // determine if date is in summer or winter time
435 var dateSummerTime = isSummertime(result);
437 // work around bug in Nokias calendar api resulting in dates within a different DST to be off by
1 hour
438 if (summertime && !dateSummerTime) {
439 result = new Date(result.getTime() -
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // -
1 hour
440 console.info('parseDate(): fixing time -
1h: ' + result);
442 else if (!summertime && dateSummerTime) {
443 result = new Date(result.getTime() +
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // +
1 hour
444 console.info('parseDate(): fixing time +
1h: ' + result);
451 // 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"
452 function formatDate(date, format)
454 var day = date.getDate().toString();
455 var month = (date.getMonth() +
1).toString();
456 while (day.length <
2) { day = '
0' + day; }
457 while (month.length <
2) { month = '
0' + month; }
459 if (config['showTodayAsText'].Value && isToday(date))
460 return '
<span class=
"today">' + config['todayText'].Value + '
</span>';
461 if (config['showTodayAsText'].Value && isTomorrow(date))
462 return '
<span class=
"tomorrow">' + config['tomorrowText'].Value + '
</span>';
464 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
465 if (dateArr.length !=
5 && dateArr.length !=
6) {
466 // we don't know how to format this
467 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
468 return day + config['dateSeparator'].Value + month;
470 return month + config['dateSeparator'].Value + day;
474 if (config['dateFormat'].Value == 'MMDD')
476 else if (config['dateFormat'].Value == 'DDMM')
479 // config['dateFormat'].Value == 'auto', try to detect system setting
481 var day_ = dateArr[
1];
482 var month_ = dateArr[
2];
483 var year_ = dateArr[
3];
484 // make sure month is set properly
485 if (isNaN(parseInt(day_))) {
490 } else if (isNaN(parseInt(year_))) {
496 // make sure day and year are set properly
497 if (Number(day_)
> Number(year_))
502 return day + config['dateSeparator'].Value + month;
504 return month + config['dateSeparator'].Value + day;
507 function formatTime(date)
509 // date is a Date() object
510 date.setSeconds(
0); // we don't care about seconds
511 var time = date.toLocaleTimeString().replace(/[\.:]
00/, ''); // remove seconds from string
512 if (time.replace(/\./, ':').split(':')[
0].length <
2)
514 if (config['showNowAsText'].Value && date.getTime() == now.getTime())
515 time = '
<span class=
"now">' + config['nowText'].Value + '
</span>';
519 function updateData()
521 console.info('updateData()');
526 // check if we got additional or less calendars since our last update
527 var newCalendarList = listCalendars();
528 if (newCalendarList.length != calendarList.length) {
529 calendarList = newCalendarList;
530 updateCalendarColors();
531 cancelNotification();
532 requestNotification();
536 // meetings have time
537 // 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
539 summertime = isSummertime(now); // cache summer time info for today
540 var meetingList = [];
541 for(var i=
0; i < calendarList.length; i++) {
542 // ignore excluded calendars
543 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
545 var meetingListFiltering = {
546 Type:'CalendarEntry',
548 CalendarName: calendarList[i],
549 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
550 EndRange: (new Date(now.getFullYear(), now.getMonth() + config['monthRange'].Value, now.getDate(),
0,
0,
0))
553 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
554 if (meetingResult.ErrorCode !=
0)
555 throw(
"Error fetching calendar data: " + meetingResult.ErrorCode + ': ' + meetingResult.ErrorMessage);
556 var list = meetingResult.ReturnValue;
557 meetingList = meetingList.concat(listToArray(list, calendarList[i]));
559 console.info(
"updateData(): meetingList.sort()");
560 meetingList.sort(sortCalendarEntries);
562 // todos don't, they start on
00:
00 hrs., but should be visible anyway
563 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
564 if (config['includeTodos'].Value) {
565 var todayTodoList = [];
566 for(var i=
0; i < calendarList.length; i++) {
567 // ignore excluded calendars
568 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
570 var todayTodoListFiltering = {
571 Type:'CalendarEntry',
573 CalendarName: calendarList[i],
575 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
576 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
579 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
580 var list = todayTodoResult.ReturnValue;
581 todayTodoList = todayTodoList.concat(listToArray(list, calendarList[i]));
583 console.info(
"updateData(): todayTodoList.sort()");
584 todayTodoList.sort(sortCalendarEntries);
585 var entryLists = [todayTodoList, meetingList];
587 var entryLists = [meetingList];
590 error('loading Calendar items list:' + e + ', line ' + e.line);
599 var fontsize = 'normal';
601 if (config['eventsPerWidget'].Value ==
3) {
603 changeCssClass('.icon', 'width:
20px; height:
20px');
605 else if (config['eventsPerWidget'].Value ==
5) {
607 changeCssClass('.icon', 'width:
10px; height:
10px');
609 else if (config['eventsPerWidget'].Value ==
6) {
611 changeCssClass('.icon', 'width:
8px; height:
8px');
615 changeCssClass('.icon', config['cssStyle_icon'].Value);
616 var entriesHtml = '
<table style=
"font-size:' + fontsize + ';">';
620 max = (panelNum +
1) * config['eventsPerWidget'].Value;
622 max =
30; // we can display a lot more events in fullscreen mode
625 for (var i=
0; i < entryLists.length; i++) {
626 listinfo = listinfo +
" " + entryLists[i].length;
627 var entrieslist =
"";
628 for (var j=
0; j < entryLists[i].length; j++) {
629 entrieslist += entryLists[i][j].Summary +
", ";
631 console.info(
"updateData(): entrieslist: " + entrieslist);
633 console.info(
"updateData(): inner loop, " + entryLists.length +
" lists, [" + listinfo +
"] entries");
635 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
636 for (var i=
0; counter < max && i < entryLists.length; i++) {
637 for (var j=
0; (counter < max) && (j < entryLists[i].length); j++) {
638 entry = entryLists[i][j];
641 // output event info for debugging
642 var entryInfo =
"event: ";
643 for(var k=
0; k < entryFields.length; ++k) {
644 if (entry[entryFields[k]] != undefined) {
645 entryInfo += entryFields[k] +
"=" + entry[entryFields[k]] +
",";
648 console.info(entryInfo);
650 // we don't want ToDos when includeTodos == false or when they are completed
651 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !config['includeTodos'].Value)) {
652 console.info('skipping ' + entry.id );
657 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
658 if (eventIds[entry.id] ==
1 && entry.Type == 'ToDo') {
659 console.info('skipped (already included) ' + entry.id);
663 eventIds[entry.id] =
1;
665 // summary can be undefined!
666 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
667 if (entry.Type == 'Meeting' && entry.Location != '' && config['showLocation'].Value)
668 Summary += ', ' + entry.Location;
670 // fix by yves: determine start and end dates/times
671 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
672 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
674 // there can be ToDos that have no date at all!
675 if (entry.Type == 'ToDo' && entry.EndTime == null)
676 entryDate =
""; // this will cause parseDate(entryDate) to return null;
678 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
680 // Convert date/time string to Date object
681 var date = parseDate(entryDate);
682 console.info('date: ' + date);
683 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
684 console.info('endDate: ' + endDate);
686 // check if meeting event has already passed
687 if (entry.Type == 'Meeting') {
688 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
689 if (now.getTime()
> compareTime) {
690 console.info('skipping Meeting (already passed) ' + entry.id);
692 eventIds[entry.id] =
0;
697 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
698 if (entry.Type == 'Anniversary') {
699 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
700 if (date.getTime() < tmp.getTime()) {
701 console.info('skipping Anniversary (already passed) ' + entry.id);
703 eventIds[entry.id] =
0;
708 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
709 if (entry.Type == 'DayEvent' && endDate != null) {
710 endDate.setMinutes(endDate.getMinutes() -
1);
711 console.info('fixing DayEvent endDate: ' + endDate);
712 if (now.getTime()
> endDate.getTime()) {
713 console.info('event already passed ' + entry.id);
715 eventIds[entry.id] =
0;
720 // check if the event is currently taking place
721 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
722 // check if we are between start and endtime
723 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
724 date = now; // change appointment date/time to now
725 console.info('event is currently taking place: ' + date);
729 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
730 if (mode ==
0 && panelNum
> 0 && counter < panelNum * config['eventsPerWidget'].Value +
1) {
731 console.info('skipping (already in first widget) ' + entry.id);
735 // mark overdue todos
737 if (entry.Type == 'ToDo' && date != null) {
738 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
0,
0,
0);
739 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
740 if (tmp1.getTime() < tmp2.getTime()) {
745 // generate html output
746 entriesHtml += '
<tr>';
747 if (config['showCalendarIndicator'].Value && calendarList.length - config['excludedCalendars'].Value.length
> 1) {
748 entriesHtml += '
<td><span class=
"calendar' + calendarColors[entry.CalendarName] + '"> </span></td>';
750 entriesHtml += '
<td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
752 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
753 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
755 var weekDay = date.toLocaleDateString().substr(
0,config['weekDayLength'].Value);
756 var time = formatTime(date);
757 var dateStr = formatDate(date, entryDate);
758 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
759 dateStr = '
<span class=
"overdue">' + config['overdueText'].Value + '
</span>';
760 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
761 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
762 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
763 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
765 entriesHtml += '
<td class=
"weekDay" width=
"1px">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
766 } else if (entry.Type == 'Meeting') {
767 if (config['showCombinedDateTime'].Value) {
769 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
770 else if (isTomorrow(date))
771 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
773 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
775 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
776 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
778 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
782 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
785 entriesHtml += '
</table>';
786 if (config['showNothingText'].Value && entriesHtml == '
<table></table>') {
787 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
788 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '
</div>';
790 if (cacheEntriesHtml != entriesHtml) {
792 document.getElementById('calendarList').innerHTML = entriesHtml;
794 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
795 cacheEntriesHtml = entriesHtml;
798 lastUpdateTime = new Date();
800 error('displaying list:' + e + ', line ' + e.line);
805 function updateScreen()
807 // check if opening fullscreen
808 if( window.innerHeight
> 91 && mode ==
0) {
810 cacheEntriesHtml = '';
811 document.getElementById('body').style.backgroundImage =
"";
814 else if (window.innerHeight <=
91 && mode !=
0) {
816 cacheEntriesHtml = '';
825 var time = new Date();
826 if (time.getTime() - lastUpdateTime.getTime()
> config['updateDataInterval'].Value *
60 *
1000) {
827 console.info('updateScreen(): force updateData() because last update was too long ago (' + (time.getTime() - lastUpdateTime.getTime()) /
1000 + 's)');
830 setUpdateTimer(); // reinitialize update timer
834 function launchCalendar()
837 widget.openApplication(config['calendarApp'].Value,
"");
838 if (config['hideWidgetOnCalendarOpen'].Value)
841 error('starting Calendar App');
848 console.info('New widget instance starting up...');
851 // call calendar service
852 if (device !=
"undefined")
853 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
855 throw('device object does not exist');
857 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>');
861 calendarList = listCalendars();
863 updateCalendarColors();
866 requestNotification();
867 document.getElementById(
"settingsTitle").innerHTML = getLocalizedText('menu.settings');
869 if (window.innerHeight
> 91) {
870 mode =
0; // we're starting fullscreen, we set mode to homescreen in order to let updateScreen() do all the work for us
875 console.info(
"init(): updateScreen()");
877 if (config['useBackgroundImage'].Value)
878 // check for screen rotation every
1 secs
879 screenRotationTimer = window.setInterval('updateScreen()',
1000 *
1);
880 console.info(
"init(): finished...");
883 function setUpdateTimer()
885 updateTimer = window.setInterval('updateTimerCallback()',
1000 *
60 * config['updateDataInterval'].Value);
888 function clearUpdateTimer()
890 window.clearInterval(updateTimer);
893 function updateTimerCallback()
895 console.info(
"updateTimerCallback()");
899 function createMenu()
901 window.menu.setLeftSoftkeyLabel(
"",null);
902 window.menu.setRightSoftkeyLabel(
"",null);
904 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
905 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
906 var menuHelp = new MenuItem(getLocalizedText('menu.help'), id++);
907 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
908 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
909 menuSettings.onSelect = showSettings;
910 menuAbout.onSelect = showAbout;
911 menuCallApp.onSelect = launchCalendar;
912 menuUpdate.onSelect = showUpdate;
913 menuHelp.onSelect = showHelp;
915 window.menu.append(menuCallApp);
916 window.menu.append(menuSettings);
917 window.menu.append(menuHelp);
918 window.menu.append(menuUpdate);
919 window.menu.append(menuAbout);
922 function showSettings()
926 document.getElementById(
"settingsView").style.display =
"block";
927 document.onclick = null;
929 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
931 for (var key in config) {
932 if (config[key].Type == 'String')
933 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
934 else if (config[key].Type == 'Int') {
935 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
936 if (config[key].Value <
0 || isNaN(config[key].Value))
937 config[key].Value = config[key].Default;
939 else if (config[key].Type == 'Bool')
940 config[key].Value = document.forms[
0].elements[
"settings." + key].checked;
941 else if (config[key].Type == 'UID') {
942 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
943 if (isNaN(config[key].Value))
944 config[key].Value = config[key].Default;
946 else if (config[key].Type == 'Enum') {
947 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
948 if (config[key].ValidValues.indexOf(config[key].Value) == -
1)
949 config[key].Value = config[key].Default;
951 else if (config[key].Type == 'Array') {
952 if (key == 'excludedCalendars') {
953 config[key].Value = new Array();
954 for(var i=
0; i < calendarList.length; i++) {
955 var element = document.forms[
0].elements[
"settings." + key +
"." + calendarList[i]];
956 if (element != null && element.checked == false)
957 config[key].Value.push(calendarList[i]);
970 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
976 var settingsHtml = '
<form>';
977 for (var key in config) {
978 if (config[key].Type == 'String') {
980 if (key.substring(
0,
9) ==
"cssStyle_")
981 prefix = getLocalizedText('settings.cssStyle_prefix');
982 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 />';
984 else if (config[key].Type == 'Int')
985 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 />';
986 else if (config[key].Type == 'Bool')
987 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 />';
988 else if (config[key].Type == 'UID')
989 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 />';
990 else if (config[key].Type == 'Enum') {
991 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><select name=
"settings.' + key + '" size=
"1">';
992 for(var i =
0; i < config[key].ValidValues.length; i++)
993 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>';
994 settingsHtml += '
</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
996 else if (config[key].Type == 'Array') {
997 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br />';
998 if (key == 'excludedCalendars') {
999 for(var i=
0; i < calendarList.length; i++) {
1000 var checked = '
checked=
"checked"';
1001 if (config[key].Value.indexOf(calendarList[i]) != -
1)
1003 settingsHtml += '
<input name=
"settings.' + key + '.' + calendarList[i] + '" type=
"checkbox" value=
"' + calendarList[i] + '" ' + checked + '
/> ' + calendarList[i] + '
<br />';
1006 settingsHtml += '
</td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1009 settingsHtml += '
<input name=
"reset" type=
"button" value=
"' + getLocalizedText('settings.restoreDefaults') + '" onclick=
"javascript:restoreDefaultSettings();showSettings();" />';
1010 settingsHtml += '
</form>';
1011 document.getElementById(
"settingsList").innerHTML = settingsHtml;
1014 function changeCssClass(classname, properties)
1016 for(var i =
0; i < document.styleSheets[
0]['cssRules'].length; i++)
1018 if (document.styleSheets[
0]['cssRules'][i].selectorText == classname) {
1019 document.styleSheets[
0].deleteRule(i);
1020 document.styleSheets[
0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[
0]['cssRules'].length);
1026 function updateCssClasses()
1028 for(var key in config) {
1029 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
1033 function getSettingsCalEntryId()
1035 if (settingsCalEntryId == null) {
1036 // check if entry already exists
1037 var listFiltering = {
1038 Type:'CalendarEntry',
1040 StartRange: new Date(
2000,
0,
1),
1041 EndRange: new Date(
2000,
0,
1),
1042 SearchText: 'ComingNext Settings|',
1046 var result = calendarService.IDataSource.GetList(listFiltering);
1047 if (result.ErrorCode) {
1048 error(result.ErrorMessage);
1051 var list = result.ReturnValue;
1052 var entry = list.getNext();
1053 if (entry != undefined) {
1054 settingsCalEntryId = entry.LocalId;
1055 console.info(
"settingsCalEntryId=" + settingsCalEntryId);
1057 else { // create settings item
1058 var item = new Object();
1059 item.Type =
"DayEvent";
1060 item.StartTime = new Date(
2000,
0,
1);
1061 item.Summary =
"ComingNext Settings|";
1063 var criteria = new Object();
1064 criteria.Type =
"CalendarEntry";
1065 criteria.Item = item;
1068 var result = calendarService.IDataSource.Add(criteria);
1069 if (result.ErrorCode)
1070 error(result.ErrorMessage);
1072 error(
"getSettingsCalEntryId: " + e + ', line ' + e.line);
1075 getSettingsCalEntryId();
1080 function restoreDefaultSettings()
1082 for (var key in config)
1083 config[key].Value = config[key].Default;
1086 function loadSettings()
1088 getSettingsCalEntryId();
1089 var listFiltering = {
1090 Type:'CalendarEntry',
1092 LocalId: settingsCalEntryId
1095 var result = calendarService.IDataSource.GetList(listFiltering);
1096 if (result.ErrorCode) {
1097 error(result.ErrorMessage);
1100 var entry = result.ReturnValue.getNext();
1101 if (entry != undefined) {
1102 console.info(
"Loading Settings...");
1103 // only reload settings if they chanced since the last reload
1104 if (settingsCache != entry.Summary)
1106 restoreDefaultSettings();
1107 var stringlist = entry.Summary.split(
"|");
1108 // skip the first two entries, those contain header and version info
1109 for(var i =
2; i < stringlist.length -
1; i++) {
1110 var pair = stringlist[i].split('=');
1112 var value = pair[
1];
1113 console.info('stringlist: ' + key + '=\'' + value + '\'');
1114 if (config[key].Type == 'Int') {
1115 config[key].Value = Number(value);
1116 if (isNaN(config[key].Value))
1117 config[key].Value = config[key].Default;
1119 else if (config[key].Type == 'String')
1120 config[key].Value = value;
1121 else if (config[key].Type == 'Bool')
1122 config[key].Value = (value == 'true')
1123 else if (config[key].Type == 'Enum')
1124 config[key].Value = value;
1125 else if (config[key].Type == 'UID') {
1126 config[key].Value = Number(value);
1127 if (isNaN(config[key].Value))
1128 config[key].Value = config[key].Default;
1130 else if (config[key].Type == 'Array') {
1131 config[key].Value = value.split(
"^");
1132 if (config[key].Value.length ==
1 && config[key].Value[
0] ==
"") {
1133 config[key].Value = [];
1137 settingsCache = entry.Summary;
1141 console.info(
"Settings already cached and did not change");
1145 error(
"Failed to load settings, calendar entry could not be found");
1149 function saveSettings()
1151 getSettingsCalEntryId();
1152 var item = new Object();
1153 item.Type =
"DayEvent";
1154 item.StartTime = new Date(
2000,
0,
1);
1155 item.LocalId = settingsCalEntryId;
1156 item.Summary =
"ComingNext Settings|" + version +
"|";
1158 for (var key in config) {
1159 if (config[key].Type == 'Int')
1160 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1161 else if (config[key].Type == 'String')
1162 item.Summary += key +
"=" + config[key].Value +
"|";
1163 else if (config[key].Type == 'Bool')
1164 item.Summary += key +
"=" + (config[key].Value ? 'true' : 'false') +
"|";
1165 else if (config[key].Type == 'Enum')
1166 item.Summary += key +
"=" + config[key].Value +
"|";
1167 else if (config[key].Type == 'UID')
1168 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1169 else if (config[key].Type == 'Array')
1170 item.Summary += key +
"=" + config[key].Value.join(
"^") +
"|";
1172 settingsCache = item.Summary;
1174 var criteria = new Object();
1175 criteria.Type =
"CalendarEntry";
1176 criteria.Item = item;
1178 console.info(
"Saving settings to calendar entry: " + item.Summary);
1180 var result = calendarService.IDataSource.Add(criteria);
1181 if (result.ErrorCode)
1182 error(result.ErrorMessage);
1184 error(
"saveSettings: " + e + ', line ' + e.line);
1191 function toggleVisibility(elementId)
1193 if (document.getElementById(elementId).style.display ==
"none")
1194 document.getElementById(elementId).style.display =
"block";
1196 document.getElementById(elementId).style.display =
"none";
1200 function printHintBox(text)
1203 return '
<td width=
"1%" align=
"right" onclick=
"javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '
</td></tr></table>'+
1204 '
<div class=
"settingsInfo" id=
"info' + uniqueId + '">' + text + '
</div>';
1207 function showAbout()
1211 document.getElementById(
"aboutView").style.display =
"block";
1212 document.onclick = null;
1214 window.menu.setLeftSoftkeyLabel(
" ", function(){});
1215 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1221 //document.getElementById(
"aboutView").innerHTML = 'aboutView';
1222 document.getElementById(
"name").innerHTML =
"Coming Next " + version;
1225 function showHelp() {
1226 widget.openURL('http://comingnext.sf.net/help');
1229 function updateFullscreen()
1233 function showFullscreen()
1235 console.info(
"showFullscreen()");
1237 document.getElementById(
"fullscreenView").style.display =
"block";
1238 document.getElementById('body').className =
"backgroundFullscreen";
1240 document.onclick = launchCalendar;
1245 function getBackgroundImage()
1250 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[
0]) // internal
1251 bgImage = 'background_' + orientation + '.png';
1253 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
1257 function updateHomescreen()
1259 if (config['useBackgroundImage'].Value) {
1260 // check for screen rotation
1261 if (orientation != 'portrait' && screen.width ==
360 && screen.height ==
640) {
1262 window.widget.prepareForTransition(
"fade");
1263 orientation = 'portrait';
1264 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1265 document.getElementById('body').style.backgroundColor = 'none';
1266 window.widget.performTransition();
1267 } else if (orientation != 'landscape' && screen.width ==
640 && screen.height ==
360) {
1268 window.widget.prepareForTransition(
"fade");
1269 orientation = 'landscape';
1270 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1271 document.getElementById('body').style.backgroundColor = 'none';
1272 window.widget.performTransition();
1274 else if (document.getElementById('body').style.backgroundImage ==
"")
1276 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1281 function showHomescreen()
1283 console.info(
"showHomescreen()");
1285 document.getElementById(
"homescreenView").style.display =
"block";
1286 document.getElementById('body').className =
"background";
1287 document.onclick = null;
1291 function getLocalizedText(p_Txt)
1293 if (localizedText[p_Txt])
1294 return localizedText[p_Txt];
1296 return 'ERROR: missing translation for ' + p_Txt;
1299 function showUpdate()
1303 document.getElementById(
"updateView").style.display =
"block";
1304 document.onclick = null;
1306 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1309 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1315 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
1319 function checkForUpdate()
1321 // asynch XHR to server url
1322 reqV = new XMLHttpRequest();
1323 reqV.onreadystatechange = checkForUpdateCallback;
1324 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
1325 reqV.open(
"GET", versionURL, true);
1326 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1330 function checkForUpdateCallback()
1332 if (reqV.readyState ==
4) {
1333 if (reqV.status ==
200) {
1334 var resultXml = reqV.responseText;
1336 var div = document.getElementById(
"tmp");
1337 div.innerHTML = resultXml;
1338 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
1339 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
1341 if (version != newVersion) {
1342 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1345 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1350 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1355 function hideViews()
1357 document.getElementById(
"homescreenView").style.display =
"none";
1358 document.getElementById(
"fullscreenView").style.display =
"none";
1359 document.getElementById(
"aboutView").style.display =
"none";
1360 document.getElementById(
"settingsView").style.display =
"none";
1361 document.getElementById(
"updateView").style.display =
"none";
1364 function listCalendars()
1370 DefaultCalendar: false
1374 var calendarsResult = calendarService.IDataSource.GetList(criteria);
1375 if (calendarsResult.ErrorCode !=
0)
1376 throw(
"Error fetching list of calendars: " + calendarsResult.ErrorCode + ': ' + calendarsResult.ErrorMessage);
1377 var calendarListIterator = calendarsResult.ReturnValue;
1382 while (( item = calendarListIterator.getNext()) != undefined ) {
1383 calendars[count++] = item;
1385 console.info(
"Available Calendars: " + calendars.join(
", "));
1388 error('listing calendars:' + e + ', line ' + e.line);
1393 // Copies all objects and their properties to an array. Data is copied so nothing gets lost when the reference is removed
1394 // 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
1395 function listToArray(list, calendarName)
1397 var array = new Array();
1400 while (( item = list.getNext()) != undefined ) {
1401 var itemCopy = new Object();
1402 for(var i=
0; i < entryFields.length; i++) {
1403 itemCopy[entryFields[i]] = item[entryFields[i]];
1405 // for some reason, the CalendarName property is never correctly queried, so we assign it manually here
1406 if (!itemCopy['CalendarName']) {
1407 itemCopy['CalendarName'] = calendarName;
1409 array.push(itemCopy);
1410 txt += array[array.length -
1].Summary +
", ";
1412 console.info(
"listToArray(): " + txt);
1416 function sortCalendarEntries(a, b)
1419 console.info(
"sortCalendarEntries(" + a.Summary +
"," + b.Summary +
")");
1421 if (a.InstanceStartTime != null) {
1422 atime = a.InstanceStartTime;
1424 else if (a.StartTime != null) {
1425 atime = a.StartTime;
1427 else if (a.InstanceEndTime != null) {
1428 atime = a.InstanceEndTime;
1430 else if (a.EndTime != null) {
1434 if (b.InstanceStartTime != null) {
1435 btime = b.InstanceStartTime;
1437 else if (b.StartTime != null) {
1438 btime = b.StartTime;
1440 else if (b.InstanceEndTime != null) {
1441 btime = b.InstanceEndTime;
1443 else if (b.EndTime != null) {
1447 if (atime && btime) {
1449 atime = parseDate(atime);
1450 btime = parseDate(btime);
1452 // sort by date & time
1453 if (atime < btime) {
1456 else if (atime
> btime) {
1460 else if (a.Type != b.Type) {
1461 if (a.Type < b.Type) {
1464 else if (a.Type
> b.Type) {
1468 // sort by description
1469 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1470 if (a.Summary < b.Summary) {
1473 else if (a.Summary
> b.Summary) {
1478 // NOTE: events my have no date information at all. In that case, we list events without date first
1479 else if (atime && !btime) {
1482 else if (!atime && btime) {
1485 else if (!atime && !btime) {
1487 if (a.Type != b.Type) {
1488 if (a.Type < b.Type) {
1491 else if (a.Type
> b.Type) {
1495 // sort by description
1496 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1497 if (a.Summary < b.Summary) {
1500 else if (a.Summary
> b.Summary) {
1509 function updateCalendarColors()
1512 calendarColors = [];
1513 if (calendarList.length
> maxColors) {
1514 console.info(
"updateCalendarColors(): Warning: more calendars than available indicator colors");
1516 for(var i=
0; i < calendarList.length; i++) {
1517 calendarColors[calendarList[i]] = (i % maxColors) +
1;
1523 <style type=
"text/css">
1525 table { margin:
0px; padding:
0px; border-spacing:
0px; }
1526 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
1527 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1528 .settingsInfo { display:none; font-style:italic; }
1529 .title { font-weight:bold; font-size:
14pt; }
1530 .textInput { width:
90%; }
1531 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1532 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
1533 #calendarList { position:absolute; left:
5px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
1534 #name { text-align:center; }
1535 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1536 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1541 <body id=
"body" class=
"background">
1542 <div id=
"homescreenView">
1543 <div id=
"calendarList"></div>
1545 <div id=
"fullscreenView" style=
"display:none;">
1546 <img src=
"Icon.png" id=
"smallappicon">
1547 <h1 class=
"title">Coming Next
</h1>
1549 <div id=
"fullscreenCalendarList">loading...
</div>
1551 <div id=
"settingsView" style=
"display:none">
1552 <img src=
"Icon.png" id=
"smallappicon">
1553 <h1 id=
"settingsTitle" class=
"title">Settings
</h1>
1555 <div id=
"settingsList"></div>
1557 <div id=
"aboutView" style=
"display:none">
1558 <img src=
"Icon.png" id=
"appicon">
1559 <h1 id=
"name">Coming Next
</h1>
1561 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1562 <p>Contributions:
</p>
1563 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1564 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1565 <p class=
"credits">Christophe Milsent (translation support & french translation)
</p>
1566 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation)
</p>
1567 <p class=
"credits">Tokeda (russian translation)
</p>
1568 <p class=
"credits">Marcella Ferrari (italian translation)
</p>
1569 <p class=
"credits">Venos (italian translation)
</p>
1570 <p>This software is open source and licensed under the GPLv3.
</p>
1571 <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>
1574 <div id=
"updateView" style=
"display:none">
1575 <img src=
"Icon.png" id=
"smallappicon">
1576 <h1 class=
"title">Check for update
</h1>
1578 <div id=
"currentVersion">Coming Next ??
</div>
1579 <div id=
"updateDiv"></div>
1580 <div id=
"tmp" style=
"display:none;"></div>