1 <?xml version=
"1.0" encoding=
"UTF-8"?>
2 <!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns=
"http://www.w3.org/1999/xhtml">
6 <title>Coming Next
</title>
8 <style type=
"text/css">
9 /* The following classes can be modified by widget settings */
11 .backgroundFullscreen { }
29 <script type=
"text/javascript" src=
"localizedTextStrings.js" charset=
"utf-8" />
32 // valid types for the config object are 'Int', 'Bool', 'String', 'Enum', 'UID', 'Array'
34 monthRange: { Type: 'Int', Default:
2, Value:
2,},
35 includeTodos: { Type: 'Bool', Default: true, Value: true,},
36 useBackgroundImage: { Type: 'Bool', Default: true, Value: true,},
37 backgroundImageLocation: { Type: 'Enum', Default: 'internal', Value: 'internal', ValidValues: ['internal', 'external']},
38 showCombinedDateTime: { Type: 'Bool', Default: false, Value: false,},
39 showLocation: { Type: 'Bool', Default: true, Value: true,},
40 showTodayAsText: { Type: 'Bool', Default: true, Value: true,},
41 todayText: { Type: 'String', Default: getLocalizedText('settings.default.todayText'), Value: getLocalizedText('settings.default.todayText'),},
42 tomorrowText: { Type: 'String', Default: getLocalizedText('settings.default.tomorrowText'), Value: getLocalizedText('settings.default.tomorrowText'),},
43 showNowAsText: { Type: 'Bool', Default: true, Value: true,},
44 nowText: { Type: 'String', Default: getLocalizedText('settings.default.nowText'), Value: getLocalizedText('settings.default.nowText'),},
45 markOverdueTodos: { Type: 'Bool', Default: true, Value: true,},
46 overdueText: {Type: 'String', Default: getLocalizedText('settings.default.overdueText'), Value: getLocalizedText('settings.default.overdueText'),},
47 dateSeparator: { Type: 'String', Default: getLocalizedText('settings.default.dateSeparator'), Value: getLocalizedText('settings.default.dateSeparator'),},
48 dateFormat: { Type: 'Enum', Default: 'auto', Value: 'auto', ValidValues: ['auto', 'DDMM', 'MMDD'],},
49 weekDayLength: { Type: 'Int', Default:
2, Value:
2,},
50 updateDataInterval: { Type: 'Int', Default:
5, Value:
5,},
51 calendarApp: { Type: 'UID', Default:
0x10005901, Value:
0x10005901,},
52 eventsPerWidget: { Type: 'Int', Default:
4, Value:
4,},
53 showNothingText: { Type: 'Bool', Default: true, Value: true,},
54 nothingText: { Type: 'String', Default: getLocalizedText('settings.default.nothingText'), Value: getLocalizedText('settings.default.nothingText'),},
55 enableDaylightSaving: { Type: 'Bool', Default: true, Value: true,},
56 daylightSavingOffset: { Type: 'Int', Default:
1, Value:
1,},
57 hideWidgetOnCalendarOpen: { Type: 'Bool', Default: false, Value: false,},
58 showCalendarIndicator: { Type: 'Bool', Default: true, Value: true,},
59 excludedCalendars: { Type: 'Array', Default: [], Value: [],},
60 cssStyle_background: { Type: 'String', Default: 'color:#ffffff; background-color:#
000000', Value: 'color:#ffffff; background-color:#
000000',},
61 cssStyle_backgroundFullscreen: { Type: 'String', Default: 'color:#ffffff; background-color:#
000000', Value: 'color:#ffffff; background-color:#
000000',},
62 cssStyle_weekDay: { Type: 'String', Default: '', Value: '',},
63 cssStyle_date: { Type: 'String', Default: '', Value: '',},
64 cssStyle_today: { Type: 'String', Default: 'color:#ff0000', Value: 'color:#ff0000',},
65 cssStyle_tomorrow: { Type: 'String', Default: 'color:#
0000ff', Value: 'color:#
0000ff',},
66 cssStyle_time: { Type: 'String', Default: '', Value: '',},
67 cssStyle_now: { Type: 'String', Default: 'color:#ff00ff', Value: 'color:#ff00ff',},
68 cssStyle_description: { Type: 'String', Default: '', Value: '',},
69 cssStyle_icon: { Type: 'String', Default: 'width:
15px; height:
15px', Value: 'width:
15px; height:
15px',},
70 cssStyle_overdue: { Type: 'String', Default: 'color:#ffff00', Value: 'color:#ffff00',},
71 cssStyle_calendar1: { Type: 'String', Default: 'background-color:#
0757cf', Value: 'background-color:#
0757cf',},
72 cssStyle_calendar2: { Type: 'String', Default: 'background-color:#
579f37', Value: 'background-color:#
579f37',},
73 cssStyle_calendar3: { Type: 'String', Default: 'background-color:#ff9f07', Value: 'background-color:#ff9f07',},
74 cssStyle_calendar4: { Type: 'String', Default: 'background-color:#af8fef', Value: 'background-color:#af8fef',},
75 cssStyle_calendar5: { Type: 'String', Default: 'background-color:#
57afbf', Value: 'background-color:#
57afbf',},
76 cssStyle_calendar6: { Type: 'String', Default: 'background-color:#
9fdf57', Value: 'background-color:#
9fdf57',},
81 //-------------------------------------------------------
82 // Nothing of interest from here on...
83 //-------------------------------------------------------
84 var panelNum =
0; // use
1 for second panel
86 var versionURL =
"http://comingnext.sourceforge.net/version.xml";
87 var calendarService = null;
88 var cacheEntriesHtml = [];
89 var months_translated = [];
92 var mode =
0; //
0 = homescreen,
1 = fullscreen,
2 = settings,
3 = about,
4 = check for update
94 var settingsCalEntryId = null;
95 var settingsCache = null;
96 var notificationRequests = new Array();
97 var calendarList = [];
98 var calendarColors = [];
99 var updateTimer = null;
100 var screenRotationTimer = null;
101 var lastUpdateTime = now;
102 var errorOccured = false;
104 // vars for daylight saving time
105 var summertime = false; // true, if current date is in summer, false if in winter
106 var daylightSavingDates = new Object(); // caches calculated DST winter and summer time shift dates
108 // this is a list of data fields a calendar event can have
122 window.onload = init;
123 window.onresize = updateScreen;
124 window.onshow = updateScreen;
126 function isLeapYear( year ) {
127 if (( year %
4 ==
0 && year %
100 !=
0 ) || year %
400 ==
0 )
133 function calcLeapYear(year, days)
135 if (isLeapYear(year))
141 function subToSunday(myDate, year, days, prevMonthDays)
143 for (i = myDate.getDay(); i
> 0 ;i--)
145 days -= prevMonthDays;
146 days = isLeapYear(year) ? --days : days;
150 function isSummertime(curDate)
155 // if we already calculated DST summer and winter time dates for this year, use cached values
156 var dst = daylightSavingDates[curDate.getFullYear()];
158 var thisYearS = new Date(curDate.getFullYear(),
3,
0,
0,
0,
0 );
159 var thisYearW = new Date(curDate.getFullYear(),
10,
0,
0,
0,
0 );
160 var nextYearS = new Date(curDate.getFullYear() +
1,
3,
0,
0,
0,
0 );
161 var nextYearW = new Date(curDate.getFullYear() +
1,
10,
0,
0,
0,
0 );
163 thisYearSDays = nextYearSDays =
90;
164 thisYearWDays = nextYearWDays =
304;
166 thisYearSDays = calcLeapYear(curDate.getFullYear(), thisYearSDays);
167 thisYearWDays = calcLeapYear(curDate.getFullYear(), thisYearWDays);
168 nextYearSDays = calcLeapYear(curDate.getFullYear() +
1, nextYearSDays);
169 nextYearWDays = calcLeapYear(curDate.getFullYear() +
1, nextYearWDays);
171 thisYearSDays = subToSunday(thisYearS, curDate.getFullYear(), thisYearSDays,
59);
172 thisYearWDays = subToSunday(thisYearW, curDate.getFullYear(), thisYearWDays,
273);
173 nextYearSDays = subToSunday(nextYearS, curDate.getFullYear() +
1, nextYearSDays,
59);
174 nextYearWDays = subToSunday(nextYearW, curDate.getFullYear() +
1, nextYearWDays,
273);
177 Summer: new Date (curDate.getFullYear(),
03-
1, thisYearSDays,
2,
0,
0),
178 Winter: new Date (curDate.getFullYear(),
10-
1, thisYearWDays,
2,
0,
0),
180 daylightSavingDates[curDate.getFullYear()] = dst;
183 if (dst.Summer < curDate)
185 if (dst.Winter < curDate)
187 if (summer && !winter)
193 function error(message)
195 console.info('Error: ' + message);
196 document.getElementById(
"calendarList").innerHTML = 'Error: ' + message;
197 document.getElementById(
"fullscreenCalendarList").innerHTML = 'Error: ' + message;
199 document.onclick = null;
202 function areDatesEqual(date1, date2)
204 return (date1.getFullYear() == date2.getFullYear() &&
205 date1.getMonth() == date2.getMonth() &&
206 date1.getDate() == date2.getDate());
209 function isTomorrow(date)
211 // tommorow = now +
1 day
212 // ToDo: some days can be shorter as
24 hours(daylight saving change day)
213 return areDatesEqual(date, new Date (now.getTime() +
24*
60*
60*
1000));
216 function isToday(date)
218 return areDatesEqual(date, now);
221 function collectLocales()
223 var tmpyear =
2000 + panelNum;
226 if (months_translated.length
> 0)
228 for (month =
0; month <
12; month++) {
229 var startDate = new Date(tmpyear, month,
15);
231 var item = new Object();
232 item.Type =
"DayEvent";
233 item.StartTime = startDate;
234 item.Summary =
"__temp" + month;
236 var criteria = new Object();
237 criteria.Type =
"CalendarEntry";
238 criteria.Item = item;
241 var result = calendarService.IDataSource.Add(criteria);
242 if (result.ErrorCode)
243 error(result.ErrorMessage);
245 error(
"collectLocales: " + e + ', line ' + e.line);
249 var startTime = new Date(tmpyear,
0,
1);
250 var endTime = new Date(tmpyear,
11,
31);
251 var listFiltering = {
252 Type:'CalendarEntry',
254 StartRange: startTime,
256 SearchText: '__temp',
260 var result = calendarService.IDataSource.GetList(listFiltering);
261 if (result.ErrorCode) {
262 error(result.ErrorMessage);
265 var list = result.ReturnValue;
267 error(e + ', line ' + e.line);
270 var ids = new Array();
276 while (list && (entry = list.getNext()) != undefined) {
277 dateArr = entry.StartTime.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
278 var day = dateArr[
1];
279 var month = dateArr[
2];
280 var year = dateArr[
3];
282 // make sure month is set properly
283 if (isNaN(parseInt(day))) {
287 } else if (isNaN(parseInt(year))) {
293 console.info(entry.StartTime + ' -
> ' + month + ' ' + counter);
294 ids[counter] = entry.id;
295 months_translated[month] = counter +
1;
299 error(e + ', line ' + e.line);
304 var criteria = new Object();
305 criteria.Type =
"CalendarEntry";
310 var result = calendarService.IDataSource.Delete(criteria);
311 if (result.ErrorCode)
312 error(result.ErrorMessage);
314 error('deleting temp calendar entries:' + e + ', line ' + e.line);
319 function requestNotification()
321 var criteria = new Object();
322 criteria.Type =
"CalendarEntry";
323 criteria.Filter = new Object();
324 for(var i=
0; i < calendarList.length; i++) {
325 criteria.Filter.CalendarName = calendarList[i];
327 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria, callback);
328 if (notificationRequest.ErrorCode)
329 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
330 notificationRequests.push(notificationRequest);
332 error(
"requestNotification: " + e + ', line ' + e.line);
336 var criteria2 = new Object();
337 criteria2.Type =
"CalendarEntry";
338 criteria2.Filter = new Object();
339 criteria2.Filter.LocalIdList = new Array();
340 criteria2.Filter.LocalIdList[
0] = settingsCalEntryId;
342 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria2, settingsCallback);
343 if (notificationRequest.ErrorCode)
344 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
345 notificationRequests.push(notificationRequest);
347 error(
"requestNotification: " + e + ', line ' + e.line);
351 function cancelNotification()
353 for(var i=
0; i < notificationRequests.length; i++) {
355 var result = calendarService.IDataSource.Cancel(notificationRequests[i]);
356 if (result.ErrorCode)
357 error('cancelNotification failed with error code ' + result.ErrorCode);
359 error(
"cancelNotification: " + e + ', line ' + e.line);
364 function callback(transId, eventCode, result)
366 console.info(
"callback(): panelNum: %d transId: %d eventCode: %d result.ErrorCode: %d", panelNum, transId, eventCode, result.ErrorCode);
370 function settingsCallback(transId, eventCode, result)
372 console.info(
"settingsCallback(): panelNum: %d transId: %d eventCode: %d result.ErrorCode: %d", panelNum, transId, eventCode, result.ErrorCode);
376 function parseDate(dateString)
379 Dates my look very differently. Also keep in mind that the names are localized!!! These are the possibilities depending on the users date format setting:
380 Wednesday,
26 August,
2009 24:
00:
00
381 Wednesday,
26 August,
2009 12:
00:
00 am
382 Wednesday, August
26,
2009 12:
00:
00 am
383 Wednesday,
2009 August,
26 12:
00:
00 am
384 Wednesday,
2009 August,
28 8.00.00 pm
385 Wednesday,
2009 August,
28 08:
00:
00 PM
388 if (dateString ==
"" || dateString == null)
390 var dateArr = dateString.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
391 if (dateArr.length !=
5 && dateArr.length !=
6)
395 var weekDay = dateArr[
0];
396 var day = dateArr[
1];
397 var month = dateArr[
2];
398 var year = dateArr[
3];
399 // make sure month is set properly
400 if (isNaN(parseInt(day))) {
404 } else if (isNaN(parseInt(year))) {
409 // make sure day and year are set properly
410 if (Number(day)
> Number(year)) {
415 month = months_translated[month];
418 var timeArr = dateArr[
4].split(':');
419 if (timeArr.length !=
3)
421 var hours = Number(timeArr[
0]);
422 var minutes = Number(timeArr[
1]);
423 var seconds = Number(timeArr[
2]);
424 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'pm' && hours <
12)
426 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'am' && hours ==
12)
429 var result = new Date(year, month -
1, day, hours, minutes, seconds);
431 // take care of daylight saving time
432 if (config['enableDaylightSaving'].Value) {
434 // determine if date is in summer or winter time
435 var dateSummerTime = isSummertime(result);
437 // work around bug in Nokias calendar api resulting in dates within a different DST to be off by
1 hour
438 if (summertime && !dateSummerTime) {
439 result = new Date(result.getTime() -
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // -
1 hour
440 console.info('parseDate(): fixing time -
1h: ' + result);
442 else if (!summertime && dateSummerTime) {
443 result = new Date(result.getTime() +
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // +
1 hour
444 console.info('parseDate(): fixing time +
1h: ' + result);
451 // returns a short date as string (
"31.12" or
"12.31") based on the format string which should look like
"Wednesday, 26 August, 2009 12:00:00 am"
452 function formatDate(date, format)
454 var day = date.getDate().toString();
455 var month = (date.getMonth() +
1).toString();
456 while (day.length <
2) { day = '
0' + day; }
457 while (month.length <
2) { month = '
0' + month; }
459 if (config['showTodayAsText'].Value && isToday(date))
460 return '
<span class=
"today">' + config['todayText'].Value + '
</span>';
461 if (config['showTodayAsText'].Value && isTomorrow(date))
462 return '
<span class=
"tomorrow">' + config['tomorrowText'].Value + '
</span>';
464 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
465 if (dateArr.length !=
5 && dateArr.length !=
6) {
466 // we don't know how to format this
467 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
468 return day + config['dateSeparator'].Value + month;
470 return month + config['dateSeparator'].Value + day;
474 if (config['dateFormat'].Value == 'MMDD')
476 else if (config['dateFormat'].Value == 'DDMM')
479 // config['dateFormat'].Value == 'auto', try to detect system setting
481 var day_ = dateArr[
1];
482 var month_ = dateArr[
2];
483 var year_ = dateArr[
3];
484 // make sure month is set properly
485 if (isNaN(parseInt(day_))) {
490 } else if (isNaN(parseInt(year_))) {
496 // make sure day and year are set properly
497 if (Number(day_)
> Number(year_))
502 return day + config['dateSeparator'].Value + month;
504 return month + config['dateSeparator'].Value + day;
507 function formatTime(date)
509 // date is a Date() object
510 date.setSeconds(
0); // we don't care about seconds
511 var time = date.toLocaleTimeString().replace(/[\.:]
00/, ''); // remove seconds from string
512 if (time.replace(/\./, ':').split(':')[
0].length <
2)
514 if (config['showNowAsText'].Value && date.getTime() == now.getTime())
515 time = '
<span class=
"now">' + config['nowText'].Value + '
</span>';
519 function updateData()
521 console.info('updateData()');
526 // check if we got additional or less calendars since our last update
527 var newCalendarList = listCalendars();
528 if (newCalendarList.length != calendarList.length) {
529 calendarList = newCalendarList;
530 updateCalendarColors();
531 cancelNotification();
532 requestNotification();
536 // meetings have time
537 // note: anniveraries have a start time of
12:
00am. So since we want to include them, we have to query the whole day and check if events have passed later
539 summertime = isSummertime(now); // cache summer time info for today
540 var meetingList = [];
541 for(var i=
0; i < calendarList.length; i++) {
542 // ignore excluded calendars
543 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
545 var meetingListFiltering = {
546 Type:'CalendarEntry',
548 CalendarName: calendarList[i],
549 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
550 EndRange: (new Date(now.getFullYear(), now.getMonth() + config['monthRange'].Value, now.getDate(),
0,
0,
0))
553 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
554 if (meetingResult.ErrorCode !=
0)
555 throw(
"Error fetching calendar data: " + meetingResult.ErrorCode + ': ' + meetingResult.ErrorMessage);
556 var list = meetingResult.ReturnValue;
557 meetingList = meetingList.concat(listToArray(list, calendarList[i]));
559 console.info(
"updateData(): meetingList.sort()");
560 meetingList.sort(sortCalendarEntries);
562 // todos don't, they start on
00:
00 hrs., but should be visible anyway
563 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
564 if (config['includeTodos'].Value) {
565 var todayTodoList = [];
566 for(var i=
0; i < calendarList.length; i++) {
567 // ignore excluded calendars
568 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
570 var todayTodoListFiltering = {
571 Type:'CalendarEntry',
573 CalendarName: calendarList[i],
575 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
576 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
579 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
580 var list = todayTodoResult.ReturnValue;
581 todayTodoList = todayTodoList.concat(listToArray(list, calendarList[i]));
583 console.info(
"updateData(): todayTodoList.sort()");
584 todayTodoList.sort(sortCalendarEntries);
585 var entryLists = [todayTodoList, meetingList];
587 var entryLists = [meetingList];
590 error('loading Calendar items list:' + e + ', line ' + e.line);
599 var fontsize = 'normal';
601 if (config['eventsPerWidget'].Value ==
3) {
603 changeCssClass('.icon', 'width:
20px; height:
20px');
605 else if (config['eventsPerWidget'].Value ==
5) {
607 changeCssClass('.icon', 'width:
10px; height:
10px');
609 else if (config['eventsPerWidget'].Value ==
6) {
611 changeCssClass('.icon', 'width:
8px; height:
8px');
615 changeCssClass('.icon', config['cssStyle_icon'].Value);
616 var entriesHtml = '
<table style=
"font-size:' + fontsize + ';">';
620 max = (panelNum +
1) * config['eventsPerWidget'].Value;
622 max =
30; // we can display a lot more events in fullscreen mode
625 for (var i=
0; i < entryLists.length; i++) {
626 listinfo = listinfo +
" " + entryLists[i].length;
627 var entrieslist =
"";
628 for (var j=
0; j < entryLists[i].length; j++) {
629 entrieslist += entryLists[i][j].Summary +
", ";
631 console.info(
"updateData(): entrieslist: " + entrieslist);
633 console.info(
"updateData(): inner loop, " + entryLists.length +
" lists, [" + listinfo +
"] entries");
635 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
636 for (var i=
0; counter < max && i < entryLists.length; i++) {
637 for (var j=
0; (counter < max) && (j < entryLists[i].length); j++) {
638 entry = entryLists[i][j];
641 // output event info for debugging
642 var entryInfo =
"event: ";
643 for(var k=
0; k < entryFields.length; ++k) {
644 if (entry[entryFields[k]] != undefined) {
645 entryInfo += entryFields[k] +
"=" + entry[entryFields[k]] +
",";
648 console.info(entryInfo);
650 // we don't want ToDos when includeTodos == false or when they are completed
651 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !config['includeTodos'].Value)) {
652 console.info('skipping ' + entry.id );
657 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
658 if (eventIds[entry.id] ==
1 && entry.Type == 'ToDo') {
659 console.info('skipped (already included) ' + entry.id);
663 eventIds[entry.id] =
1;
665 // summary can be undefined!
666 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
667 if (entry.Type == 'Meeting' && entry.Location != '' && config['showLocation'].Value)
668 Summary += ', ' + entry.Location;
670 // fix by yves: determine start and end dates/times
671 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
672 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
674 // there can be ToDos that have no date at all!
675 if (entry.Type == 'ToDo' && entry.EndTime == null)
676 entryDate =
""; // this will cause parseDate(entryDate) to return null;
678 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
680 // Convert date/time string to Date object
681 var date = parseDate(entryDate);
682 console.info('date: ' + date);
683 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
684 console.info('endDate: ' + endDate);
686 // check if meeting event has already passed
687 if (entry.Type == 'Meeting') {
688 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
689 if (now.getTime()
> compareTime) {
690 console.info('skipping Meeting (already passed) ' + entry.id);
692 eventIds[entry.id] =
0;
697 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
698 if (entry.Type == 'Anniversary') {
699 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
700 if (date.getTime() < tmp.getTime()) {
701 console.info('skipping Anniversary (already passed) ' + entry.id);
703 eventIds[entry.id] =
0;
708 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
709 if (entry.Type == 'DayEvent' && endDate != null) {
710 endDate.setMinutes(endDate.getMinutes() -
1);
711 console.info('fixing DayEvent endDate: ' + endDate);
712 if (now.getTime()
> endDate.getTime()) {
713 console.info('event already passed ' + entry.id);
715 eventIds[entry.id] =
0;
720 // check if the event is currently taking place
721 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
722 // check if we are between start and endtime
723 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
724 date = now; // change appointment date/time to now
725 console.info('event is currently taking place: ' + date);
729 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
730 if (mode ==
0 && panelNum
> 0 && counter < panelNum * config['eventsPerWidget'].Value +
1) {
731 console.info('skipping (already in first widget) ' + entry.id);
735 // mark overdue todos
737 if (entry.Type == 'ToDo' && date != null) {
738 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
0,
0,
0);
739 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
740 if (tmp1.getTime() < tmp2.getTime()) {
745 // generate html output
746 entriesHtml += '
<tr>';
747 if (config['showCalendarIndicator'].Value && calendarList.length - config['excludedCalendars'].Value.length
> 1) {
748 entriesHtml += '
<td><span class=
"calendar' + calendarColors[entry.CalendarName] + '"> </span></td>';
750 entriesHtml += '
<td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
752 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
753 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
755 var weekDay = date.toLocaleDateString().substr(
0,config['weekDayLength'].Value);
756 var time = formatTime(date);
757 var dateStr = formatDate(date, entryDate);
758 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
759 dateStr = '
<span class=
"overdue">' + config['overdueText'].Value + '
</span>';
760 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
761 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
762 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
763 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
765 entriesHtml += '
<td class=
"weekDay" width=
"1px">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
766 } else if (entry.Type == 'Meeting') {
767 if (config['showCombinedDateTime'].Value) {
769 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
770 else if (isTomorrow(date))
771 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
773 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
775 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
776 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
778 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
782 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
785 entriesHtml += '
</table>';
786 if (config['showNothingText'].Value && entriesHtml == '
<table></table>') {
787 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
788 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '
</div>';
790 if (cacheEntriesHtml != entriesHtml) {
792 document.getElementById('calendarList').innerHTML = entriesHtml;
794 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
795 cacheEntriesHtml = entriesHtml;
798 lastUpdateTime = new Date();
800 error('displaying list:' + e + ', line ' + e.line);
805 function updateScreen()
807 // check if opening fullscreen
808 if( window.innerHeight
> 91 && mode ==
0) {
810 cacheEntriesHtml = '';
811 document.getElementById('body').style.backgroundImage =
"";
814 else if (window.innerHeight <=
91 && mode !=
0) {
816 cacheEntriesHtml = '';
825 var time = new Date();
826 if (time.getTime() - lastUpdateTime.getTime()
> config['updateDataInterval'].Value *
60 *
1000) {
827 console.info('updateScreen(): force updateData() because last update was too long ago (' + (time.getTime() - lastUpdateTime.getTime()) /
1000 + 's)');
830 setUpdateTimer(); // reinitialize update timer
834 function launchCalendar()
837 widget.openApplication(config['calendarApp'].Value,
"");
838 if (config['hideWidgetOnCalendarOpen'].Value)
841 error('starting Calendar App');
848 console.info('New widget instance starting up...');
851 // call calendar service
852 if (device !=
"undefined")
853 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
855 throw('device object does not exist');
857 error('loading Calendar service: ' + e + ', line ' + e.line + '
<br /><a onclick=
"widget.openURL(\'http://comingnext.sf.net/help\'); return false;" href=
"http://comingnext.sf.net/help">' + getLocalizedText('menu.help') + '
</a>');
861 calendarList = listCalendars();
863 updateCalendarColors();
866 requestNotification();
867 document.getElementById(
"settingsTitle").innerHTML = getLocalizedText('menu.settings');
869 if (window.innerHeight
> 91) {
870 mode =
0; // we're starting fullscreen, we set mode to homescreen in order to let updateScreen() do all the work for us
875 console.info(
"init(): updateScreen()");
877 if (config['useBackgroundImage'].Value)
878 // check for screen rotation every
1 secs
879 screenRotationTimer = window.setInterval('updateScreen()',
1000 *
1);
880 console.info(
"init(): finished...");
883 function setUpdateTimer()
885 updateTimer = window.setInterval('updateTimerCallback()',
1000 *
60 * config['updateDataInterval'].Value);
888 function clearUpdateTimer()
890 window.clearInterval(updateTimer);
893 function updateTimerCallback()
895 console.info(
"updateTimerCallback()");
899 function createMenu()
901 window.menu.setLeftSoftkeyLabel(
"",null);
902 window.menu.setRightSoftkeyLabel(
"",null);
904 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
905 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
906 var menuHelp = new MenuItem(getLocalizedText('menu.help'), id++);
907 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
908 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
909 menuSettings.onSelect = showSettings;
910 menuAbout.onSelect = showAbout;
911 menuCallApp.onSelect = launchCalendar;
912 menuUpdate.onSelect = showUpdate;
913 menuHelp.onSelect = showHelp;
915 window.menu.append(menuCallApp);
916 window.menu.append(menuSettings);
917 window.menu.append(menuHelp);
918 window.menu.append(menuUpdate);
919 window.menu.append(menuAbout);
922 function showSettings()
926 document.getElementById(
"settingsView").style.display =
"block";
927 document.onclick = null;
929 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
931 for (var key in config) {
932 if (config[key].Type == 'String')
933 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
934 else if (config[key].Type == 'Int') {
935 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
936 if (config[key].Value <
0)
937 config[key].Value = config[key].Default;
939 else if (config[key].Type == 'Bool')
940 config[key].Value = document.forms[
0].elements[
"settings." + key].checked;
941 else if (config[key].Type == 'UID')
942 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
943 else if (config[key].Type == 'Enum') {
944 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
945 if (config[key].ValidValues.indexOf(config[key].Value) == -
1)
946 config[key].Value = config[key].Default;
948 else if (config[key].Type == 'Array') {
949 if (key == 'excludedCalendars') {
950 config[key].Value = new Array();
951 for(var i=
0; i < calendarList.length; i++) {
952 var element = document.forms[
0].elements[
"settings." + key +
"." + calendarList[i]];
953 if (element != null && element.checked == false)
954 config[key].Value.push(calendarList[i]);
967 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
973 var settingsHtml = '
<form>';
974 for (var key in config) {
975 if (config[key].Type == 'String') {
977 if (key.substring(
0,
9) ==
"cssStyle_")
978 prefix = getLocalizedText('settings.cssStyle_prefix');
979 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 />';
981 else if (config[key].Type == 'Int')
982 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 />';
983 else if (config[key].Type == 'Bool')
984 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 />';
985 else if (config[key].Type == 'UID')
986 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 />';
987 else if (config[key].Type == 'Enum') {
988 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><select name=
"settings.' + key + '" size=
"1">';
989 for(var i =
0; i < config[key].ValidValues.length; i++)
990 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>';
991 settingsHtml += '
</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
993 else if (config[key].Type == 'Array') {
994 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br />';
995 if (key == 'excludedCalendars') {
996 for(var i=
0; i < calendarList.length; i++) {
997 var checked = '
checked=
"checked"';
998 if (config[key].Value.indexOf(calendarList[i]) != -
1)
1000 settingsHtml += '
<input name=
"settings.' + key + '.' + calendarList[i] + '" type=
"checkbox" value=
"' + calendarList[i] + '" ' + checked + '
/> ' + calendarList[i] + '
<br />';
1003 settingsHtml += '
</td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
1006 settingsHtml += '
<input name=
"reset" type=
"button" value=
"' + getLocalizedText('settings.restoreDefaults') + '" onclick=
"javascript:restoreDefaultSettings();showSettings();" />';
1007 settingsHtml += '
</form>';
1008 document.getElementById(
"settingsList").innerHTML = settingsHtml;
1011 function changeCssClass(classname, properties)
1013 for(var i =
0; i < document.styleSheets[
0]['cssRules'].length; i++)
1015 if (document.styleSheets[
0]['cssRules'][i].selectorText == classname) {
1016 document.styleSheets[
0].deleteRule(i);
1017 document.styleSheets[
0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[
0]['cssRules'].length);
1023 function updateCssClasses()
1025 for(var key in config) {
1026 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
1030 function getSettingsCalEntryId()
1032 if (settingsCalEntryId == null) {
1033 // check if entry already exists
1034 var listFiltering = {
1035 Type:'CalendarEntry',
1037 StartRange: new Date(
2000,
0,
1),
1038 EndRange: new Date(
2000,
0,
1),
1039 SearchText: 'ComingNext Settings|',
1043 var result = calendarService.IDataSource.GetList(listFiltering);
1044 if (result.ErrorCode) {
1045 error(result.ErrorMessage);
1048 var list = result.ReturnValue;
1049 var entry = list.getNext();
1050 if (entry != undefined) {
1051 settingsCalEntryId = entry.LocalId;
1052 console.info(
"settingsCalEntryId=" + settingsCalEntryId);
1054 else { // create settings item
1055 var item = new Object();
1056 item.Type =
"DayEvent";
1057 item.StartTime = new Date(
2000,
0,
1);
1058 item.Summary =
"ComingNext Settings|";
1060 var criteria = new Object();
1061 criteria.Type =
"CalendarEntry";
1062 criteria.Item = item;
1065 var result = calendarService.IDataSource.Add(criteria);
1066 if (result.ErrorCode)
1067 error(result.ErrorMessage);
1069 error(
"getSettingsCalEntryId: " + e + ', line ' + e.line);
1072 getSettingsCalEntryId();
1077 function restoreDefaultSettings()
1079 for (var key in config)
1080 config[key].Value = config[key].Default;
1083 function loadSettings()
1085 getSettingsCalEntryId();
1086 var listFiltering = {
1087 Type:'CalendarEntry',
1089 LocalId: settingsCalEntryId
1092 var result = calendarService.IDataSource.GetList(listFiltering);
1093 if (result.ErrorCode) {
1094 error(result.ErrorMessage);
1097 var entry = result.ReturnValue.getNext();
1098 if (entry != undefined) {
1099 console.info(
"Loading Settings...");
1100 // only reload settings if they chanced since the last reload
1101 if (settingsCache != entry.Summary)
1103 restoreDefaultSettings();
1104 var stringlist = entry.Summary.split(
"|");
1105 // skip the first two entries, those contain header and version info
1106 for(var i =
2; i < stringlist.length -
1; i++) {
1107 var pair = stringlist[i].split('=');
1109 var value = pair[
1];
1110 console.info('stringlist: ' + key + '=\'' + value + '\'');
1111 if (config[key].Type == 'Int')
1112 config[key].Value = Number(value);
1113 else if (config[key].Type == 'String')
1114 config[key].Value = value;
1115 else if (config[key].Type == 'Bool')
1116 config[key].Value = (value == 'true')
1117 else if (config[key].Type == 'Enum')
1118 config[key].Value = value;
1119 else if (config[key].Type == 'UID')
1120 config[key].Value = Number(value);
1121 else if (config[key].Type == 'Array') {
1122 config[key].Value = value.split(
"^");
1123 if (config[key].Value.length ==
1 && config[key].Value[
0] ==
"") {
1124 config[key].Value = [];
1128 settingsCache = entry.Summary;
1132 console.info(
"Settings already cached and did not change");
1136 error(
"Failed to load settings, calendar entry could not be found");
1140 function saveSettings()
1142 getSettingsCalEntryId();
1143 var item = new Object();
1144 item.Type =
"DayEvent";
1145 item.StartTime = new Date(
2000,
0,
1);
1146 item.LocalId = settingsCalEntryId;
1147 item.Summary =
"ComingNext Settings|" + version +
"|";
1149 for (var key in config) {
1150 if (config[key].Type == 'Int')
1151 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1152 else if (config[key].Type == 'String')
1153 item.Summary += key +
"=" + config[key].Value +
"|";
1154 else if (config[key].Type == 'Bool')
1155 item.Summary += key +
"=" + (config[key].Value ? 'true' : 'false') +
"|";
1156 else if (config[key].Type == 'Enum')
1157 item.Summary += key +
"=" + config[key].Value +
"|";
1158 else if (config[key].Type == 'UID')
1159 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1160 else if (config[key].Type == 'Array')
1161 item.Summary += key +
"=" + config[key].Value.join(
"^") +
"|";
1163 settingsCache = item.Summary;
1165 var criteria = new Object();
1166 criteria.Type =
"CalendarEntry";
1167 criteria.Item = item;
1169 console.info(
"Saving settings to calendar entry: " + item.Summary);
1171 var result = calendarService.IDataSource.Add(criteria);
1172 if (result.ErrorCode)
1173 error(result.ErrorMessage);
1175 error(
"saveSettings: " + e + ', line ' + e.line);
1182 function toggleVisibility(elementId)
1184 if (document.getElementById(elementId).style.display ==
"none")
1185 document.getElementById(elementId).style.display =
"block";
1187 document.getElementById(elementId).style.display =
"none";
1191 function printHintBox(text)
1194 return '
<td width=
"1%" align=
"right" onclick=
"javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '
</td></tr></table>'+
1195 '
<div class=
"settingsInfo" id=
"info' + uniqueId + '">' + text + '
</div>';
1198 function showAbout()
1202 document.getElementById(
"aboutView").style.display =
"block";
1203 document.onclick = null;
1205 window.menu.setLeftSoftkeyLabel(
" ", function(){});
1206 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1212 //document.getElementById(
"aboutView").innerHTML = 'aboutView';
1213 document.getElementById(
"name").innerHTML =
"Coming Next " + version;
1216 function showHelp() {
1217 widget.openURL('http://comingnext.sf.net/help');
1220 function updateFullscreen()
1224 function showFullscreen()
1226 console.info(
"showFullscreen()");
1228 document.getElementById(
"fullscreenView").style.display =
"block";
1229 document.getElementById('body').className =
"backgroundFullscreen";
1231 document.onclick = launchCalendar;
1236 function getBackgroundImage()
1241 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[
0]) // internal
1242 bgImage = 'background_' + orientation + '.png';
1244 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
1248 function updateHomescreen()
1250 if (config['useBackgroundImage'].Value) {
1251 // check for screen rotation
1252 if (orientation != 'portrait' && screen.width ==
360 && screen.height ==
640) {
1253 window.widget.prepareForTransition(
"fade");
1254 orientation = 'portrait';
1255 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1256 document.getElementById('body').style.backgroundColor = 'none';
1257 window.widget.performTransition();
1258 } else if (orientation != 'landscape' && screen.width ==
640 && screen.height ==
360) {
1259 window.widget.prepareForTransition(
"fade");
1260 orientation = 'landscape';
1261 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1262 document.getElementById('body').style.backgroundColor = 'none';
1263 window.widget.performTransition();
1265 else if (document.getElementById('body').style.backgroundImage ==
"")
1267 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1272 function showHomescreen()
1274 console.info(
"showHomescreen()");
1276 document.getElementById(
"homescreenView").style.display =
"block";
1277 document.getElementById('body').className =
"background";
1278 document.onclick = null;
1282 function getLocalizedText(p_Txt)
1284 if (localizedText[p_Txt])
1285 return localizedText[p_Txt];
1287 return 'ERROR: missing translation for ' + p_Txt;
1290 function showUpdate()
1294 document.getElementById(
"updateView").style.display =
"block";
1295 document.onclick = null;
1297 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1300 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1306 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
1310 function checkForUpdate()
1312 // asynch XHR to server url
1313 reqV = new XMLHttpRequest();
1314 reqV.onreadystatechange = checkForUpdateCallback;
1315 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
1316 reqV.open(
"GET", versionURL, true);
1317 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1321 function checkForUpdateCallback()
1323 if (reqV.readyState ==
4) {
1324 if (reqV.status ==
200) {
1325 var resultXml = reqV.responseText;
1327 var div = document.getElementById(
"tmp");
1328 div.innerHTML = resultXml;
1329 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
1330 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
1332 if (version != newVersion) {
1333 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1336 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1341 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1346 function hideViews()
1348 document.getElementById(
"homescreenView").style.display =
"none";
1349 document.getElementById(
"fullscreenView").style.display =
"none";
1350 document.getElementById(
"aboutView").style.display =
"none";
1351 document.getElementById(
"settingsView").style.display =
"none";
1352 document.getElementById(
"updateView").style.display =
"none";
1355 function listCalendars()
1361 DefaultCalendar: false
1365 var calendarsResult = calendarService.IDataSource.GetList(criteria);
1366 if (calendarsResult.ErrorCode !=
0)
1367 throw(
"Error fetching list of calendars: " + calendarsResult.ErrorCode + ': ' + calendarsResult.ErrorMessage);
1368 var calendarListIterator = calendarsResult.ReturnValue;
1373 while (( item = calendarListIterator.getNext()) != undefined ) {
1374 calendars[count++] = item;
1376 console.info(
"Available Calendars: " + calendars.join(
", "));
1379 error('listing calendars:' + e + ', line ' + e.line);
1384 // Copies all objects and their properties to an array. Data is copied so nothing gets lost when the reference is removed
1385 // 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
1386 function listToArray(list, calendarName)
1388 var array = new Array();
1391 while (( item = list.getNext()) != undefined ) {
1392 var itemCopy = new Object();
1393 for(var i=
0; i < entryFields.length; i++) {
1394 itemCopy[entryFields[i]] = item[entryFields[i]];
1396 // for some reason, the CalendarName property is never correctly queried, so we assign it manually here
1397 if (!itemCopy['CalendarName']) {
1398 itemCopy['CalendarName'] = calendarName;
1400 array.push(itemCopy);
1401 txt += array[array.length -
1].Summary +
", ";
1403 console.info(
"listToArray(): " + txt);
1407 function sortCalendarEntries(a, b)
1410 console.info(
"sortCalendarEntries(" + a.Summary +
"," + b.Summary +
")");
1412 if (a.InstanceStartTime != null) {
1413 atime = a.InstanceStartTime;
1415 else if (a.StartTime != null) {
1416 atime = a.StartTime;
1418 else if (a.InstanceEndTime != null) {
1419 atime = a.InstanceEndTime;
1421 else if (a.EndTime != null) {
1425 if (b.InstanceStartTime != null) {
1426 btime = b.InstanceStartTime;
1428 else if (b.StartTime != null) {
1429 btime = b.StartTime;
1431 else if (b.InstanceEndTime != null) {
1432 btime = b.InstanceEndTime;
1434 else if (b.EndTime != null) {
1438 if (atime && btime) {
1440 atime = parseDate(atime);
1441 btime = parseDate(btime);
1443 // sort by date & time
1444 if (atime < btime) {
1447 else if (atime
> btime) {
1451 else if (a.Type != b.Type) {
1452 if (a.Type < b.Type) {
1455 else if (a.Type
> b.Type) {
1459 // sort by description
1460 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1461 if (a.Summary < b.Summary) {
1464 else if (a.Summary
> b.Summary) {
1469 // NOTE: events my have no date information at all. In that case, we list events without date first
1470 else if (atime && !btime) {
1473 else if (!atime && btime) {
1476 else if (!atime && !btime) {
1478 if (a.Type != b.Type) {
1479 if (a.Type < b.Type) {
1482 else if (a.Type
> b.Type) {
1486 // sort by description
1487 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1488 if (a.Summary < b.Summary) {
1491 else if (a.Summary
> b.Summary) {
1500 function updateCalendarColors()
1503 calendarColors = [];
1504 if (calendarList.length
> maxColors) {
1505 console.info(
"updateCalendarColors(): Warning: more calendars than available indicator colors");
1507 for(var i=
0; i < calendarList.length; i++) {
1508 calendarColors[calendarList[i]] = (i % maxColors) +
1;
1514 <style type=
"text/css">
1516 table { margin:
0px; padding:
0px; border-spacing:
0px; }
1517 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
1518 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1519 .settingsInfo { display:none; font-style:italic; }
1520 .title { font-weight:bold; font-size:
14pt; }
1521 .textInput { width:
90%; }
1522 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1523 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
1524 #calendarList { position:absolute; left:
5px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
1525 #name { text-align:center; }
1526 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1527 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1532 <body id=
"body" class=
"background">
1533 <div id=
"homescreenView">
1534 <div id=
"calendarList"></div>
1536 <div id=
"fullscreenView" style=
"display:none;">
1537 <img src=
"Icon.png" id=
"smallappicon">
1538 <h1 class=
"title">Coming Next
</h1>
1540 <div id=
"fullscreenCalendarList">loading...
</div>
1542 <div id=
"settingsView" style=
"display:none">
1543 <img src=
"Icon.png" id=
"smallappicon">
1544 <h1 id=
"settingsTitle" class=
"title">Settings
</h1>
1546 <div id=
"settingsList"></div>
1548 <div id=
"aboutView" style=
"display:none">
1549 <img src=
"Icon.png" id=
"appicon">
1550 <h1 id=
"name">Coming Next
</h1>
1552 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1553 <p>Contributions:
</p>
1554 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1555 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1556 <p class=
"credits">Christophe Milsent (translation support & french translation)
</p>
1557 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation)
</p>
1558 <p class=
"credits">Tokeda (russian translation)
</p>
1559 <p class=
"credits">Marcella Ferrari (italian translation)
</p>
1560 <p class=
"credits">Venos (italian translation)
</p>
1561 <p>This software is open source and licensed under the GPLv3.
</p>
1562 <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>
1565 <div id=
"updateView" style=
"display:none">
1566 <img src=
"Icon.png" id=
"smallappicon">
1567 <h1 class=
"title">Check for update
</h1>
1569 <div id=
"currentVersion">Coming Next ??
</div>
1570 <div id=
"updateDiv"></div>
1571 <div id=
"tmp" style=
"display:none;"></div>