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 window.onload = init;
127 window.onresize = updateScreen;
128 window.onshow = updateScreen;
130 function isLeapYear( year ) {
131 if (( year %
4 ==
0 && year %
100 !=
0 ) || year %
400 ==
0 )
137 function calcLeapYear(year, days)
139 if (isLeapYear(year))
145 function subToSunday(myDate, year, days, prevMonthDays)
147 for (i = myDate.getDay(); i
> 0 ;i--)
149 days -= prevMonthDays;
150 days = isLeapYear(year) ? --days : days;
154 function isSummertime(curDate)
159 // if we already calculated DST summer and winter time dates for this year, use cached values
160 var dst = daylightSavingDates[curDate.getFullYear()];
162 var thisYearS = new Date(curDate.getFullYear(),
3,
0,
0,
0,
0 );
163 var thisYearW = new Date(curDate.getFullYear(),
10,
0,
0,
0,
0 );
164 var nextYearS = new Date(curDate.getFullYear() +
1,
3,
0,
0,
0,
0 );
165 var nextYearW = new Date(curDate.getFullYear() +
1,
10,
0,
0,
0,
0 );
167 thisYearSDays = nextYearSDays =
90;
168 thisYearWDays = nextYearWDays =
304;
170 thisYearSDays = calcLeapYear(curDate.getFullYear(), thisYearSDays);
171 thisYearWDays = calcLeapYear(curDate.getFullYear(), thisYearWDays);
172 nextYearSDays = calcLeapYear(curDate.getFullYear() +
1, nextYearSDays);
173 nextYearWDays = calcLeapYear(curDate.getFullYear() +
1, nextYearWDays);
175 thisYearSDays = subToSunday(thisYearS, curDate.getFullYear(), thisYearSDays,
59);
176 thisYearWDays = subToSunday(thisYearW, curDate.getFullYear(), thisYearWDays,
273);
177 nextYearSDays = subToSunday(nextYearS, curDate.getFullYear() +
1, nextYearSDays,
59);
178 nextYearWDays = subToSunday(nextYearW, curDate.getFullYear() +
1, nextYearWDays,
273);
181 Summer: new Date (curDate.getFullYear(),
03-
1, thisYearSDays,
2,
0,
0),
182 Winter: new Date (curDate.getFullYear(),
10-
1, thisYearWDays,
2,
0,
0),
184 daylightSavingDates[curDate.getFullYear()] = dst;
187 if (dst.Summer < curDate)
189 if (dst.Winter < curDate)
191 if (summer && !winter)
197 function error(message)
199 console.info('Error: ' + message);
200 document.getElementById(
"calendarList").innerHTML = 'Error: ' + message;
201 document.getElementById(
"fullscreenCalendarList").innerHTML = 'Error: ' + message;
203 document.onclick = null;
206 function areDatesEqual(date1, date2)
208 return (date1.getFullYear() == date2.getFullYear() &&
209 date1.getMonth() == date2.getMonth() &&
210 date1.getDate() == date2.getDate());
213 function isTomorrow(date)
215 // tommorow = now +
1 day
216 // ToDo: some days can be shorter as
24 hours(daylight saving change day)
217 return areDatesEqual(date, new Date (now.getTime() +
24*
60*
60*
1000));
220 function isToday(date)
222 return areDatesEqual(date, now);
225 function collectLocales()
227 var tmpyear =
2000 + panelNum;
230 if (months_translated.length
> 0)
232 for (month =
0; month <
12; month++) {
233 var startDate = new Date(tmpyear, month,
15);
235 var item = new Object();
236 item.Type =
"DayEvent";
237 item.StartTime = startDate;
238 item.Summary =
"__temp" + month;
240 var criteria = new Object();
241 criteria.Type =
"CalendarEntry";
242 criteria.Item = item;
245 var result = calendarService.IDataSource.Add(criteria);
246 if (result.ErrorCode)
247 error(result.ErrorMessage);
249 error(
"collectLocales: " + e + ', line ' + e.line);
253 var startTime = new Date(tmpyear,
0,
1);
254 var endTime = new Date(tmpyear,
11,
31);
255 var listFiltering = {
256 Type:'CalendarEntry',
258 StartRange: startTime,
260 SearchText: '__temp',
264 var result = calendarService.IDataSource.GetList(listFiltering);
265 if (result.ErrorCode) {
266 error(result.ErrorMessage);
269 var list = result.ReturnValue;
271 error(e + ', line ' + e.line);
274 var ids = new Array();
280 while (list && (entry = list.getNext()) != undefined) {
281 dateArr = entry.StartTime.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
282 var day = dateArr[
1];
283 var month = dateArr[
2];
284 var year = dateArr[
3];
286 // make sure month is set properly
287 if (isNaN(parseInt(day))) {
291 } else if (isNaN(parseInt(year))) {
297 log(entry.StartTime + ' -
> ' + month + ' ' + counter);
298 ids[counter] = entry.id;
299 months_translated[month] = counter +
1;
303 error(e + ', line ' + e.line);
308 var criteria = new Object();
309 criteria.Type =
"CalendarEntry";
314 var result = calendarService.IDataSource.Delete(criteria);
315 if (result.ErrorCode)
316 error(result.ErrorMessage);
318 error('deleting temp calendar entries:' + e + ', line ' + e.line);
323 function requestNotification()
325 var criteria = new Object();
326 criteria.Type =
"CalendarEntry";
327 criteria.Filter = new Object();
328 for(var i=
0; i < calendarList.length; i++) {
329 criteria.Filter.CalendarName = calendarList[i];
331 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria, callback);
332 if (notificationRequest.ErrorCode)
333 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
334 notificationRequests.push(notificationRequest);
336 error(
"requestNotification: " + e + ', line ' + e.line);
340 var criteria2 = new Object();
341 criteria2.Type =
"CalendarEntry";
342 criteria2.Filter = new Object();
343 criteria2.Filter.LocalIdList = new Array();
344 criteria2.Filter.LocalIdList[
0] = settingsCalEntryId;
346 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria2, settingsCallback);
347 if (notificationRequest.ErrorCode)
348 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
349 notificationRequests.push(notificationRequest);
351 error(
"requestNotification: " + e + ', line ' + e.line);
355 function cancelNotification()
357 for(var i=
0; i < notificationRequests.length; i++) {
359 var result = calendarService.IDataSource.Cancel(notificationRequests[i]);
360 if (result.ErrorCode)
361 error('cancelNotification failed with error code ' + result.ErrorCode);
363 error(
"cancelNotification: " + e + ', line ' + e.line);
368 function callback(transId, eventCode, result)
370 log(
"callback(): panelNum: %d transId: %d eventCode: %d result.ErrorCode: %d", panelNum, transId, eventCode, result.ErrorCode);
371 lastReloadTime = null; // force calendar data reload on next update
375 function settingsCallback(transId, eventCode, result)
377 log(
"settingsCallback(): panelNum: %d transId: %d eventCode: %d result.ErrorCode: %d", panelNum, transId, eventCode, result.ErrorCode);
381 function parseDate(dateString)
384 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:
385 Wednesday,
26 August,
2009 24:
00:
00
386 Wednesday,
26 August,
2009 12:
00:
00 am
387 Wednesday, August
26,
2009 12:
00:
00 am
388 Wednesday,
2009 August,
26 12:
00:
00 am
389 Wednesday,
2009 August,
28 8.00.00 pm
390 Wednesday,
2009 August,
28 08:
00:
00 PM
393 if (dateString ==
"" || dateString == null)
395 var dateArr = dateString.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
396 if (dateArr.length !=
5 && dateArr.length !=
6)
400 var weekDay = dateArr[
0];
401 var day = dateArr[
1];
402 var month = dateArr[
2];
403 var year = dateArr[
3];
404 // make sure month is set properly
405 if (isNaN(parseInt(day))) {
409 } else if (isNaN(parseInt(year))) {
414 // make sure day and year are set properly
415 if (Number(day)
> Number(year)) {
420 month = months_translated[month];
423 var timeArr = dateArr[
4].split(':');
424 if (timeArr.length !=
3)
426 var hours = Number(timeArr[
0]);
427 var minutes = Number(timeArr[
1]);
428 var seconds = Number(timeArr[
2]);
429 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'pm' && hours <
12)
431 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'am' && hours ==
12)
434 var result = new Date(year, month -
1, day, hours, minutes, seconds);
436 // take care of daylight saving time
437 if (config['enableDaylightSaving'].Value) {
439 // determine if date is in summer or winter time
440 var dateSummerTime = isSummertime(result);
442 // work around bug in Nokias calendar api resulting in dates within a different DST to be off by
1 hour
443 if (summertime && !dateSummerTime) {
444 result = new Date(result.getTime() -
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // -
1 hour
445 log('parseDate(): fixing time -
1h: ' + result);
447 else if (!summertime && dateSummerTime) {
448 result = new Date(result.getTime() +
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // +
1 hour
449 log('parseDate(): fixing time +
1h: ' + result);
456 // 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"
457 function formatDate(date, format)
459 var day = date.getDate().toString();
460 var month = (date.getMonth() +
1).toString();
461 while (day.length <
2) { day = '
0' + day; }
462 while (month.length <
2) { month = '
0' + month; }
464 if (config['showTodayAsText'].Value && isToday(date))
465 return '
<span class=
"today">' + config['todayText'].Value + '
</span>';
466 if (config['showTodayAsText'].Value && isTomorrow(date))
467 return '
<span class=
"tomorrow">' + config['tomorrowText'].Value + '
</span>';
469 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
470 if (dateArr.length !=
5 && dateArr.length !=
6) {
471 // we don't know how to format this
472 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
473 return day + config['dateSeparator'].Value + month;
475 return month + config['dateSeparator'].Value + day;
479 if (config['dateFormat'].Value == 'MMDD')
481 else if (config['dateFormat'].Value == 'DDMM')
484 // config['dateFormat'].Value == 'auto', try to detect system setting
486 var day_ = dateArr[
1];
487 var month_ = dateArr[
2];
488 var year_ = dateArr[
3];
489 // make sure month is set properly
490 if (isNaN(parseInt(day_))) {
495 } else if (isNaN(parseInt(year_))) {
501 // make sure day and year are set properly
502 if (Number(day_)
> Number(year_))
507 return day + config['dateSeparator'].Value + month;
509 return month + config['dateSeparator'].Value + day;
512 function formatTime(date)
514 // date is a Date() object
515 date.setSeconds(
0); // we don't care about seconds
516 var time = date.toLocaleTimeString().replace(/[\.:]
00/, ''); // remove seconds from string
517 if (time.replace(/\./, ':').split(':')[
0].length <
2)
519 if (config['showNowAsText'].Value && date.getTime() == now.getTime())
520 time = '
<span class=
"now">' + config['nowText'].Value + '
</span>';
524 function updateData()
531 // check if we got additional or less calendars since our last update
532 var newCalendarList = listCalendars();
533 if (newCalendarList.length != calendarList.length) {
534 calendarList = newCalendarList;
535 updateCalendarColors();
536 cancelNotification();
537 requestNotification();
538 lastReloadTime = null; // force calendar data reload on this update
543 // only reload calendar data every
6 hours, visual updates occure more often
544 if (!lastReloadTime || now.getTime() - lastReloadTime.getTime()
> reloadInterval) {
545 log('updateData(): reloading calendar data');
547 // meetings have time
548 // 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
549 summertime = isSummertime(now); // cache summer time info for today
550 var meetingList = [];
551 for(var i=
0; i < calendarList.length; i++) {
552 // ignore excluded calendars
553 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
555 var meetingListFiltering = {
556 Type:'CalendarEntry',
558 CalendarName: calendarList[i],
559 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
560 EndRange: (new Date(now.getFullYear(), now.getMonth() + config['monthRange'].Value, now.getDate(),
0,
0,
0))
563 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
564 if (meetingResult.ErrorCode !=
0)
565 throw(
"Error fetching calendar data: " + meetingResult.ErrorCode + ': ' + meetingResult.ErrorMessage);
566 var list = meetingResult.ReturnValue;
567 meetingList = meetingList.concat(listToArray(list, calendarList[i]));
569 log(
"updateData(): meetingList.sort()");
570 meetingList.sort(sortCalendarEntries);
572 // todos don't, they start on
00:
00 hrs., but should be visible anyway
573 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
574 if (config['includeTodos'].Value) {
575 var todayTodoList = [];
576 for(var i=
0; i < calendarList.length; i++) {
577 // ignore excluded calendars
578 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
580 var todayTodoListFiltering = {
581 Type:'CalendarEntry',
583 CalendarName: calendarList[i],
585 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
586 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
589 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
590 var list = todayTodoResult.ReturnValue;
591 todayTodoList = todayTodoList.concat(listToArray(list, calendarList[i]));
593 log(
"updateData(): todayTodoList.sort()");
594 todayTodoList.sort(sortCalendarEntries);
595 entryLists = [todayTodoList, meetingList];
597 entryLists = [meetingList];
599 lastReloadTime = new Date();
601 error('loading Calendar items list:' + e + ', line ' + e.line);
611 var fontsize = 'normal';
613 if (config['eventsPerWidget'].Value ==
3) {
615 changeCssClass('.icon', 'width:
20px; height:
20px');
617 else if (config['eventsPerWidget'].Value ==
5) {
619 changeCssClass('.icon', 'width:
10px; height:
10px');
621 else if (config['eventsPerWidget'].Value ==
6) {
623 changeCssClass('.icon', 'width:
8px; height:
8px');
627 changeCssClass('.icon', config['cssStyle_icon'].Value);
628 var entriesHtml = '
<table style=
"font-size:' + fontsize + ';">';
632 max = (panelNum +
1) * config['eventsPerWidget'].Value;
634 max =
30; // we can display a lot more events in fullscreen mode
636 if (config['enableLogging'].Value) {
638 for (var i=
0; i < entryLists.length; i++) {
639 listinfo = listinfo +
" " + entryLists[i].length;
640 var entrieslist =
"";
641 for (var j=
0; j < entryLists[i].length; j++) {
642 entrieslist += entryLists[i][j].Summary +
", ";
644 log(
"updateData(): entrieslist: " + entrieslist);
646 log(
"updateData(): inner loop, " + entryLists.length +
" lists, [" + listinfo +
"] entries");
649 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
650 for (var i=
0; counter < max && i < entryLists.length; i++) {
651 for (var j=
0; (counter < max) && (j < entryLists[i].length); j++) {
652 entry = entryLists[i][j];
655 // output event info for debugging
656 var entryInfo =
"event: ";
657 for(var k=
0; k < entryFields.length; ++k) {
658 if (entry[entryFields[k]] != undefined) {
659 entryInfo += entryFields[k] +
"=" + entry[entryFields[k]] +
",";
664 // we don't want ToDos when includeTodos == false or when they are completed
665 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !config['includeTodos'].Value)) {
666 log('skipping ' + entry.id );
671 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
672 if (eventIds[entry.id] ==
1 && entry.Type == 'ToDo') {
673 log('skipped (already included) ' + entry.id);
677 eventIds[entry.id] =
1;
679 // summary can be undefined!
680 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
681 if (entry.Type == 'Meeting' && entry.Location != '' && config['showLocation'].Value)
682 Summary += ', ' + entry.Location;
684 // fix by yves: determine start and end dates/times
685 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
686 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
688 // there can be ToDos that have no date at all!
689 if (entry.Type == 'ToDo' && entry.EndTime == null)
690 entryDate =
""; // this will cause parseDate(entryDate) to return null;
692 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
694 // Convert date/time string to Date object
695 var date = parseDate(entryDate);
696 log('date: ' + date);
697 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
698 log('endDate: ' + endDate);
700 // check if meeting event has already passed
701 if (entry.Type == 'Meeting') {
702 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
703 if (now.getTime()
> compareTime) {
704 log('skipping Meeting (already passed) ' + entry.id);
706 eventIds[entry.id] =
0;
711 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
712 if (entry.Type == 'Anniversary') {
713 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
714 if (date.getTime() < tmp.getTime()) {
715 log('skipping Anniversary (already passed) ' + entry.id);
717 eventIds[entry.id] =
0;
722 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
723 if (entry.Type == 'DayEvent' && endDate != null) {
724 endDate.setMinutes(endDate.getMinutes() -
1);
725 log('fixing DayEvent endDate: ' + endDate);
726 if (now.getTime()
> endDate.getTime()) {
727 log('event already passed ' + entry.id);
729 eventIds[entry.id] =
0;
734 // check if the event is currently taking place
735 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
736 // check if we are between start and endtime
737 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
738 date = now; // change appointment date/time to now
739 log('event is currently taking place: ' + date);
743 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
744 if (mode ==
0 && panelNum
> 0 && counter < panelNum * config['eventsPerWidget'].Value +
1) {
745 log('skipping (already in first widget) ' + entry.id);
749 // mark overdue todos
751 if (entry.Type == 'ToDo' && date != null) {
752 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
0,
0,
0);
753 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
754 if (tmp1.getTime() < tmp2.getTime()) {
759 // generate html output
760 entriesHtml += '
<tr>';
761 if (config['showCalendarIndicator'].Value && calendarList.length - config['excludedCalendars'].Value.length
> 1) {
762 entriesHtml += '
<td><span class=
"calendar' + calendarColors[entry.CalendarName] + '"> </span></td>';
764 entriesHtml += '
<td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
766 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
767 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
769 var weekDay = date.toLocaleDateString().substr(
0,config['weekDayLength'].Value);
770 var time = formatTime(date);
771 var dateStr = formatDate(date, entryDate);
772 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
773 dateStr = '
<span class=
"overdue">' + config['overdueText'].Value + '
</span>';
774 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
775 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
776 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
777 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
779 entriesHtml += '
<td class=
"weekDay" width=
"1px">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
780 } else if (entry.Type == 'Meeting') {
781 if (config['showCombinedDateTime'].Value) {
783 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
784 else if (isTomorrow(date))
785 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
787 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
789 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
790 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
792 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
796 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
799 entriesHtml += '
</table>';
800 if (config['showNothingText'].Value && entriesHtml == '
<table></table>') {
801 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
802 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '
</div>';
804 if (cacheEntriesHtml != entriesHtml) {
806 document.getElementById('calendarList').innerHTML = entriesHtml;
808 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
809 cacheEntriesHtml = entriesHtml;
812 lastUpdateTime = new Date();
814 error('displaying list:' + e + ', line ' + e.line);
819 function updateScreen()
821 // check if opening fullscreen
822 if( window.innerHeight
> 91 && mode ==
0) {
824 cacheEntriesHtml = '';
825 document.getElementById('body').style.backgroundImage =
"";
828 else if (window.innerHeight <=
91 && mode !=
0) {
830 cacheEntriesHtml = '';
839 var time = new Date();
840 if (time.getTime() - lastUpdateTime.getTime()
> config['updateDataInterval'].Value *
60 *
1000) {
841 log('updateScreen(): force updateData() because last update was too long ago (' + (time.getTime() - lastUpdateTime.getTime()) /
1000 + 's)');
844 setUpdateTimer(); // reinitialize update timer
848 function launchCalendar()
851 widget.openApplication(config['calendarApp'].Value,
"");
852 if (config['hideWidgetOnCalendarOpen'].Value)
855 error('starting Calendar App');
862 log('New widget instance starting up...');
865 // call calendar service
866 if (device !=
"undefined")
867 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
869 throw('device object does not exist');
871 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>');
875 calendarList = listCalendars();
877 updateCalendarColors();
880 requestNotification();
881 document.getElementById(
"settingsTitle").innerHTML = getLocalizedText('menu.settings');
883 if (window.innerHeight
> 91) {
884 mode =
0; // we're starting fullscreen, we set mode to homescreen in order to let updateScreen() do all the work for us
889 log(
"init(): updateScreen()");
891 if (config['useBackgroundImage'].Value)
892 // check for screen rotation every
1 secs
893 screenRotationTimer = window.setInterval('updateScreen()',
1000 *
1);
894 log(
"init(): finished...");
897 function setUpdateTimer()
899 updateTimer = window.setInterval('updateTimerCallback()',
1000 *
60 * config['updateDataInterval'].Value);
902 function clearUpdateTimer()
904 window.clearInterval(updateTimer);
907 function updateTimerCallback()
909 log(
"updateTimerCallback()");
913 function createMenu()
915 window.menu.setLeftSoftkeyLabel(
"",null);
916 window.menu.setRightSoftkeyLabel(
"",null);
918 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
919 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
920 var menuHelp = new MenuItem(getLocalizedText('menu.help'), id++);
921 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
922 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
923 menuSettings.onSelect = showSettings;
924 menuAbout.onSelect = showAbout;
925 menuCallApp.onSelect = launchCalendar;
926 menuUpdate.onSelect = showUpdate;
927 menuHelp.onSelect = showHelp;
929 window.menu.append(menuCallApp);
930 window.menu.append(menuSettings);
931 window.menu.append(menuHelp);
932 window.menu.append(menuUpdate);
933 window.menu.append(menuAbout);
936 function showSettings()
940 document.getElementById(
"settingsView").style.display =
"block";
941 document.onclick = null;
943 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
945 for (var key in config) {
946 if (config[key].Type == 'String')
947 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
948 else if (config[key].Type == 'Int') {
949 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
950 if (config[key].Value <
0)
951 config[key].Value = config[key].Default;
953 else if (config[key].Type == 'Bool')
954 config[key].Value = document.forms[
0].elements[
"settings." + key].checked;
955 else if (config[key].Type == 'UID')
956 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
957 else if (config[key].Type == 'Enum') {
958 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
959 if (config[key].ValidValues.indexOf(config[key].Value) == -
1)
960 config[key].Value = config[key].Default;
962 else if (config[key].Type == 'Array') {
963 if (key == 'excludedCalendars') {
964 config[key].Value = new Array();
965 for(var i=
0; i < calendarList.length; i++) {
966 var element = document.forms[
0].elements[
"settings." + key +
"." + calendarList[i]];
967 if (element != null && element.checked == false)
968 config[key].Value.push(calendarList[i]);
981 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
987 var settingsHtml = '
<form>';
988 for (var key in config) {
989 if (config[key].Type == 'String') {
991 if (key.substring(
0,
9) ==
"cssStyle_")
992 prefix = getLocalizedText('settings.cssStyle_prefix');
993 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 />';
995 else if (config[key].Type == 'Int')
996 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 />';
997 else if (config[key].Type == 'Bool')
998 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 />';
999 else if (config[key].Type == 'UID')
1000 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 />';
1001 else if (config[key].Type == 'Enum') {
1002 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><select name=
"settings.' + key + '" size=
"1">';
1003 for(var i =
0; i < config[key].ValidValues.length; i++)
1004 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>';
1005 settingsHtml += '
</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1007 else if (config[key].Type == 'Array') {
1008 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br />';
1009 if (key == 'excludedCalendars') {
1010 for(var i=
0; i < calendarList.length; i++) {
1011 var checked = '
checked=
"checked"';
1012 if (config[key].Value.indexOf(calendarList[i]) != -
1)
1014 settingsHtml += '
<input name=
"settings.' + key + '.' + calendarList[i] + '" type=
"checkbox" value=
"' + calendarList[i] + '" ' + checked + '
/> ' + calendarList[i] + '
<br />';
1017 settingsHtml += '
</td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1020 settingsHtml += '
<input name=
"reset" type=
"button" value=
"' + getLocalizedText('settings.restoreDefaults') + '" onclick=
"javascript:restoreDefaultSettings();showSettings();" />';
1021 settingsHtml += '
</form>';
1022 document.getElementById(
"settingsList").innerHTML = settingsHtml;
1025 function changeCssClass(classname, properties)
1027 for(var i =
0; i < document.styleSheets[
0]['cssRules'].length; i++)
1029 if (document.styleSheets[
0]['cssRules'][i].selectorText == classname) {
1030 document.styleSheets[
0].deleteRule(i);
1031 document.styleSheets[
0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[
0]['cssRules'].length);
1037 function updateCssClasses()
1039 for(var key in config) {
1040 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
1044 function getSettingsCalEntryId()
1046 if (settingsCalEntryId == null) {
1047 // check if entry already exists
1048 var listFiltering = {
1049 Type:'CalendarEntry',
1051 StartRange: new Date(
2000,
0,
1),
1052 EndRange: new Date(
2000,
0,
1),
1053 SearchText: 'ComingNext Settings|',
1057 var result = calendarService.IDataSource.GetList(listFiltering);
1058 if (result.ErrorCode) {
1059 error(result.ErrorMessage);
1062 var list = result.ReturnValue;
1063 var entry = list.getNext();
1064 if (entry != undefined) {
1065 settingsCalEntryId = entry.LocalId;
1066 log(
"settingsCalEntryId=" + settingsCalEntryId);
1068 else { // create settings item
1069 var item = new Object();
1070 item.Type =
"DayEvent";
1071 item.StartTime = new Date(
2000,
0,
1);
1072 item.Summary =
"ComingNext Settings|";
1074 var criteria = new Object();
1075 criteria.Type =
"CalendarEntry";
1076 criteria.Item = item;
1079 var result = calendarService.IDataSource.Add(criteria);
1080 if (result.ErrorCode)
1081 error(result.ErrorMessage);
1083 error(
"getSettingsCalEntryId: " + e + ', line ' + e.line);
1086 getSettingsCalEntryId();
1091 function restoreDefaultSettings()
1093 for (var key in config)
1094 config[key].Value = config[key].Default;
1097 function loadSettings()
1099 getSettingsCalEntryId();
1100 var listFiltering = {
1101 Type:'CalendarEntry',
1103 LocalId: settingsCalEntryId
1106 var result = calendarService.IDataSource.GetList(listFiltering);
1107 if (result.ErrorCode) {
1108 error(result.ErrorMessage);
1111 var entry = result.ReturnValue.getNext();
1112 if (entry != undefined) {
1113 log(
"Loading Settings...");
1114 // only reload settings if they chanced since the last reload
1115 if (settingsCache != entry.Summary)
1117 restoreDefaultSettings();
1118 var stringlist = entry.Summary.split(
"|");
1119 // skip the first two entries, those contain header and version info
1120 for(var i =
2; i < stringlist.length -
1; i++) {
1121 var pair = stringlist[i].split('=');
1123 var value = pair[
1];
1124 log('stringlist: ' + key + '=\'' + value + '\'');
1125 if (config[key].Type == 'Int')
1126 config[key].Value = Number(value);
1127 else if (config[key].Type == 'String')
1128 config[key].Value = value;
1129 else if (config[key].Type == 'Bool')
1130 config[key].Value = (value == 'true')
1131 else if (config[key].Type == 'Enum')
1132 config[key].Value = value;
1133 else if (config[key].Type == 'UID')
1134 config[key].Value = Number(value);
1135 else if (config[key].Type == 'Array') {
1136 config[key].Value = value.split(
"^");
1137 if (config[key].Value.length ==
1 && config[key].Value[
0] ==
"") {
1138 config[key].Value = [];
1142 settingsCache = entry.Summary;
1146 log(
"Settings already cached and did not change");
1150 error(
"Failed to load settings, calendar entry could not be found");
1154 function saveSettings()
1156 getSettingsCalEntryId();
1157 var item = new Object();
1158 item.Type =
"DayEvent";
1159 item.StartTime = new Date(
2000,
0,
1);
1160 item.LocalId = settingsCalEntryId;
1161 item.Summary =
"ComingNext Settings|" + version +
"|";
1163 for (var key in config) {
1164 if (config[key].Type == 'Int')
1165 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1166 else if (config[key].Type == 'String')
1167 item.Summary += key +
"=" + config[key].Value +
"|";
1168 else if (config[key].Type == 'Bool')
1169 item.Summary += key +
"=" + (config[key].Value ? 'true' : 'false') +
"|";
1170 else if (config[key].Type == 'Enum')
1171 item.Summary += key +
"=" + config[key].Value +
"|";
1172 else if (config[key].Type == 'UID')
1173 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1174 else if (config[key].Type == 'Array')
1175 item.Summary += key +
"=" + config[key].Value.join(
"^") +
"|";
1177 settingsCache = item.Summary;
1179 var criteria = new Object();
1180 criteria.Type =
"CalendarEntry";
1181 criteria.Item = item;
1183 log(
"Saving settings to calendar entry: " + item.Summary);
1185 var result = calendarService.IDataSource.Add(criteria);
1186 if (result.ErrorCode)
1187 error(result.ErrorMessage);
1189 error(
"saveSettings: " + e + ', line ' + e.line);
1192 lastReloadTime = null; // force calendar data reload on next update
1197 function toggleVisibility(elementId)
1199 if (document.getElementById(elementId).style.display ==
"none")
1200 document.getElementById(elementId).style.display =
"block";
1202 document.getElementById(elementId).style.display =
"none";
1206 function printHintBox(text)
1209 return '
<td width=
"1%" align=
"right" onclick=
"javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '
</td></tr></table>'+
1210 '
<div class=
"settingsInfo" id=
"info' + uniqueId + '">' + text + '
</div>';
1213 function showAbout()
1217 document.getElementById(
"aboutView").style.display =
"block";
1218 document.onclick = null;
1220 window.menu.setLeftSoftkeyLabel(
" ", function(){});
1221 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1227 //document.getElementById(
"aboutView").innerHTML = 'aboutView';
1228 document.getElementById(
"name").innerHTML =
"Coming Next " + version;
1231 function showHelp() {
1232 widget.openURL('http://comingnext.sf.net/help');
1235 function updateFullscreen()
1239 function showFullscreen()
1241 log(
"showFullscreen()");
1243 document.getElementById(
"fullscreenView").style.display =
"block";
1244 document.getElementById('body').className =
"backgroundFullscreen";
1246 document.onclick = launchCalendar;
1251 function getBackgroundImage()
1256 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[
0]) // internal
1257 bgImage = 'background_' + orientation + '.png';
1259 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
1263 function updateHomescreen()
1265 if (config['useBackgroundImage'].Value) {
1266 // check for screen rotation
1267 if (orientation != 'portrait' && screen.width ==
360 && screen.height ==
640) {
1268 window.widget.prepareForTransition(
"fade");
1269 orientation = 'portrait';
1270 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1271 document.getElementById('body').style.backgroundColor = 'none';
1272 window.widget.performTransition();
1273 } else if (orientation != 'landscape' && screen.width ==
640 && screen.height ==
360) {
1274 window.widget.prepareForTransition(
"fade");
1275 orientation = 'landscape';
1276 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1277 document.getElementById('body').style.backgroundColor = 'none';
1278 window.widget.performTransition();
1280 else if (document.getElementById('body').style.backgroundImage ==
"")
1282 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1287 function showHomescreen()
1289 log(
"showHomescreen()");
1291 document.getElementById(
"homescreenView").style.display =
"block";
1292 document.getElementById('body').className =
"background";
1293 document.onclick = null;
1297 function getLocalizedText(p_Txt)
1299 if (localizedText[p_Txt])
1300 return localizedText[p_Txt];
1302 return 'ERROR: missing translation for ' + p_Txt;
1305 function showUpdate()
1309 document.getElementById(
"updateView").style.display =
"block";
1310 document.onclick = null;
1312 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1315 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1321 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
1325 function checkForUpdate()
1327 // asynch XHR to server url
1328 reqV = new XMLHttpRequest();
1329 reqV.onreadystatechange = checkForUpdateCallback;
1330 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
1331 reqV.open(
"GET", versionURL, true);
1332 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1336 function checkForUpdateCallback()
1338 if (reqV.readyState ==
4) {
1339 if (reqV.status ==
200) {
1340 var resultXml = reqV.responseText;
1342 var div = document.getElementById(
"tmp");
1343 div.innerHTML = resultXml;
1344 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
1345 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
1347 if (version != newVersion) {
1348 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1351 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1356 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1361 function hideViews()
1363 document.getElementById(
"homescreenView").style.display =
"none";
1364 document.getElementById(
"fullscreenView").style.display =
"none";
1365 document.getElementById(
"aboutView").style.display =
"none";
1366 document.getElementById(
"settingsView").style.display =
"none";
1367 document.getElementById(
"updateView").style.display =
"none";
1370 function listCalendars()
1376 DefaultCalendar: false
1380 var calendarsResult = calendarService.IDataSource.GetList(criteria);
1381 if (calendarsResult.ErrorCode !=
0)
1382 throw(
"Error fetching list of calendars: " + calendarsResult.ErrorCode + ': ' + calendarsResult.ErrorMessage);
1383 var calendarListIterator = calendarsResult.ReturnValue;
1388 while (( item = calendarListIterator.getNext()) != undefined ) {
1389 calendars[count++] = item;
1391 log(
"Available Calendars: " + calendars.join(
", "));
1394 error('listing calendars:' + e + ', line ' + e.line);
1399 // Copies all objects and their properties to an array. Data is copied so nothing gets lost when the reference is removed
1400 // 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
1401 function listToArray(list, calendarName)
1403 var array = new Array();
1406 while (( item = list.getNext()) != undefined ) {
1407 var itemCopy = new Object();
1408 for(var i=
0; i < entryFields.length; i++) {
1409 itemCopy[entryFields[i]] = item[entryFields[i]];
1411 // for some reason, the CalendarName property is never correctly queried, so we assign it manually here
1412 if (!itemCopy['CalendarName']) {
1413 itemCopy['CalendarName'] = calendarName;
1415 array.push(itemCopy);
1416 txt += array[array.length -
1].Summary +
", ";
1418 log(
"listToArray(): " + txt);
1422 function sortCalendarEntries(a, b)
1425 log(
"sortCalendarEntries(" + a.Summary +
"," + b.Summary +
")");
1427 if (a.InstanceStartTime != null) {
1428 atime = a.InstanceStartTime;
1430 else if (a.StartTime != null) {
1431 atime = a.StartTime;
1433 else if (a.InstanceEndTime != null) {
1434 atime = a.InstanceEndTime;
1436 else if (a.EndTime != null) {
1440 if (b.InstanceStartTime != null) {
1441 btime = b.InstanceStartTime;
1443 else if (b.StartTime != null) {
1444 btime = b.StartTime;
1446 else if (b.InstanceEndTime != null) {
1447 btime = b.InstanceEndTime;
1449 else if (b.EndTime != null) {
1453 if (atime && btime) {
1455 atime = parseDate(atime);
1456 btime = parseDate(btime);
1458 // sort by date & time
1459 if (atime < btime) {
1462 else if (atime
> btime) {
1466 else if (a.Type != b.Type) {
1467 if (a.Type < b.Type) {
1470 else if (a.Type
> b.Type) {
1474 // sort by description
1475 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1476 if (a.Summary < b.Summary) {
1479 else if (a.Summary
> b.Summary) {
1484 // NOTE: events my have no date information at all. In that case, we list events without date first
1485 else if (atime && !btime) {
1488 else if (!atime && btime) {
1491 else if (!atime && !btime) {
1493 if (a.Type != b.Type) {
1494 if (a.Type < b.Type) {
1497 else if (a.Type
> b.Type) {
1501 // sort by description
1502 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1503 if (a.Summary < b.Summary) {
1506 else if (a.Summary
> b.Summary) {
1515 function updateCalendarColors()
1518 calendarColors = [];
1519 if (calendarList.length
> maxColors) {
1520 log(
"updateCalendarColors(): Warning: more calendars than available indicator colors");
1522 for(var i=
0; i < calendarList.length; i++) {
1523 calendarColors[calendarList[i]] = (i % maxColors) +
1;
1527 function log(message) {
1528 if (config['enableLogging'].Value) {
1529 console.info(message);
1535 <style type=
"text/css">
1537 table { margin:
0px; padding:
0px; border-spacing:
0px; }
1538 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
1539 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1540 .settingsInfo { display:none; font-style:italic; }
1541 .title { font-weight:bold; font-size:
14pt; }
1542 .textInput { width:
90%; }
1543 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1544 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
1545 #calendarList { position:absolute; left:
5px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
1546 #name { text-align:center; }
1547 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1548 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1553 <body id=
"body" class=
"background">
1554 <div id=
"homescreenView">
1555 <div id=
"calendarList"></div>
1557 <div id=
"fullscreenView" style=
"display:none;">
1558 <img src=
"Icon.png" id=
"smallappicon">
1559 <h1 class=
"title">Coming Next
</h1>
1561 <div id=
"fullscreenCalendarList">loading...
</div>
1563 <div id=
"settingsView" style=
"display:none">
1564 <img src=
"Icon.png" id=
"smallappicon">
1565 <h1 id=
"settingsTitle" class=
"title">Settings
</h1>
1567 <div id=
"settingsList"></div>
1569 <div id=
"aboutView" style=
"display:none">
1570 <img src=
"Icon.png" id=
"appicon">
1571 <h1 id=
"name">Coming Next
</h1>
1573 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1574 <p>Contributions:
</p>
1575 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1576 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1577 <p class=
"credits">Christophe Milsent (translation support & french translation)
</p>
1578 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation)
</p>
1579 <p class=
"credits">Tokeda (russian translation)
</p>
1580 <p class=
"credits">Marcella Ferrari (italian translation)
</p>
1581 <p class=
"credits">Venos (italian translation)
</p>
1582 <p>This software is open source and licensed under the GPLv3.
</p>
1583 <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>
1586 <div id=
"updateView" style=
"display:none">
1587 <img src=
"Icon.png" id=
"smallappicon">
1588 <h1 class=
"title">Check for update
</h1>
1590 <div id=
"currentVersion">Coming Next ??
</div>
1591 <div id=
"updateDiv"></div>
1592 <div id=
"tmp" style=
"display:none;"></div>