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;
102 // vars for daylight saving time
103 var summertime = false; // true, if current date is in summer, false if in winter
104 var daylightSavingDates = new Object(); // caches calculated DST winter and summer time shift dates
106 // this is a list of data fields a calendar event can have
120 window.onload = init;
121 window.onresize = updateScreen;
122 window.onshow = updateScreen;
124 function isLeapYear( year ) {
125 if (( year %
4 ==
0 && year %
100 !=
0 ) || year %
400 ==
0 )
131 function calcLeapYear(year, days)
133 if (isLeapYear(year))
139 function subToSunday(myDate, year, days, prevMonthDays)
141 for (i = myDate.getDay(); i
> 0 ;i--)
143 days -= prevMonthDays;
144 days = isLeapYear(year) ? --days : days;
148 function isSummertime(curDate)
153 // if we already calculated DST summer and winter time dates for this year, use cached values
154 var dst = daylightSavingDates[curDate.getFullYear()];
156 var thisYearS = new Date(curDate.getFullYear(),
3,
0,
0,
0,
0 );
157 var thisYearW = new Date(curDate.getFullYear(),
10,
0,
0,
0,
0 );
158 var nextYearS = new Date(curDate.getFullYear() +
1,
3,
0,
0,
0,
0 );
159 var nextYearW = new Date(curDate.getFullYear() +
1,
10,
0,
0,
0,
0 );
161 thisYearSDays = nextYearSDays =
90;
162 thisYearWDays = nextYearWDays =
304;
164 thisYearSDays = calcLeapYear(curDate.getFullYear(), thisYearSDays);
165 thisYearWDays = calcLeapYear(curDate.getFullYear(), thisYearWDays);
166 nextYearSDays = calcLeapYear(curDate.getFullYear() +
1, nextYearSDays);
167 nextYearWDays = calcLeapYear(curDate.getFullYear() +
1, nextYearWDays);
169 thisYearSDays = subToSunday(thisYearS, curDate.getFullYear(), thisYearSDays,
59);
170 thisYearWDays = subToSunday(thisYearW, curDate.getFullYear(), thisYearWDays,
273);
171 nextYearSDays = subToSunday(nextYearS, curDate.getFullYear() +
1, nextYearSDays,
59);
172 nextYearWDays = subToSunday(nextYearW, curDate.getFullYear() +
1, nextYearWDays,
273);
175 Summer: new Date (curDate.getFullYear(),
03-
1, thisYearSDays,
2,
0,
0),
176 Winter: new Date (curDate.getFullYear(),
10-
1, thisYearWDays,
2,
0,
0),
178 daylightSavingDates[curDate.getFullYear()] = dst;
181 if (dst.Summer < curDate)
183 if (dst.Winter < curDate)
185 if (summer && !winter)
191 function error(message)
193 console.info('Error: ' + message);
194 document.getElementById(
"calendarList").innerHTML = 'Error: ' + message;
197 function areDatesEqual(date1, date2)
199 return (date1.getFullYear() == date2.getFullYear() &&
200 date1.getMonth() == date2.getMonth() &&
201 date1.getDate() == date2.getDate());
204 function isTomorrow(date)
206 // tommorow = now +
1 day
207 // ToDo: some days can be shorter as
24 hours(daylight saving change day)
208 return areDatesEqual(date, new Date (now.getTime() +
24*
60*
60*
1000));
211 function isToday(date)
213 return areDatesEqual(date, now);
216 function collectLocales()
218 var tmpyear =
2000 + panelNum;
221 if (months_translated.length
> 0)
223 for (month =
0; month <
12; month++) {
224 var startDate = new Date(tmpyear, month,
15);
226 var item = new Object();
227 item.Type =
"DayEvent";
228 item.StartTime = startDate;
229 item.Summary =
"__temp" + month;
231 var criteria = new Object();
232 criteria.Type =
"CalendarEntry";
233 criteria.Item = item;
236 var result = calendarService.IDataSource.Add(criteria);
237 if (result.ErrorCode)
238 error(result.ErrorMessage);
240 error(
"collectLocales: " + e + ', line ' + e.line);
244 var startTime = new Date(tmpyear,
0,
1);
245 var endTime = new Date(tmpyear,
11,
31);
246 var listFiltering = {
247 Type:'CalendarEntry',
249 StartRange: startTime,
251 SearchText: '__temp',
255 var result = calendarService.IDataSource.GetList(listFiltering);
256 if (result.ErrorCode) {
257 error(result.ErrorMessage);
260 var list = result.ReturnValue;
262 error(e + ', line ' + e.line);
265 var ids = new Array();
271 while (list && (entry = list.getNext()) != undefined) {
272 dateArr = entry.StartTime.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
273 var day = dateArr[
1];
274 var month = dateArr[
2];
275 var year = dateArr[
3];
277 // make sure month is set properly
278 if (isNaN(parseInt(day))) {
282 } else if (isNaN(parseInt(year))) {
288 console.info(entry.StartTime + ' -
> ' + month + ' ' + counter);
289 ids[counter] = entry.id;
290 months_translated[month] = counter +
1;
294 error(e + ', line ' + e.line);
299 var criteria = new Object();
300 criteria.Type =
"CalendarEntry";
305 var result = calendarService.IDataSource.Delete(criteria);
306 if (result.ErrorCode)
307 error(result.ErrorMessage);
309 error('deleting temp calendar entries:' + e + ', line ' + e.line);
314 function requestNotification()
316 var criteria = new Object();
317 criteria.Type =
"CalendarEntry";
318 criteria.Filter = new Object();
319 for(var i=
0; i < calendarList.length; i++) {
320 criteria.Filter.CalendarName = calendarList[i];
322 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria, callback);
323 if (notificationRequest.ErrorCode)
324 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
325 notificationRequests.push(notificationRequest);
327 error(
"requestNotification: " + e + ', line ' + e.line);
331 var criteria2 = new Object();
332 criteria2.Type =
"CalendarEntry";
333 criteria2.Filter = new Object();
334 criteria2.Filter.LocalIdList = new Array();
335 criteria2.Filter.LocalIdList[
0] = settingsCalEntryId;
337 var notificationRequest = calendarService.IDataSource.RequestNotification(criteria2, settingsCallback);
338 if (notificationRequest.ErrorCode)
339 error('requestNotification failed with error code ' + notificationRequest.ErrorCode);
340 notificationRequests.push(notificationRequest);
342 error(
"requestNotification: " + e + ', line ' + e.line);
346 function cancelNotification()
348 for(var i=
0; i < notificationRequests.length; i++) {
350 var result = calendarService.IDataSource.Cancel(notificationRequests[i]);
351 if (result.ErrorCode)
352 error('cancelNotification failed with error code ' + result.ErrorCode);
354 error(
"cancelNotification: " + e + ', line ' + e.line);
359 function callback(transId, eventCode, result)
361 console.info(
"callback(): panelNum: %d transId: %d eventCode: %d result.ErrorCode: %d", panelNum, transId, eventCode, result.ErrorCode);
365 function settingsCallback(transId, eventCode, result)
367 console.info(
"settingsCallback(): panelNum: %d transId: %d eventCode: %d result.ErrorCode: %d", panelNum, transId, eventCode, result.ErrorCode);
371 function parseDate(dateString)
374 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:
375 Wednesday,
26 August,
2009 24:
00:
00
376 Wednesday,
26 August,
2009 12:
00:
00 am
377 Wednesday, August
26,
2009 12:
00:
00 am
378 Wednesday,
2009 August,
26 12:
00:
00 am
379 Wednesday,
2009 August,
28 8.00.00 pm
380 Wednesday,
2009 August,
28 08:
00:
00 PM
383 if (dateString ==
"" || dateString == null)
385 var dateArr = dateString.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
386 if (dateArr.length !=
5 && dateArr.length !=
6)
390 var weekDay = dateArr[
0];
391 var day = dateArr[
1];
392 var month = dateArr[
2];
393 var year = dateArr[
3];
394 // make sure month is set properly
395 if (isNaN(parseInt(day))) {
399 } else if (isNaN(parseInt(year))) {
404 // make sure day and year are set properly
405 if (Number(day)
> Number(year)) {
410 month = months_translated[month];
413 var timeArr = dateArr[
4].split(':');
414 if (timeArr.length !=
3)
416 var hours = Number(timeArr[
0]);
417 var minutes = Number(timeArr[
1]);
418 var seconds = Number(timeArr[
2]);
419 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'pm' && hours <
12)
421 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'am' && hours ==
12)
424 var result = new Date(year, month -
1, day, hours, minutes, seconds);
426 // take care of daylight saving time
427 if (config['enableDaylightSaving'].Value) {
429 // determine if date is in summer or winter time
430 var dateSummerTime = isSummertime(result);
432 // work around bug in Nokias calendar api resulting in dates within a different DST to be off by
1 hour
433 if (summertime && !dateSummerTime) {
434 result = new Date(result.getTime() -
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // -
1 hour
435 console.info('parseDate(): fixing time -
1h: ' + result);
437 else if (!summertime && dateSummerTime) {
438 result = new Date(result.getTime() +
1000 *
60 *
60 * config['daylightSavingOffset'].Value); // +
1 hour
439 console.info('parseDate(): fixing time +
1h: ' + result);
446 // 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"
447 function formatDate(date, format)
449 var day = date.getDate().toString();
450 var month = (date.getMonth() +
1).toString();
451 while (day.length <
2) { day = '
0' + day; }
452 while (month.length <
2) { month = '
0' + month; }
454 if (config['showTodayAsText'].Value && isToday(date))
455 return '
<span class=
"today">' + config['todayText'].Value + '
</span>';
456 if (config['showTodayAsText'].Value && isTomorrow(date))
457 return '
<span class=
"tomorrow">' + config['tomorrowText'].Value + '
</span>';
459 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
460 if (dateArr.length !=
5 && dateArr.length !=
6) {
461 // we don't know how to format this
462 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
463 return day + config['dateSeparator'].Value + month;
465 return month + config['dateSeparator'].Value + day;
469 if (config['dateFormat'].Value == 'MMDD')
471 else if (config['dateFormat'].Value == 'DDMM')
474 // config['dateFormat'].Value == 'auto', try to detect system setting
476 var day_ = dateArr[
1];
477 var month_ = dateArr[
2];
478 var year_ = dateArr[
3];
479 // make sure month is set properly
480 if (isNaN(parseInt(day_))) {
485 } else if (isNaN(parseInt(year_))) {
491 // make sure day and year are set properly
492 if (Number(day_)
> Number(year_))
497 return day + config['dateSeparator'].Value + month;
499 return month + config['dateSeparator'].Value + day;
502 function formatTime(date)
504 // date is a Date() object
505 date.setSeconds(
0); // we don't care about seconds
506 var time = date.toLocaleTimeString().replace(/[\.:]
00/, ''); // remove seconds from string
507 if (time.replace(/\./, ':').split(':')[
0].length <
2)
509 if (config['showNowAsText'].Value && date.getTime() == now.getTime())
510 time = '
<span class=
"now">' + config['nowText'].Value + '
</span>';
514 function updateData()
516 console.info('updateData()');
518 // check if we got additional or less calendars since our last update
519 var newCalendarList = listCalendars();
520 if (newCalendarList.length != calendarList.length) {
521 calendarList = newCalendarList;
522 updateCalendarColors();
523 cancelNotification();
524 requestNotification();
528 // meetings have time
529 // 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
531 summertime = isSummertime(now); // cache summer time info for today
532 var meetingList = [];
533 for(var i=
0; i < calendarList.length; i++) {
534 // ignore excluded calendars
535 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
537 var meetingListFiltering = {
538 Type:'CalendarEntry',
540 CalendarName: calendarList[i],
541 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
542 EndRange: (new Date(now.getFullYear(), now.getMonth() + config['monthRange'].Value, now.getDate(),
0,
0,
0))
545 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
546 if (meetingResult.ErrorCode !=
0)
547 throw(
"Error fetching calendar data: " + meetingResult.ErrorCode + ': ' + meetingResult.ErrorMessage);
548 var list = meetingResult.ReturnValue;
549 meetingList = meetingList.concat(listToArray(list, calendarList[i]));
551 console.info(
"updateData(): meetingList.sort()");
552 meetingList.sort(sortCalendarEntries);
554 // todos don't, they start on
00:
00 hrs., but should be visible anyway
555 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
556 if (config['includeTodos'].Value) {
557 var todayTodoList = [];
558 for(var i=
0; i < calendarList.length; i++) {
559 // ignore excluded calendars
560 if (config['excludedCalendars'].Value.indexOf(calendarList[i]) != -
1)
562 var todayTodoListFiltering = {
563 Type:'CalendarEntry',
565 CalendarName: calendarList[i],
567 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
568 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
571 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
572 var list = todayTodoResult.ReturnValue;
573 todayTodoList = todayTodoList.concat(listToArray(list, calendarList[i]));
575 console.info(
"updateData(): todayTodoList.sort()");
576 todayTodoList.sort(sortCalendarEntries);
577 var entryLists = [todayTodoList, meetingList];
579 var entryLists = [meetingList];
582 error('loading Calendar items list:' + e + ', line ' + e.line);
591 var fontsize = 'normal';
593 if (config['eventsPerWidget'].Value ==
3) {
595 changeCssClass('.icon', 'width:
20px; height:
20px');
597 else if (config['eventsPerWidget'].Value ==
5) {
599 changeCssClass('.icon', 'width:
10px; height:
10px');
601 else if (config['eventsPerWidget'].Value ==
6) {
603 changeCssClass('.icon', 'width:
8px; height:
8px');
607 changeCssClass('.icon', config['cssStyle_icon'].Value);
608 var entriesHtml = '
<table style=
"font-size:' + fontsize + ';">';
612 max = (panelNum +
1) * config['eventsPerWidget'].Value;
614 max =
30; // we can display a lot more events in fullscreen mode
617 for (var i=
0; i < entryLists.length; i++) {
618 listinfo = listinfo +
" " + entryLists[i].length;
619 var entrieslist =
"";
620 for (var j=
0; j < entryLists[i].length; j++) {
621 entrieslist += entryLists[i][j].Summary +
", ";
623 console.info(
"updateData(): entrieslist: " + entrieslist);
625 console.info(
"updateData(): inner loop, " + entryLists.length +
" lists, [" + listinfo +
"] entries");
627 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
628 for (var i=
0; counter < max && i < entryLists.length; i++) {
629 for (var j=
0; (counter < max) && (j < entryLists[i].length); j++) {
630 entry = entryLists[i][j];
633 // output event info for debugging
634 var entryInfo =
"event: ";
635 for(var k=
0; k < entryFields.length; ++k) {
636 if (entry[entryFields[k]] != undefined) {
637 entryInfo += entryFields[k] +
"=" + entry[entryFields[k]] +
",";
640 console.info(entryInfo);
642 // we don't want ToDos when includeTodos == false or when they are completed
643 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !config['includeTodos'].Value)) {
644 console.info('skipping ' + entry.id );
649 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
650 if (eventIds[entry.id] ==
1 && entry.Type == 'ToDo') {
651 console.info('skipped (already included) ' + entry.id);
655 eventIds[entry.id] =
1;
657 // summary can be undefined!
658 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
659 if (entry.Type == 'Meeting' && entry.Location != '' && config['showLocation'].Value)
660 Summary += ', ' + entry.Location;
662 // fix by yves: determine start and end dates/times
663 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
664 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
666 // there can be ToDos that have no date at all!
667 if (entry.Type == 'ToDo' && entry.EndTime == null)
668 entryDate =
""; // this will cause parseDate(entryDate) to return null;
670 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
672 // Convert date/time string to Date object
673 var date = parseDate(entryDate);
674 console.info('date: ' + date);
675 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
676 console.info('endDate: ' + endDate);
678 // check if meeting event has already passed
679 if (entry.Type == 'Meeting') {
680 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
681 if (now.getTime()
> compareTime) {
682 console.info('skipping Meeting (already passed) ' + entry.id);
684 eventIds[entry.id] =
0;
689 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
690 if (entry.Type == 'Anniversary') {
691 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
692 if (date.getTime() < tmp.getTime()) {
693 console.info('skipping Anniversary (already passed) ' + entry.id);
695 eventIds[entry.id] =
0;
700 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
701 if (entry.Type == 'DayEvent' && endDate != null) {
702 endDate.setMinutes(endDate.getMinutes() -
1);
703 console.info('fixing DayEvent endDate: ' + endDate);
704 if (now.getTime()
> endDate.getTime()) {
705 console.info('event already passed ' + entry.id);
707 eventIds[entry.id] =
0;
712 // check if the event is currently taking place
713 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
714 // check if we are between start and endtime
715 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
716 date = now; // change appointment date/time to now
717 console.info('event is currently taking place: ' + date);
721 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
722 if (mode ==
0 && panelNum
> 0 && counter < panelNum * config['eventsPerWidget'].Value +
1) {
723 console.info('skipping (already in first widget) ' + entry.id);
727 // mark overdue todos
729 if (entry.Type == 'ToDo' && date != null) {
730 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
0,
0,
0);
731 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
732 if (tmp1.getTime() < tmp2.getTime()) {
737 // generate html output
738 entriesHtml += '
<tr>';
739 if (config['showCalendarIndicator'].Value && calendarList.length - config['excludedCalendars'].Value.length
> 1) {
740 entriesHtml += '
<td><span class=
"calendar' + calendarColors[entry.CalendarName] + '"> </span></td>';
742 entriesHtml += '
<td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
744 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
745 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
747 var weekDay = date.toLocaleDateString().substr(
0,config['weekDayLength'].Value);
748 var time = formatTime(date);
749 var dateStr = formatDate(date, entryDate);
750 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
751 dateStr = '
<span class=
"overdue">' + config['overdueText'].Value + '
</span>';
752 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
753 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
754 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
755 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
757 entriesHtml += '
<td class=
"weekDay" width=
"1px">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
758 } else if (entry.Type == 'Meeting') {
759 if (config['showCombinedDateTime'].Value) {
761 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
762 else if (isTomorrow(date))
763 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
765 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
767 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
768 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
770 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
774 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
777 entriesHtml += '
</table>';
778 if (config['showNothingText'].Value && entriesHtml == '
<table></table>') {
779 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
780 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '
</div>';
782 if (cacheEntriesHtml != entriesHtml) {
784 document.getElementById('calendarList').innerHTML = entriesHtml;
786 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
787 cacheEntriesHtml = entriesHtml;
790 error('displaying list:' + e + ', line ' + e.line);
795 function updateScreen()
797 // check if opening fullscreen
798 if( window.innerHeight
> 91 && mode ==
0) {
800 cacheEntriesHtml = '';
801 document.getElementById('body').style.backgroundImage =
"";
804 else if (window.innerHeight <=
91 && mode !=
0) {
806 cacheEntriesHtml = '';
816 function launchCalendar()
819 widget.openApplication(config['calendarApp'].Value,
"");
820 if (config['hideWidgetOnCalendarOpen'].Value)
823 error('starting Calendar App');
830 console.info('New widget instance starting up...');
833 // call calendar service
834 if (device !=
"undefined")
835 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
837 throw('device object does not exist');
839 error('loading Calendar service: ' + e + ', line ' + e.line);
843 calendarList = listCalendars();
845 updateCalendarColors();
848 requestNotification();
849 document.getElementById(
"settingsTitle").innerHTML = getLocalizedText('menu.settings');
851 if (window.innerHeight
> 91) {
852 mode =
0; // we're starting fullscreen, we set mode to homescreen in order to let updateScreen() do all the work for us
857 console.info(
"init(): updateScreen()");
859 if (config['useBackgroundImage'].Value)
860 // check for screen rotation every
1 secs
861 screenRotationTimer = window.setInterval('updateScreen()',
1000 *
1);
862 console.info(
"init(): finished...");
865 function setUpdateTimer()
867 updateTimer = window.setInterval('updateTimerCallback()',
1000 *
60 * config['updateDataInterval'].Value);
870 function clearUpdateTimer()
872 window.clearInterval(updateTimer);
875 function updateTimerCallback()
877 console.info(
"updateTimerCallback()");
881 function createMenu()
883 window.menu.setLeftSoftkeyLabel(
"",null);
884 window.menu.setRightSoftkeyLabel(
"",null);
886 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
887 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
888 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
889 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
890 menuSettings.onSelect = showSettings;
891 menuAbout.onSelect = showAbout;
892 menuCallApp.onSelect = launchCalendar;
893 menuUpdate.onSelect = showUpdate;
895 window.menu.append(menuCallApp);
896 window.menu.append(menuSettings);
897 window.menu.append(menuUpdate);
898 window.menu.append(menuAbout);
901 function showSettings()
905 document.getElementById(
"settingsView").style.display =
"block";
906 document.onclick = null;
908 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
910 for (var key in config) {
911 if (config[key].Type == 'String')
912 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
913 else if (config[key].Type == 'Int') {
914 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
915 if (config[key].Value <
0)
916 config[key].Value = config[key].Default;
918 else if (config[key].Type == 'Bool')
919 config[key].Value = document.forms[
0].elements[
"settings." + key].checked;
920 else if (config[key].Type == 'UID')
921 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
922 else if (config[key].Type == 'Enum') {
923 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
924 if (config[key].ValidValues.indexOf(config[key].Value) == -
1)
925 config[key].Value = config[key].Default;
927 else if (config[key].Type == 'Array') {
928 if (key == 'excludedCalendars') {
929 config[key].Value = new Array();
930 for(var i=
0; i < calendarList.length; i++) {
931 var element = document.forms[
0].elements[
"settings." + key +
"." + calendarList[i]];
932 if (element != null && element.checked == false)
933 config[key].Value.push(calendarList[i]);
946 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
952 var settingsHtml = '
<form>';
953 for (var key in config) {
954 if (config[key].Type == 'String') {
956 if (key.substring(
0,
9) ==
"cssStyle_")
957 prefix = getLocalizedText('settings.cssStyle_prefix');
958 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 />';
960 else if (config[key].Type == 'Int')
961 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 />';
962 else if (config[key].Type == 'Bool')
963 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 />';
964 else if (config[key].Type == 'UID')
965 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 />';
966 else if (config[key].Type == 'Enum') {
967 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><select name=
"settings.' + key + '" size=
"1">';
968 for(var i =
0; i < config[key].ValidValues.length; i++)
969 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>';
970 settingsHtml += '
</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
972 else if (config[key].Type == 'Array') {
973 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br />';
974 if (key == 'excludedCalendars') {
975 for(var i=
0; i < calendarList.length; i++) {
976 var checked = '
checked=
"checked"';
977 if (config[key].Value.indexOf(calendarList[i]) != -
1)
979 settingsHtml += '
<input name=
"settings.' + key + '.' + calendarList[i] + '" type=
"checkbox" value=
"' + calendarList[i] + '" ' + checked + '
/> ' + calendarList[i] + '
<br />';
982 settingsHtml += '
</td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
985 settingsHtml += '
<input name=
"reset" type=
"button" value=
"' + getLocalizedText('settings.restoreDefaults') + '" onclick=
"javascript:restoreDefaultSettings();showSettings();" />';
986 settingsHtml += '
</form>';
987 document.getElementById(
"settingsList").innerHTML = settingsHtml;
990 function changeCssClass(classname, properties)
992 for(var i =
0; i < document.styleSheets[
0]['cssRules'].length; i++)
994 if (document.styleSheets[
0]['cssRules'][i].selectorText == classname) {
995 document.styleSheets[
0].deleteRule(i);
996 document.styleSheets[
0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[
0]['cssRules'].length);
1002 function updateCssClasses()
1004 for(var key in config) {
1005 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
1009 function getSettingsCalEntryId()
1011 if (settingsCalEntryId == null) {
1012 // check if entry already exists
1013 var listFiltering = {
1014 Type:'CalendarEntry',
1016 StartRange: new Date(
2000,
0,
1),
1017 EndRange: new Date(
2000,
0,
1),
1018 SearchText: 'ComingNext Settings|',
1022 var result = calendarService.IDataSource.GetList(listFiltering);
1023 if (result.ErrorCode) {
1024 error(result.ErrorMessage);
1027 var list = result.ReturnValue;
1028 var entry = list.getNext();
1029 if (entry != undefined) {
1030 settingsCalEntryId = entry.LocalId;
1031 console.info(
"settingsCalEntryId=" + settingsCalEntryId);
1033 else { // create settings item
1034 var item = new Object();
1035 item.Type =
"DayEvent";
1036 item.StartTime = new Date(
2000,
0,
1);
1037 item.Summary =
"ComingNext Settings|";
1039 var criteria = new Object();
1040 criteria.Type =
"CalendarEntry";
1041 criteria.Item = item;
1044 var result = calendarService.IDataSource.Add(criteria);
1045 if (result.ErrorCode)
1046 error(result.ErrorMessage);
1048 error(
"getSettingsCalEntryId: " + e + ', line ' + e.line);
1051 getSettingsCalEntryId();
1056 function restoreDefaultSettings()
1058 for (var key in config)
1059 config[key].Value = config[key].Default;
1062 function loadSettings()
1064 getSettingsCalEntryId();
1065 var listFiltering = {
1066 Type:'CalendarEntry',
1068 LocalId: settingsCalEntryId
1071 var result = calendarService.IDataSource.GetList(listFiltering);
1072 if (result.ErrorCode) {
1073 error(result.ErrorMessage);
1076 var entry = result.ReturnValue.getNext();
1077 if (entry != undefined) {
1078 console.info(
"Loading Settings...");
1079 // only reload settings if they chanced since the last reload
1080 if (settingsCache != entry.Summary)
1082 restoreDefaultSettings();
1083 var stringlist = entry.Summary.split(
"|");
1084 // skip the first two entries, those contain header and version info
1085 for(var i =
2; i < stringlist.length -
1; i++) {
1086 var pair = stringlist[i].split('=');
1088 var value = pair[
1];
1089 console.info('stringlist: ' + key + '=\'' + value + '\'');
1090 if (config[key].Type == 'Int')
1091 config[key].Value = Number(value);
1092 else if (config[key].Type == 'String')
1093 config[key].Value = value;
1094 else if (config[key].Type == 'Bool')
1095 config[key].Value = (value == 'true')
1096 else if (config[key].Type == 'Enum')
1097 config[key].Value = value;
1098 else if (config[key].Type == 'UID')
1099 config[key].Value = Number(value);
1100 else if (config[key].Type == 'Array')
1101 config[key].Value = value.split(
"^");
1103 settingsCache = entry.Summary;
1107 console.info(
"Settings already cached and did not change");
1111 error(
"Failed to load settings, calendar entry could not be found");
1115 function saveSettings()
1117 getSettingsCalEntryId();
1118 var item = new Object();
1119 item.Type =
"DayEvent";
1120 item.StartTime = new Date(
2000,
0,
1);
1121 item.LocalId = settingsCalEntryId;
1122 item.Summary =
"ComingNext Settings|" + version +
"|";
1124 for (var key in config) {
1125 if (config[key].Type == 'Int')
1126 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1127 else if (config[key].Type == 'String')
1128 item.Summary += key +
"=" + config[key].Value +
"|";
1129 else if (config[key].Type == 'Bool')
1130 item.Summary += key +
"=" + (config[key].Value ? 'true' : 'false') +
"|";
1131 else if (config[key].Type == 'Enum')
1132 item.Summary += key +
"=" + config[key].Value +
"|";
1133 else if (config[key].Type == 'UID')
1134 item.Summary += key +
"=" + config[key].Value.toString() +
"|";
1135 else if (config[key].Type == 'Array')
1136 item.Summary += key +
"=" + config[key].Value.join(
"^") +
"|";
1138 settingsCache = item.Summary;
1140 var criteria = new Object();
1141 criteria.Type =
"CalendarEntry";
1142 criteria.Item = item;
1144 console.info(
"Saving settings to calendar entry: " + item.Summary);
1146 var result = calendarService.IDataSource.Add(criteria);
1147 if (result.ErrorCode)
1148 error(result.ErrorMessage);
1150 error(
"saveSettings: " + e + ', line ' + e.line);
1157 function toggleVisibility(elementId)
1159 if (document.getElementById(elementId).style.display ==
"none")
1160 document.getElementById(elementId).style.display =
"block";
1162 document.getElementById(elementId).style.display =
"none";
1166 function printHintBox(text)
1169 return '
<td width=
"1%" align=
"right" onclick=
"javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '
</td></tr></table>'+
1170 '
<div class=
"settingsInfo" id=
"info' + uniqueId + '">' + text + '
</div>';
1173 function showAbout()
1177 document.getElementById(
"aboutView").style.display =
"block";
1178 document.onclick = null;
1180 window.menu.setLeftSoftkeyLabel(
" ", function(){});
1181 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1187 //document.getElementById(
"aboutView").innerHTML = 'aboutView';
1188 document.getElementById(
"name").innerHTML =
"Coming Next " + version;
1191 function updateFullscreen()
1195 function showFullscreen()
1197 console.info(
"showFullscreen()");
1199 document.getElementById(
"fullscreenView").style.display =
"block";
1200 document.getElementById('body').className =
"backgroundFullscreen";
1201 document.onclick = launchCalendar;
1206 function getBackgroundImage()
1209 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[
0]) // internal
1210 bgImage = 'background_' + orientation + '.png';
1212 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
1216 function updateHomescreen()
1218 if (config['useBackgroundImage'].Value) {
1219 // check for screen rotation
1220 if (orientation != 'portrait' && screen.width ==
360 && screen.height ==
640) {
1221 window.widget.prepareForTransition(
"fade");
1222 orientation = 'portrait';
1223 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1224 document.getElementById('body').style.backgroundColor = 'none';
1225 window.widget.performTransition();
1226 } else if (orientation != 'landscape' && screen.width ==
640 && screen.height ==
360) {
1227 window.widget.prepareForTransition(
"fade");
1228 orientation = 'landscape';
1229 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1230 document.getElementById('body').style.backgroundColor = 'none';
1231 window.widget.performTransition();
1233 else if (document.getElementById('body').style.backgroundImage ==
"")
1235 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1240 function showHomescreen()
1242 console.info(
"showHomescreen()");
1244 document.getElementById(
"homescreenView").style.display =
"block";
1245 document.getElementById('body').className =
"background";
1246 document.onclick = null;
1250 function getLocalizedText(p_Txt)
1252 if (localizedText[p_Txt])
1253 return localizedText[p_Txt];
1255 return 'ERROR: missing translation for ' + p_Txt;
1258 function showUpdate()
1262 document.getElementById(
"updateView").style.display =
"block";
1263 document.onclick = null;
1265 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1268 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1274 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
1278 function checkForUpdate()
1280 // asynch XHR to server url
1281 reqV = new XMLHttpRequest();
1282 reqV.onreadystatechange = checkForUpdateCallback;
1283 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
1284 reqV.open(
"GET", versionURL, true);
1285 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1289 function checkForUpdateCallback()
1291 if (reqV.readyState ==
4) {
1292 if (reqV.status ==
200) {
1293 var resultXml = reqV.responseText;
1295 var div = document.getElementById(
"tmp");
1296 div.innerHTML = resultXml;
1297 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
1298 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
1300 if (version != newVersion) {
1301 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1304 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1309 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1314 function hideViews()
1316 document.getElementById(
"homescreenView").style.display =
"none";
1317 document.getElementById(
"fullscreenView").style.display =
"none";
1318 document.getElementById(
"aboutView").style.display =
"none";
1319 document.getElementById(
"settingsView").style.display =
"none";
1320 document.getElementById(
"updateView").style.display =
"none";
1323 function listCalendars()
1329 DefaultCalendar: false
1333 var calendarsResult = calendarService.IDataSource.GetList(criteria);
1334 if (calendarsResult.ErrorCode !=
0)
1335 throw(
"Error fetching list of calendars: " + calendarsResult.ErrorCode + ': ' + calendarsResult.ErrorMessage);
1336 var calendarListIterator = calendarsResult.ReturnValue;
1341 while (( item = calendarListIterator.getNext()) != undefined ) {
1342 calendars[count++] = item;
1344 console.info(
"Available Calendars: " + calendars.join(
", "));
1347 error('listing calendars:' + e + ', line ' + e.line);
1352 // Copies all objects and their properties to an array. Data is copied so nothing gets lost when the reference is removed
1353 // 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
1354 function listToArray(list, calendarName)
1356 var array = new Array();
1359 while (( item = list.getNext()) != undefined ) {
1360 var itemCopy = new Object();
1361 for(var i=
0; i < entryFields.length; i++) {
1362 itemCopy[entryFields[i]] = item[entryFields[i]];
1364 // for some reason, the CalendarName property is never correctly queried, so we assign it manually here
1365 if (!itemCopy['CalendarName']) {
1366 itemCopy['CalendarName'] = calendarName;
1368 array.push(itemCopy);
1369 txt += array[array.length -
1].Summary +
", ";
1371 console.info(
"listToArray(): " + txt);
1375 function sortCalendarEntries(a, b)
1378 console.info(
"sortCalendarEntries(" + a.Summary +
"," + b.Summary +
")");
1380 if (a.InstanceStartTime != null) {
1381 atime = a.InstanceStartTime;
1383 else if (a.StartTime != null) {
1384 atime = a.StartTime;
1386 else if (a.InstanceEndTime != null) {
1387 atime = a.InstanceEndTime;
1389 else if (a.EndTime != null) {
1393 if (b.InstanceStartTime != null) {
1394 btime = b.InstanceStartTime;
1396 else if (b.StartTime != null) {
1397 btime = b.StartTime;
1399 else if (b.InstanceEndTime != null) {
1400 btime = b.InstanceEndTime;
1402 else if (b.EndTime != null) {
1406 if (atime && btime) {
1408 atime = parseDate(atime);
1409 btime = parseDate(btime);
1411 // sort by date & time
1412 if (atime < btime) {
1415 else if (atime
> btime) {
1419 else if (a.Type != b.Type) {
1420 if (a.Type < b.Type) {
1423 else if (a.Type
> b.Type) {
1427 // sort by description
1428 else if (a.Summary && b.Summary && a.Summary != b.Summary) {
1429 if (a.Summary < b.Summary) {
1432 else if (a.Summary
> b.Summary) {
1441 function updateCalendarColors()
1444 calendarColors = [];
1445 if (calendarList.length
> maxColors) {
1446 console.info(
"updateCalendarColors(): Warning: more calendars than available indicator colors");
1448 for(var i=
0; i < calendarList.length; i++) {
1449 calendarColors[calendarList[i]] = (i % maxColors) +
1;
1455 <style type=
"text/css">
1456 table { margin:
0px; padding:
0px; border-spacing:
0px; }
1457 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
1458 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1459 .settingsInfo { display:none; font-style:italic; }
1460 .title { font-weight:bold; font-size:
14pt; }
1461 .textInput { width:
90%; }
1462 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1463 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
1464 #calendarList { position:absolute; left:
5px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
1465 #name { text-align:center; }
1466 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1467 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1472 <body id=
"body" class=
"background">
1473 <div id=
"homescreenView">
1474 <div id=
"calendarList"></div>
1476 <div id=
"fullscreenView" style=
"display:none;">
1477 <img src=
"Icon.png" id=
"smallappicon">
1478 <h1 class=
"title">Coming Next
</h1>
1480 <div id=
"fullscreenCalendarList">loading...
</div>
1482 <div id=
"settingsView" style=
"display:none">
1483 <img src=
"Icon.png" id=
"smallappicon">
1484 <h1 id=
"settingsTitle" class=
"title">Settings
</h1>
1486 <div id=
"settingsList"></div>
1488 <div id=
"aboutView" style=
"display:none">
1489 <img src=
"Icon.png" id=
"appicon">
1490 <h1 id=
"name">Coming Next
</h1>
1492 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1493 <p>Contributions:
</p>
1494 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1495 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1496 <p class=
"credits">Christophe Milsent (translation support & french translation)
</p>
1497 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation)
</p>
1498 <p class=
"credits">Tokeda (russian translation)
</p>
1499 <p class=
"credits">Marcella Ferrari (italian translation)
</p>
1500 <p class=
"credits">Venos (italian translation)
</p>
1501 <p>This software is open source and licensed under the GPLv3.
</p>
1502 <p>Visit
<a href=
"http://sourceforge.net/projects/comingnext">sourceforge.net/projects/comingnext
</a> for free updates.
</p>
1505 <div id=
"updateView" style=
"display:none">
1506 <img src=
"Icon.png" id=
"smallappicon">
1507 <h1 class=
"title">Check for update
</h1>
1509 <div id=
"currentVersion">Coming Next ??
</div>
1510 <div id=
"updateDiv"></div>
1511 <div id=
"tmp" style=
"display:none;"></div>