1 <?xml version=
"1.0" encoding=
"UTF-8"?>
2 <!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns=
"http://www.w3.org/1999/xhtml">
6 <title>Coming Next
</title>
8 <style type=
"text/css">
9 /* The following classes can be modified by widget settings */
10 .background { color:#ffffff; background-color:#
000000 }
11 .backgroundFullscreen { color:#ffffff; background-color:#
000000 }
14 .today { color:#ff0000 }
15 .tomorrow { color:#
0000ff }
17 .now { color:#ff00ff }
19 .icon { width:
15px; height:
15px }
20 .overdue { color:#ffff00 }
21 .calendar1 { background-color:#
0757cf }
22 .calendar2 { background-color:#
579f37 }
23 .calendar3 { background-color:#ff9f07 }
24 .calendar4 { background-color:#af8fef }
25 .calendar5 { background-color:#
57afbf }
26 .calendar6 { background-color:#
9fdf57 }
29 <script type=
"text/javascript" src=
"localizedTextStrings.js" charset=
"utf-8" />
32 // valid types for the config object are 'Int', 'Bool', 'String', 'Enum', 'UID', 'Array'
34 monthRange: { Type: 'Int', Default:
2, Value:
2,},
35 includeTodos: { Type: 'Bool', Default: true, Value: true,},
36 useBackgroundImage: { Type: 'Bool', Default: true, Value: true,},
37 backgroundImageLocation: { Type: 'Enum', Default: 'internal', Value: 'internal', ValidValues: ['internal', 'external']},
38 showCombinedDateTime: { Type: 'Bool', Default: false, Value: false,},
39 showLocation: { Type: 'Bool', Default: true, Value: true,},
40 showTodayAsText: { Type: 'Bool', Default: true, Value: true,},
41 todayText: { Type: 'String', Default: getLocalizedText('settings.default.todayText'), Value: getLocalizedText('settings.default.todayText'),},
42 tomorrowText: { Type: 'String', Default: getLocalizedText('settings.default.tomorrowText'), Value: getLocalizedText('settings.default.tomorrowText'),},
43 showNowAsText: { Type: 'Bool', Default: true, Value: true,},
44 nowText: { Type: 'String', Default: getLocalizedText('settings.default.nowText'), Value: getLocalizedText('settings.default.nowText'),},
45 markOverdueTodos: { Type: 'Bool', Default: true, Value: true,},
46 overdueText: {Type: 'String', Default: getLocalizedText('settings.default.overdueText'), Value: getLocalizedText('settings.default.overdueText'),},
47 dateSeparator: { Type: 'String', Default: getLocalizedText('settings.default.dateSeparator'), Value: getLocalizedText('settings.default.dateSeparator'),},
48 dateFormat: { Type: 'Enum', Default: 'auto', Value: 'auto', ValidValues: ['auto', 'DDMM', 'MMDD'],},
49 weekDayLength: { Type: 'Int', Default:
2, Value:
2,},
50 updateDataInterval: { Type: 'Int', Default:
5, Value:
5,},
51 calendarApp: { Type: 'UID', Default:
0x10005901, Value:
0x10005901,},
52 eventsPerWidget: { Type: 'Int', Default:
4, Value:
4,},
53 showNothingText: { Type: 'Bool', Default: true, Value: true,},
54 nothingText: { Type: 'String', Default: getLocalizedText('settings.default.nothingText'), Value: getLocalizedText('settings.default.nothingText'),},
55 enableDaylightSaving: { Type: 'Bool', Default: true, Value: true,},
56 daylightSavingOffset: { Type: 'Int', Default:
1, Value:
1,},
57 hideWidgetOnCalendarOpen: { Type: 'Bool', Default: false, Value: false,},
58 showCalendarIndicator: { Type: 'Bool', Default: true, Value: true,},
59 excludedCalendars: { Type: 'Array', Default: [], Value: [],},
60 enableLogging: { Type: 'Bool', Default: false, Value: false,},
61 cssStyle_background: { Type: 'String', Default: 'color:#ffffff; background-color:#
000000', Value: 'color:#ffffff; background-color:#
000000',},
62 cssStyle_backgroundFullscreen: { Type: 'String', Default: 'color:#ffffff; background-color:#
000000', Value: 'color:#ffffff; background-color:#
000000',},
63 cssStyle_weekDay: { Type: 'String', Default: '', Value: '',},
64 cssStyle_date: { Type: 'String', Default: '', Value: '',},
65 cssStyle_today: { Type: 'String', Default: 'color:#ff0000', Value: 'color:#ff0000',},
66 cssStyle_tomorrow: { Type: 'String', Default: 'color:#
0000ff', Value: 'color:#
0000ff',},
67 cssStyle_time: { Type: 'String', Default: '', Value: '',},
68 cssStyle_now: { Type: 'String', Default: 'color:#ff00ff', Value: 'color:#ff00ff',},
69 cssStyle_description: { Type: 'String', Default: '', Value: '',},
70 cssStyle_icon: { Type: 'String', Default: 'width:
15px; height:
15px', Value: 'width:
15px; height:
15px',},
71 cssStyle_overdue: { Type: 'String', Default: 'color:#ffff00', Value: 'color:#ffff00',},
72 cssStyle_calendar1: { Type: 'String', Default: 'background-color:#
0757cf', Value: 'background-color:#
0757cf',},
73 cssStyle_calendar2: { Type: 'String', Default: 'background-color:#
579f37', Value: 'background-color:#
579f37',},
74 cssStyle_calendar3: { Type: 'String', Default: 'background-color:#ff9f07', Value: 'background-color:#ff9f07',},
75 cssStyle_calendar4: { Type: 'String', Default: 'background-color:#af8fef', Value: 'background-color:#af8fef',},
76 cssStyle_calendar5: { Type: 'String', Default: 'background-color:#
57afbf', Value: 'background-color:#
57afbf',},
77 cssStyle_calendar6: { Type: 'String', Default: 'background-color:#
9fdf57', Value: 'background-color:#
9fdf57',},
82 //-------------------------------------------------------
83 // Nothing of interest from here on...
84 //-------------------------------------------------------
85 var panelNum =
0; // use
1 for second panel
87 var versionURL =
"http://comingnext.sourceforge.net/version.xml";
88 var calendarService = null;
89 var cacheEntriesHtml = [];
90 var months_translated = [];
93 var mode =
0; //
0 = homescreen,
1 = fullscreen,
2 = settings,
3 = about,
4 = check for update
95 var settingsCalEntryId = null;
96 var settingsCache = null;
97 var notificationRequests = new Array();
98 var calendarList = [];
99 var calendarColors = [];
100 var updateTimer = null;
101 var screenRotationTimer = null;
102 var lastUpdateTime = now; // last time we updated the display
103 var lastReloadTime = null; // last time we fetched calendar data
104 var reloadInterval =
6 *
60 *
60 *
1000; // =
6 hours; time interval for reloading calendar data
105 var errorOccured = false;
106 var entryLists = null; // stores all fetched calendar entries until data is refreshed
108 // vars for daylight saving time
109 var summertime = false; // true, if current date is in summer, false if in winter
110 var daylightSavingDates = new Object(); // caches calculated DST winter and summer time shift dates
112 // this is a list of data fields a calendar event can have
126 function isLeapYear( year ) {
127 if (( year %
4 ==
0 && year %
100 !=
0 ) || year %
400 ==
0 )
133 function calcLeapYear(year, days)
135 if (isLeapYear(year))
141 function subToSunday(myDate, year, days, prevMonthDays)
143 for (i = myDate.getDay(); i
> 0 ;i--)
145 days -= prevMonthDays;
146 days = isLeapYear(year) ? --days : days;
150 function isSummertime(curDate)
155 // if we already calculated DST summer and winter time dates for this year, use cached values
156 var dst = daylightSavingDates[curDate.getFullYear()];
158 var thisYearS = new Date(curDate.getFullYear(),
3,
0,
0,
0,
0 );
159 var thisYearW = new Date(curDate.getFullYear(),
10,
0,
0,
0,
0 );
160 var nextYearS = new Date(curDate.getFullYear() +
1,
3,
0,
0,
0,
0 );
161 var nextYearW = new Date(curDate.getFullYear() +
1,
10,
0,
0,
0,
0 );
163 thisYearSDays = nextYearSDays =
90;
164 thisYearWDays = nextYearWDays =
304;
166 thisYearSDays = calcLeapYear(curDate.getFullYear(), thisYearSDays);
167 thisYearWDays = calcLeapYear(curDate.getFullYear(), thisYearWDays);
168 nextYearSDays = calcLeapYear(curDate.getFullYear() +
1, nextYearSDays);
169 nextYearWDays = calcLeapYear(curDate.getFullYear() +
1, nextYearWDays);
171 thisYearSDays = subToSunday(thisYearS, curDate.getFullYear(), thisYearSDays,
59);
172 thisYearWDays = subToSunday(thisYearW, curDate.getFullYear(), thisYearWDays,
273);
173 nextYearSDays = subToSunday(nextYearS, curDate.getFullYear() +
1, nextYearSDays,
59);
174 nextYearWDays = subToSunday(nextYearW, curDate.getFullYear() +
1, nextYearWDays,
273);
177 Summer: new Date (curDate.getFullYear(),
03-
1, thisYearSDays,
2,
0,
0),
178 Winter: new Date (curDate.getFullYear(),
10-
1, thisYearWDays,
2,
0,
0),
180 daylightSavingDates[curDate.getFullYear()] = dst;
183 if (dst.Summer < curDate)
185 if (dst.Winter < curDate)
187 if (summer && !winter)
193 function error(message)
195 console.info('Error: ' + message);
196 document.getElementById(
"calendarList").innerHTML = 'Error: ' + message;
197 document.getElementById(
"fullscreenCalendarList").innerHTML = 'Error: ' + message;
199 document.onclick = null;
202 function areDatesEqual(date1, date2)
204 return (date1.getFullYear() == date2.getFullYear() &&
205 date1.getMonth() == date2.getMonth() &&
206 date1.getDate() == date2.getDate());
209 function isTomorrow(date)
211 // tommorow = now +
1 day
212 // ToDo: some days can be shorter as
24 hours(daylight saving change day)
213 return areDatesEqual(date, new Date (now.getTime() +
24*
60*
60*
1000));
216 function isToday(date)
218 return areDatesEqual(date, now);
221 function collectLocales()
223 var tmpyear =
2000 + panelNum;
226 if (months_translated.length
> 0)
228 for (month =
0; month <
12; month++) {
229 var startDate = new Date(tmpyear, month,
15);
231 var item = new Object();
232 item.Type =
"DayEvent";
233 item.StartTime = startDate;
234 item.Summary =
"__temp" + month;
236 var criteria = new Object();
237 criteria.Type =
"CalendarEntry";
238 criteria.Item = item;
241 var result = calendarService.IDataSource.Add(criteria);
242 if (result.ErrorCode)
243 error(result.ErrorMessage);
245 error(
"collectLocales: " + e + ', line ' + e.line);
249 var startTime = new Date(tmpyear,
0,
1);
250 var endTime = new Date(tmpyear,
11,
31);
251 var listFiltering = {
252 Type:'CalendarEntry',
254 StartRange: startTime,
256 SearchText: '__temp',
260 var result = calendarService.IDataSource.GetList(listFiltering);
261 if (result.ErrorCode) {
262 error(result.ErrorMessage);
265 var list = result.ReturnValue;
267 error(e + ', line ' + e.line);
270 var ids = new Array();
276 while (list && (entry = list.getNext()) != undefined) {
277 dateArr = entry.StartTime.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
278 var day = dateArr[
1];
279 var month = dateArr[
2];
280 var year = dateArr[
3];
282 // make sure month is set properly
283 if (isNaN(parseInt(day))) {
287 } else if (isNaN(parseInt(year))) {
293 log(entry.StartTime + ' -
> ' + month + ' ' + counter);
294 ids[counter] = entry.id;
295 months_translated[month] = counter +
1;
299 error(e + ', line ' + e.line);
304 var criteria = new Object();
305 criteria.Type =
"CalendarEntry";
310 var result = calendarService.IDataSource.Delete(criteria);
311 if (result.ErrorCode)
312 error(result.ErrorMessage);
314 error('deleting temp calendar entries:' + e + ', line ' + e.line);
319 function requestNotification()
321 var criteria = new Object();
322 criteria.Type =
"CalendarEntry";
323 criteria.Filter = new Object();
324 for(var i=
0; i < calendarList.length; i++) {
325 criteria.Filter.CalendarName = calendarList[i];
327 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria, callback);
328 if (notificationRequest.ErrorCode)
329 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
330 notificationRequests.push(notificationRequest);
332 error(
"requestNotification: " + e + ', line ' + e.line);
336 var criteria2 = new Object();
337 criteria2.Type =
"CalendarEntry";
338 criteria2.Filter = new Object();
339 criteria2.Filter.LocalIdList = new Array();
340 criteria2.Filter.LocalIdList[
0] = settingsCalEntryId;
342 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria2, settingsCallback);
343 if (notificationRequest.ErrorCode)
344 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
345 notificationRequests.push(notificationRequest);
347 error(
"requestNotification: " + e + ', line ' + e.line);
351 function cancelNotification()
353 for(var i=
0; i < notificationRequests.length; i++) {
355 var result = calendarService.IDataSource.Cancel(notificationRequests[i]);
356 if (result.ErrorCode)
357 error('cancelNotification failed with error code ' + result.ErrorCode);
359 error(
"cancelNotification: " + e + ', line ' + e.line);
364 function callback(transId, eventCode, result)
366 log(
"callback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
367 lastReloadTime = null; // force calendar data reload on next update
371 function settingsCallback(transId, eventCode, result)
373 log(
"settingsCallback(): panelNum: " + panelNum +
" transId: " + transId +
" eventCode: " + eventCode +
" result.ErrorCode: " + result.ErrorCode);
377 function parseDate(dateString)
380 Dates my look very differently. Also keep in mind that the names are localized!!! These are the possibilities depending on the users date format setting:
381 Wednesday,
26 August,
2009 24:
00:
00
382 Wednesday,
26 August,
2009 12:
00:
00 am
383 Wednesday, August
26,
2009 12:
00:
00 am
384 Wednesday,
2009 August,
26 12:
00:
00 am
385 Wednesday,
2009 August,
28 8.00.00 pm
386 Wednesday,
2009 August,
28 08:
00:
00 PM
389 if (dateString ==
"" || dateString == null)
391 var dateArr = dateString.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
392 if (dateArr.length !=
5 && dateArr.length !=
6)
396 var weekDay = dateArr[
0];
397 var day = dateArr[
1];
398 var month = dateArr[
2];
399 var year = dateArr[
3];
400 // make sure month is set properly
401 if (isNaN(parseInt(day))) {
405 } else if (isNaN(parseInt(year))) {
410 // make sure day and year are set properly
411 if (Number(day)
> Number(year)) {
416 month = months_translated[month];
419 var timeArr = dateArr[
4].split(':');
420 if (timeArr.length !=
3)
422 var hours = Number(timeArr[
0]);
423 var minutes = Number(timeArr[
1]);
424 var seconds = Number(timeArr[
2]);
425 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'pm' && hours <
12)
427 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'am' && hours ==
12)
430 var result = new Date(year, month -
1, day, hours, minutes, seconds);
432 // take care of daylight saving time
433 if (config['enableDaylightSaving'].Value) {
435 // determine if date is in summer or winter time
436 var dateSummerTime = isSummertime(result);
438 // work around bug in Nokias calendar api resulting in dates within a different DST to be off by
1 hour
439 if (summertime && !dateSummerTime) {
440 result = new Date(result.getTime() -
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // -
1 hour
441 log('parseDate(): fixing time -
1h: ' + result);
443 else if (!summertime && dateSummerTime) {
444 result = new Date(result.getTime() +
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // +
1 hour
445 log('parseDate(): fixing time +
1h: ' + result);
452 // returns a short date as string (
"31.12" or
"12.31") based on the format string which should look like
"Wednesday, 26 August, 2009 12:00:00 am"
453 function formatDate(date, format)
455 var day = date.getDate().toString();
456 var month = (date.getMonth() +
1).toString();
457 while (day.length <
2) { day = '
0' + day; }
458 while (month.length <
2) { month = '
0' + month; }
460 if (config['showTodayAsText'].Value && isToday(date))
461 return '
<span class=
"today">' + config['todayText'].Value + '
</span>';
462 if (config['showTodayAsText'].Value && isTomorrow(date))
463 return '
<span class=
"tomorrow">' + config['tomorrowText'].Value + '
</span>';
465 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
466 if (dateArr.length !=
5 && dateArr.length !=
6) {
467 // we don't know how to format this
468 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
469 return day + config['dateSeparator'].Value + month;
471 return month + config['dateSeparator'].Value + day;
475 if (config['dateFormat'].Value == 'MMDD')
477 else if (config['dateFormat'].Value == 'DDMM')
480 // config['dateFormat'].Value == 'auto', try to detect system setting
482 var day_ = dateArr[
1];
483 var month_ = dateArr[
2];
484 var year_ = dateArr[
3];
485 // make sure month is set properly
486 if (isNaN(parseInt(day_))) {
491 } else if (isNaN(parseInt(year_))) {
497 // make sure day and year are set properly
498 if (Number(day_)
> Number(year_))
503 return day + config['dateSeparator'].Value + month;
505 return month + config['dateSeparator'].Value + day;
508 function formatTime(date)
510 // date is a Date() object
511 date.setSeconds(
0); // we don't care about seconds
512 var time = date.toLocaleTimeString().replace(/[\.:]
00/, ''); // remove seconds from string
513 if (time.replace(/\./, ':').split(':')[
0].length <
2)
515 if (config['showNowAsText'].Value && date.getTime() == now.getTime())
516 time = '
<span class=
"now">' + config['nowText'].Value + '
</span>';
520 function updateData()
527 // check if we got additional or less calendars since our last update
528 var newCalendarList = listCalendars();
529 if (newCalendarList.length != calendarList.length) {
530 calendarList = newCalendarList;
531 updateCalendarColors();
532 cancelNotification();
533 requestNotification();
534 lastReloadTime = null; // force calendar data reload on this update
539 // only reload calendar data every
6 hours, visual updates occure more often
540 if (!lastReloadTime || now.getTime() - lastReloadTime.getTime()
> reloadInterval) {
541 log('updateData(): reloading calendar data');
543 // meetings have time
544 // note: anniveraries have a start time of
12:
00am. So since we want to include them, we have to query the whole day and check if events have passed later
545 summertime = isSummertime(now); // cache summer time info for today
546 var meetingList = [];
547 for(var i=
0; i < calendarList.length; i++) {
548 // ignore excluded calendars
549 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
551 var meetingListFiltering = {
552 Type:'CalendarEntry',
554 CalendarName: calendarList[i],
555 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
556 EndRange: (new Date(now.getFullYear(), now.getMonth() + config['monthRange'].Value, now.getDate(),
0,
0,
0))
559 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
560 if (meetingResult.ErrorCode !=
0)
561 throw(
"Error fetching calendar data: " + meetingResult.ErrorCode + ': ' + meetingResult.ErrorMessage);
562 var list = meetingResult.ReturnValue;
563 meetingList = meetingList.concat(listToArray(list, calendarList[i]));
565 log(
"updateData(): meetingList.sort()");
566 meetingList.sort(sortCalendarEntries);
568 // todos don't, they start on
00:
00 hrs., but should be visible anyway
569 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
570 if (config['includeTodos'].Value) {
571 var todayTodoList = [];
572 for(var i=
0; i < calendarList.length; i++) {
573 // ignore excluded calendars
574 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
576 var todayTodoListFiltering = {
577 Type:'CalendarEntry',
579 CalendarName: calendarList[i],
581 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
582 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
585 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
586 var list = todayTodoResult.ReturnValue;
587 todayTodoList = todayTodoList.concat(listToArray(list, calendarList[i]));
589 log(
"updateData(): todayTodoList.sort()");
590 todayTodoList.sort(sortCalendarEntries);
591 entryLists = [todayTodoList, meetingList];
593 entryLists = [meetingList];
595 lastReloadTime = new Date();
597 error('loading Calendar items list:' + e + ', line ' + e.line);
607 var fontsize = 'normal';
609 if (config['eventsPerWidget'].Value ==
3) {
611 changeCssClass('.icon', 'width:
20px; height:
20px');
613 else if (config['eventsPerWidget'].Value ==
5) {
615 changeCssClass('.icon', 'width:
10px; height:
10px');
617 else if (config['eventsPerWidget'].Value ==
6) {
619 changeCssClass('.icon', 'width:
8px; height:
8px');
623 changeCssClass('.icon', config['cssStyle_icon'].Value);
624 var entriesHtml = '
<table style=
"font-size:' + fontsize + ';">';
628 max = (panelNum +
1) * config['eventsPerWidget'].Value;
630 max =
30; // we can display a lot more events in fullscreen mode
632 if (config['enableLogging'].Value) {
634 for (var i=
0; i < entryLists.length; i++) {
635 listinfo = listinfo +
" " + entryLists[i].length;
636 var entrieslist =
"";
637 for (var j=
0; j < entryLists[i].length; j++) {
638 entrieslist += entryLists[i][j].Summary +
", ";
640 log(
"updateData(): entrieslist: " + entrieslist);
642 log(
"updateData(): inner loop, " + entryLists.length +
" lists, [" + listinfo +
"] entries");
645 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
646 for (var i=
0; counter < max && i < entryLists.length; i++) {
647 for (var j=
0; (counter < max) && (j < entryLists[i].length); j++) {
648 entry = entryLists[i][j];
651 // output event info for debugging
652 var entryInfo =
"event: ";
653 for(var k=
0; k < entryFields.length; ++k) {
654 if (entry[entryFields[k]] != undefined) {
655 entryInfo += entryFields[k] +
"=" + entry[entryFields[k]] +
",";
660 // we don't want ToDos when includeTodos == false or when they are completed
661 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !config['includeTodos'].Value)) {
662 log('skipping ' + entry.id );
667 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
668 if (eventIds[entry.id] ==
1 && entry.Type == 'ToDo') {
669 log('skipped (already included) ' + entry.id);
673 eventIds[entry.id] =
1;
675 // summary can be undefined!
676 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
677 if (entry.Type == 'Meeting' && entry.Location != '' && config['showLocation'].Value)
678 Summary += ', ' + entry.Location;
680 // fix by yves: determine start and end dates/times
681 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
682 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
684 // there can be ToDos that have no date at all!
685 if (entry.Type == 'ToDo' && entry.EndTime == null)
686 entryDate =
""; // this will cause parseDate(entryDate) to return null;
688 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
690 // Convert date/time string to Date object
691 var date = parseDate(entryDate);
692 log('date: ' + date);
693 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
694 log('endDate: ' + endDate);
696 // check if meeting event has already passed
697 if (entry.Type == 'Meeting') {
698 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
699 if (now.getTime()
> compareTime) {
700 log('skipping Meeting (already passed) ' + entry.id);
702 eventIds[entry.id] =
0;
707 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
708 if (entry.Type == 'Anniversary') {
709 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
710 if (date.getTime() < tmp.getTime()) {
711 log('skipping Anniversary (already passed) ' + entry.id);
713 eventIds[entry.id] =
0;
718 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
719 if (entry.Type == 'DayEvent' && endDate != null) {
720 endDate.setMinutes(endDate.getMinutes() -
1);
721 log('fixing DayEvent endDate: ' + endDate);
722 if (now.getTime()
> endDate.getTime()) {
723 log('event already passed ' + entry.id);
725 eventIds[entry.id] =
0;
730 // check if the event is currently taking place
731 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
732 // check if we are between start and endtime
733 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
734 date = now; // change appointment date/time to now
735 log('event is currently taking place: ' + date);
739 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
740 if (mode ==
0 && panelNum
> 0 && counter < panelNum * config['eventsPerWidget'].Value +
1) {
741 log('skipping (already in first widget) ' + entry.id);
745 // mark overdue todos
747 if (entry.Type == 'ToDo' && date != null) {
748 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
0,
0,
0);
749 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
750 if (tmp1.getTime() < tmp2.getTime()) {
755 // generate html output
756 entriesHtml += '
<tr>';
757 if (config['showCalendarIndicator'].Value && calendarList.length - config['excludedCalendars'].Value.length
> 1) {
758 entriesHtml += '
<td><span class=
"calendar' + calendarColors[entry.CalendarName] + '"> </span></td>';
760 entriesHtml += '
<td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
762 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
763 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
765 var weekDay = date.toLocaleDateString().substr(
0,config['weekDayLength'].Value);
766 var time = formatTime(date);
767 var dateStr = formatDate(date, entryDate);
768 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
769 dateStr = '
<span class=
"overdue">' + config['overdueText'].Value + '
</span>';
770 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
771 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
772 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
773 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
775 entriesHtml += '
<td class=
"weekDay" width=
"1px">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
776 } else if (entry.Type == 'Meeting') {
777 if (config['showCombinedDateTime'].Value) {
779 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
780 else if (isTomorrow(date))
781 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
783 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
785 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
786 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
788 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
792 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
795 entriesHtml += '
</table>';
796 if (config['showNothingText'].Value && entriesHtml == '
<table></table>') {
797 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
798 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '
</div>';
800 if (cacheEntriesHtml != entriesHtml) {
802 document.getElementById('calendarList').innerHTML = entriesHtml;
804 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
805 cacheEntriesHtml = entriesHtml;
808 lastUpdateTime = new Date();
810 error('displaying list:' + e + ', line ' + e.line);
815 // called by handleOnShow() and onResize events
816 function updateScreen()
818 log('updateScreen()');
820 // check if opening fullscreen
821 if( window.innerHeight
> 91 && mode ==
0) {
823 cacheEntriesHtml = '';
824 document.getElementById('body').style.backgroundImage =
"";
827 else if (window.innerHeight <=
91 && mode !=
0) {
829 cacheEntriesHtml = '';
834 updateHomescreen(); // check for screen rotation
839 function handleOnShow()
843 var time = new Date();
844 if (time.getTime() - lastUpdateTime.getTime()
> config['updateDataInterval'].Value *
60 *
1000) {
845 log('updateScreen(): force updateData() because last update was too long ago (' + (time.getTime() - lastUpdateTime.getTime()) /
1000 + 's)');
848 setUpdateTimer(); // reinitialize update timer
852 function launchCalendar()
855 widget.openApplication(config['calendarApp'].Value,
"");
856 if (config['hideWidgetOnCalendarOpen'].Value)
859 error('starting Calendar App');
866 log('New widget instance starting up...');
869 // call calendar service
870 if (device !=
"undefined")
871 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
873 throw('device object does not exist');
875 error('loading Calendar service: ' + e + ', line ' + e.line + '
<br /><a onclick=
"widget.openURL(\'http://comingnext.sf.net/help\'); return false;" href=
"http://comingnext.sf.net/help">' + getLocalizedText('menu.help') + '
</a>');
879 calendarList = listCalendars();
881 updateCalendarColors();
884 requestNotification();
885 document.getElementById(
"settingsTitle").innerHTML = getLocalizedText('menu.settings');
887 if (window.innerHeight
> 91) {
888 mode =
0; // we're starting fullscreen, we set mode to homescreen in order to let updateScreen() do all the work for us
893 log(
"init(): updateScreen()");
895 if (config['useBackgroundImage'].Value)
896 // check for screen rotation every
1 secs
897 screenRotationTimer = window.setInterval('checkOrientation()',
1000 *
1);
899 // call updateScreen() when widget changes from background to forground
900 window.widget.onshow = handleOnShow;
902 log(
"init(): finished...");
905 function checkOrientation()
909 updateHomescreen(); // check for screen rotation
912 function setUpdateTimer()
914 updateTimer = window.setInterval('updateTimerCallback()',
1000 *
60 * config['updateDataInterval'].Value);
917 function clearUpdateTimer()
919 window.clearInterval(updateTimer);
922 function updateTimerCallback()
924 log(
"updateTimerCallback()");
928 function createMenu()
930 window.menu.setLeftSoftkeyLabel(
"",null);
931 window.menu.setRightSoftkeyLabel(
"",null);
933 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
934 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
935 var menuHelp = new MenuItem(getLocalizedText('menu.help'), id++);
936 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
937 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
938 menuSettings.onSelect = showSettings;
939 menuAbout.onSelect = showAbout;
940 menuCallApp.onSelect = launchCalendar;
941 menuUpdate.onSelect = showUpdate;
942 menuHelp.onSelect = showHelp;
944 window.menu.append(menuCallApp);
945 window.menu.append(menuSettings);
946 window.menu.append(menuHelp);
947 window.menu.append(menuUpdate);
948 window.menu.append(menuAbout);
951 function showSettings()
955 document.getElementById(
"settingsView").style.display =
"block";
956 document.onclick = null;
958 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
960 for (var key in config) {
961 if (config[key].Type == 'String')
962 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
963 else if (config[key].Type == 'Int') {
964 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
965 if (config[key].Value <
0 || isNaN(config[key].Value))
966 config[key].Value = config[key].Default;
968 else if (config[key].Type == 'Bool')
969 config[key].Value = document.forms[
0].elements[
"settings." + key].checked;
970 else if (config[key].Type == 'UID') {
971 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
972 if (isNaN(config[key].Value))
973 config[key].Value = config[key].Default;
975 else if (config[key].Type == 'Enum') {
976 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
977 if (config[key].ValidValues.indexOf(config[key].Value) == -
1)
978 config[key].Value = config[key].Default;
980 else if (config[key].Type == 'Array') {
981 if (key == 'excludedCalendars') {
982 config[key].Value = new Array();
983 for(var i=
0; i < calendarList.length; i++) {
984 var element = document.forms[
0].elements[
"settings." + key +
"." + calendarList[i]];
985 if (element != null && element.checked == false)
986 config[key].Value.push(calendarList[i]);
999 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
1005 var settingsHtml = '
<form>';
1006 for (var key in config) {
1007 if (config[key].Type == 'String') {
1009 if (key.substring(
0,
9) ==
"cssStyle_")
1010 prefix = getLocalizedText('settings.cssStyle_prefix');
1011 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 />';
1013 else if (config[key].Type == 'Int')
1014 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 />';
1015 else if (config[key].Type == 'Bool')
1016 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 />';
1017 else if (config[key].Type == 'UID')
1018 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 />';
1019 else if (config[key].Type == 'Enum') {
1020 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><select name=
"settings.' + key + '" size=
"1">';
1021 for(var i =
0; i < config[key].ValidValues.length; i++)
1022 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>';
1023 settingsHtml += '
</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1025 else if (config[key].Type == 'Array') {
1026 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br />';
1027 if (key == 'excludedCalendars') {
1028 for(var i=
0; i < calendarList.length; i++) {
1029 var checked = '
checked=
"checked"';
1030 if (config[key].Value.indexOf(calendarList[i]) != -
1)
1032 settingsHtml += '
<input name=
"settings.' + key + '.' + calendarList[i] + '" type=
"checkbox" value=
"' + calendarList[i] + '" ' + checked + '
/> ' + calendarList[i] + '
<br />';
1035 settingsHtml += '
</td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1038 settingsHtml += '
<input name=
"reset" type=
"button" value=
"' + getLocalizedText('settings.restoreDefaults') + '" onclick=
"javascript:restoreDefaultSettings();showSettings();" />';
1039 settingsHtml += '
</form>';
1040 document.getElementById(
"settingsList").innerHTML = settingsHtml;
1043 function changeCssClass(classname, properties)
1045 for(var i =
0; i < document.styleSheets[
0]['cssRules'].length; i++)
1047 if (document.styleSheets[
0]['cssRules'][i].selectorText == classname) {
1048 document.styleSheets[
0].deleteRule(i);
1049 document.styleSheets[
0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[
0]['cssRules'].length);
1055 function updateCssClasses()
1057 for(var key in config) {
1058 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
1062 function getSettingsCalEntryId()
1064 if (settingsCalEntryId == null) {
1065 // check if entry already exists
1066 var listFiltering = {
1067 Type:'CalendarEntry',
1069 StartRange: new Date(
2000,
0,
1),
1070 EndRange: new Date(
2000,
0,
1),
1071 SearchText: 'ComingNext Settings|',
1075 var result = calendarService.IDataSource.GetList(listFiltering);
1076 if (result.ErrorCode) {
1077 error(result.ErrorMessage);
1080 var list = result.ReturnValue;
1081 var entry = list.getNext();
1082 if (entry != undefined) {
1083 settingsCalEntryId = entry.LocalId;
1084 log(
"settingsCalEntryId=" + settingsCalEntryId);
1086 else { // create settings item
1087 var item = new Object();
1088 item.Type =
"DayEvent";
1089 item.StartTime = new Date(
2000,
0,
1);
1090 item.Summary =
"ComingNext Settings|";
1092 var criteria = new Object();
1093 criteria.Type =
"CalendarEntry";
1094 criteria.Item = item;
1097 var result = calendarService.IDataSource.Add(criteria);
1098 if (result.ErrorCode)
1099 error(result.ErrorMessage);
1101 error(
"getSettingsCalEntryId: " + e + ', line ' + e.line);
1104 getSettingsCalEntryId();
1109 function restoreDefaultSettings()
1111 for (var key in config)
1112 config[key].Value = config[key].Default;
1115 function loadSettings()
1117 getSettingsCalEntryId();
1118 var listFiltering = {
1119 Type:'CalendarEntry',
1121 LocalId: settingsCalEntryId
1124 var result = calendarService.IDataSource.GetList(listFiltering);
1125 if (result.ErrorCode) {
1126 error(result.ErrorMessage);
1129 var entry = result.ReturnValue.getNext();
1130 if (entry != undefined) {
1131 log(
"Loading Settings...");
1132 // only reload settings if they chanced since the last reload
1133 if (settingsCache != entry.Summary)
1135 restoreDefaultSettings();
1136 var stringlist = entry.Summary.split(
"|");
1137 // skip the first two entries, those contain header and version info
1138 for(var i =
2; i < stringlist.length -
1; i++) {
1139 var pair = stringlist[i].split('=');
1141 var value = pair[
1];
1142 log('stringlist: ' + key + '=\'' + value + '\'');
1143 if (config[key].Type == 'Int') {
1144 config[key].Value = Number(value);
1145 if (isNaN(config[key].Value))
1146 config[key].Value = config[key].Default;
1148 else if (config[key].Type == 'String')
1149 config[key].Value = value;
1150 else if (config[key].Type == 'Bool')
1151 config[key].Value = (value == 'true')
1152 else if (config[key].Type == 'Enum')
1153 config[key].Value = value;
1154 else if (config[key].Type == 'UID') {
1155 config[key].Value = Number(value);
1156 if (isNaN(config[key].Value))
1157 config[key].Value = config[key].Default;
1159 else if (config[key].Type == 'Array') {
1160 config[key].Value = value.split(
"^");
1161 if (config[key].Value.length ==
1 && config[key].Value[
0] ==
"") {
1162 config[key].Value = [];
1166 settingsCache = entry.Summary;
1170 log(
"Settings already cached and did not change");
1174 error(
"Failed to load settings, calendar entry could not be found");
1178 function saveSettings()
1180 getSettingsCalEntryId();
1181 var item = new Object();
1182 item.Type =
"DayEvent";
1183 item.StartTime = new Date(
2000,
0,
1);
1184 item.LocalId = settingsCalEntryId;
1185 item.Summary =
"ComingNext Settings|" + version +
"|";
1187 for (var key in config) {
1188 if (config[key].Type == 'Int')
1189 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1190 else if (config[key].Type == 'String')
1191 item.Summary += key +
"=" + config[key].Value +
"|";
1192 else if (config[key].Type == 'Bool')
1193 item.Summary += key +
"=" + (config[key].Value ? 'true' : 'false') +
"|";
1194 else if (config[key].Type == 'Enum')
1195 item.Summary += key +
"=" + config[key].Value +
"|";
1196 else if (config[key].Type == 'UID')
1197 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1198 else if (config[key].Type == 'Array')
1199 item.Summary += key +
"=" + config[key].Value.join(
"^") +
"|";
1201 settingsCache = item.Summary;
1203 var criteria = new Object();
1204 criteria.Type =
"CalendarEntry";
1205 criteria.Item = item;
1207 log(
"Saving settings to calendar entry: " + item.Summary);
1209 var result = calendarService.IDataSource.Add(criteria);
1210 if (result.ErrorCode)
1211 error(result.ErrorMessage);
1213 error(
"saveSettings: " + e + ', line ' + e.line);
1216 lastReloadTime = null; // force calendar data reload on next update
1221 function toggleVisibility(elementId)
1223 if (document.getElementById(elementId).style.display ==
"none")
1224 document.getElementById(elementId).style.display =
"block";
1226 document.getElementById(elementId).style.display =
"none";
1230 function printHintBox(text)
1233 return '
<td width=
"1%" align=
"right" onclick=
"javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '
</td></tr></table>'+
1234 '
<div class=
"settingsInfo" id=
"info' + uniqueId + '">' + text + '
</div>';
1237 function showAbout()
1241 document.getElementById(
"aboutView").style.display =
"block";
1242 document.onclick = null;
1244 window.menu.setLeftSoftkeyLabel(
" ", function(){});
1245 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1251 //document.getElementById(
"aboutView").innerHTML = 'aboutView';
1252 document.getElementById(
"name").innerHTML =
"Coming Next " + version;
1255 function showHelp() {
1256 widget.openURL('http://comingnext.sf.net/help');
1259 function updateFullscreen()
1263 function showFullscreen()
1265 log(
"showFullscreen()");
1267 document.getElementById(
"fullscreenView").style.display =
"block";
1268 document.getElementById('body').className =
"backgroundFullscreen";
1270 document.onclick = launchCalendar;
1275 function getBackgroundImage()
1280 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[
0]) // internal
1281 bgImage = 'background_' + orientation + '.png';
1283 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
1287 function updateHomescreen()
1289 if (config['useBackgroundImage'].Value) {
1290 // check for screen rotation
1291 if (orientation != 'portrait' && screen.width ==
360 && screen.height ==
640) {
1292 window.widget.prepareForTransition(
"fade");
1293 orientation = 'portrait';
1294 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1295 document.getElementById('body').style.backgroundColor = 'none';
1296 window.widget.performTransition();
1297 } else if (orientation != 'landscape' && screen.width ==
640 && screen.height ==
360) {
1298 window.widget.prepareForTransition(
"fade");
1299 orientation = 'landscape';
1300 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1301 document.getElementById('body').style.backgroundColor = 'none';
1302 window.widget.performTransition();
1304 else if (document.getElementById('body').style.backgroundImage ==
"")
1306 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1311 function showHomescreen()
1313 log(
"showHomescreen()");
1315 document.getElementById(
"homescreenView").style.display =
"block";
1316 document.getElementById('body').className =
"background";
1317 document.onclick = null;
1321 function getLocalizedText(p_Txt)
1323 if (localizedText[p_Txt])
1324 return localizedText[p_Txt];
1326 return 'ERROR: missing translation for ' + p_Txt;
1329 function showUpdate()
1333 document.getElementById(
"updateView").style.display =
"block";
1334 document.onclick = null;
1336 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1339 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1345 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
1349 function checkForUpdate()
1351 // asynch XHR to server url
1352 reqV = new XMLHttpRequest();
1353 reqV.onreadystatechange = checkForUpdateCallback;
1354 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
1355 reqV.open(
"GET", versionURL, true);
1356 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1360 function checkForUpdateCallback()
1362 if (reqV.readyState ==
4) {
1363 if (reqV.status ==
200) {
1364 var resultXml = reqV.responseText;
1366 var div = document.getElementById(
"tmp");
1367 div.innerHTML = resultXml;
1368 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
1369 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
1371 if (version != newVersion) {
1372 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1375 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1380 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1385 function hideViews()
1387 document.getElementById(
"homescreenView").style.display =
"none";
1388 document.getElementById(
"fullscreenView").style.display =
"none";
1389 document.getElementById(
"aboutView").style.display =
"none";
1390 document.getElementById(
"settingsView").style.display =
"none";
1391 document.getElementById(
"updateView").style.display =
"none";
1394 function listCalendars()
1400 DefaultCalendar: false
1404 var calendarsResult = calendarService.IDataSource.GetList(criteria);
1405 if (calendarsResult.ErrorCode !=
0)
1406 throw(
"Error fetching list of calendars: " + calendarsResult.ErrorCode + ': ' + calendarsResult.ErrorMessage);
1407 var calendarListIterator = calendarsResult.ReturnValue;
1412 while (( item = calendarListIterator.getNext()) != undefined ) {
1413 calendars[count++] = item;
1415 log(
"Available Calendars: " + calendars.join(
", "));
1418 error('listing calendars:' + e + ', line ' + e.line);
1423 // Copies all objects and their properties to an array. Data is copied so nothing gets lost when the reference is removed
1424 // 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
1425 function listToArray(list, calendarName)
1427 var array = new Array();
1430 while (( item = list.getNext()) != undefined ) {
1431 var itemCopy = new Object();
1432 for(var i=
0; i < entryFields.length; i++) {
1433 itemCopy[entryFields[i]] = item[entryFields[i]];
1435 // for some reason, the CalendarName property is never correctly queried, so we assign it manually here
1436 if (!itemCopy['CalendarName']) {
1437 itemCopy['CalendarName'] = calendarName;
1439 array.push(itemCopy);
1440 txt += array[array.length -
1].Summary +
", ";
1442 log(
"listToArray(): " + txt);
1446 function sortCalendarEntries(a, b)
1449 log(
"sortCalendarEntries(" + a.Summary +
"," + b.Summary +
")");
1451 if (a.InstanceStartTime != null) {
1452 atime = a.InstanceStartTime;
1454 else if (a.StartTime != null) {
1455 atime = a.StartTime;
1457 else if (a.InstanceEndTime != null) {
1458 atime = a.InstanceEndTime;
1460 else if (a.EndTime != null) {
1464 if (b.InstanceStartTime != null) {
1465 btime = b.InstanceStartTime;
1467 else if (b.StartTime != null) {
1468 btime = b.StartTime;
1470 else if (b.InstanceEndTime != null) {
1471 btime = b.InstanceEndTime;
1473 else if (b.EndTime != null) {
1477 if (atime && btime) {
1479 atime = parseDate(atime);
1480 btime = parseDate(btime);
1482 // sort by date & time
1483 if (atime < btime) {
1486 else if (atime
> btime) {
1490 else if (a.Type != b.Type) {
1491 if (a.Type < b.Type) {
1494 else if (a.Type
> b.Type) {
1498 // sort by description
1499 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1500 if (a.Summary < b.Summary) {
1503 else if (a.Summary
> b.Summary) {
1508 // NOTE: events my have no date information at all. In that case, we list events without date first
1509 else if (atime && !btime) {
1512 else if (!atime && btime) {
1515 else if (!atime && !btime) {
1517 if (a.Type != b.Type) {
1518 if (a.Type < b.Type) {
1521 else if (a.Type
> b.Type) {
1525 // sort by description
1526 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1527 if (a.Summary < b.Summary) {
1530 else if (a.Summary
> b.Summary) {
1539 function updateCalendarColors()
1542 calendarColors = [];
1543 if (calendarList.length
> maxColors) {
1544 log(
"updateCalendarColors(): Warning: more calendars than available indicator colors");
1546 for(var i=
0; i < calendarList.length; i++) {
1547 calendarColors[calendarList[i]] = (i % maxColors) +
1;
1551 function log(message) {
1552 if (config['enableLogging'].Value) {
1553 console.info(message);
1559 <style type=
"text/css">
1561 table { margin:
0px; padding:
0px; border-spacing:
0px; }
1562 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
1563 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1564 .settingsInfo { display:none; font-style:italic; }
1565 .title { font-weight:bold; font-size:
14pt; }
1566 .textInput { width:
90%; }
1567 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1568 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
1569 #calendarList { position:absolute; left:
5px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
1570 #name { text-align:center; }
1571 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1572 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1577 <body onload=
"javascript:setTimeout('init()', 10)" onresize=
"javascript:updateScreen()" id=
"body" class=
"background">
1578 <div id=
"homescreenView">
1579 <div id=
"calendarList"></div>
1581 <div id=
"fullscreenView" style=
"display:none;">
1582 <img src=
"Icon.png" id=
"smallappicon">
1583 <h1 class=
"title">Coming Next
</h1>
1585 <div id=
"fullscreenCalendarList">loading...
</div>
1587 <div id=
"settingsView" style=
"display:none">
1588 <img src=
"Icon.png" id=
"smallappicon">
1589 <h1 id=
"settingsTitle" class=
"title">Settings
</h1>
1591 <div id=
"settingsList"></div>
1593 <div id=
"aboutView" style=
"display:none">
1594 <img src=
"Icon.png" id=
"appicon">
1595 <h1 id=
"name">Coming Next
</h1>
1597 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1598 <p>Contributions:
</p>
1599 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1600 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1601 <p class=
"credits">Christophe Milsent (translation support & french translation)
</p>
1602 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation)
</p>
1603 <p class=
"credits">Tokeda (russian translation)
</p>
1604 <p class=
"credits">Marcella Ferrari (italian translation)
</p>
1605 <p class=
"credits">Venos (italian translation)
</p>
1606 <p>This software is open source and licensed under the GPLv3.
</p>
1607 <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>
1610 <div id=
"updateView" style=
"display:none">
1611 <img src=
"Icon.png" id=
"smallappicon">
1612 <h1 class=
"title">Check for update
</h1>
1614 <div id=
"currentVersion">Coming Next ??
</div>
1615 <div id=
"updateDiv"></div>
1616 <div id=
"tmp" style=
"display:none;"></div>