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 { }
23 <script type=
"text/javascript" src=
"localizedTextStrings.js" charset=
"utf-8" />
26 // valid types for the config object are 'Int', 'Bool', 'String', 'Enum', 'UID'
28 monthRange: { Type: 'Int', Default:
2, Value:
2,},
29 includeTodos: { Type: 'Bool', Default: true, Value: true,},
30 useBackgroundImage: { Type: 'Bool', Default: true, Value: true,},
31 backgroundImageLocation: { Type: 'Enum', Default: 'internal', Value: 'internal', ValidValues: ['internal', 'external']},
32 showCombinedDateTime: { Type: 'Bool', Default: false, Value: false,},
33 showLocation: { Type: 'Bool', Default: true, Value: true,},
34 showTodayAsText: { Type: 'Bool', Default: true, Value: true,},
35 todayText: { Type: 'String', Default: getLocalizedText('settings.default.todayText'), Value: getLocalizedText('settings.default.todayText'),},
36 tomorrowText: { Type: 'String', Default: getLocalizedText('settings.default.tomorrowText'), Value: getLocalizedText('settings.default.tomorrowText'),},
37 showNowAsText: { Type: 'Bool', Default: true, Value: true,},
38 nowText: { Type: 'String', Default: getLocalizedText('settings.default.nowText'), Value: getLocalizedText('settings.default.nowText'),},
39 markOverdueTodos: { Type: 'Bool', Default: true, Value: true,},
40 overdueText: {Type: 'String', Default: getLocalizedText('settings.default.overdueText'), Value: getLocalizedText('settings.default.overdueText'),},
41 dateSeparator: { Type: 'String', Default: getLocalizedText('settings.default.dateSeparator'), Value: getLocalizedText('settings.default.dateSeparator'),},
42 dateFormat: { Type: 'Enum', Default: 'auto', Value: 'auto', ValidValues: ['auto', 'DDMM', 'MMDD'],},
43 weekDayLength: { Type: 'Int', Default:
2, Value:
2,},
44 updateDataInterval: { Type: 'Int', Default:
5, Value:
5,},
45 calendarApp: { Type: 'UID', Default:
0x10005901, Value:
0x10005901,},
46 eventsPerWidget: { Type: 'Int', Default:
4, Value:
4,},
47 showNothingText: { Type: 'Bool', Default: true, Value: true,},
48 nothingText: { Type: 'String', Default: getLocalizedText('settings.default.nothingText'), Value: getLocalizedText('settings.default.nothingText'),},
49 enableDaylightSaving: { Type: 'Bool', Default: true, Value: true,},
50 hideWidgetOnCalendarOpen: { Type: 'Bool', Default: false, Value: false,},
51 cssStyle_background: { Type: 'String', Default: 'color:#ffffff; background-color:#
000000', Value: 'color:#ffffff; background-color:#
000000',},
52 cssStyle_backgroundFullscreen: { Type: 'String', Default: 'color:#ffffff; background-color:#
000000', Value: 'color:#ffffff; background-color:#
000000',},
53 cssStyle_weekDay: { Type: 'String', Default: '', Value: '',},
54 cssStyle_date: { Type: 'String', Default: '', Value: '',},
55 cssStyle_today: { Type: 'String', Default: 'color:#ff0000', Value: 'color:#ff0000',},
56 cssStyle_tomorrow: { Type: 'String', Default: 'color:#
0000ff', Value: 'color:#
0000ff',},
57 cssStyle_time: { Type: 'String', Default: '', Value: '',},
58 cssStyle_now: { Type: 'String', Default: 'color:#ff00ff', Value: 'color:#ff00ff',},
59 cssStyle_description: { Type: 'String', Default: '', Value: '',},
60 cssStyle_icon: { Type: 'String', Default: 'width:
15px; height:
15px', Value: 'width:
15px; height:
15px',},
61 cssStyle_overdue: { Type: 'String', Default: 'color:#ffff00', Value: 'color:#ffff00',},
66 //-------------------------------------------------------
67 // Nothing of interest from here on...
68 //-------------------------------------------------------
69 var panelNum =
0; // use
1 for second panel
71 var versionURL =
"http://comingnext.sourceforge.net/version.xml";
72 var calendarService = null;
73 var cacheEntriesHtml = [];
74 var months_translated = [];
77 var mode =
0; //
0 = homescreen,
1 = fullscreen,
2 = settings,
3 = about,
4 = check for update
80 // vars for daylight saving time
81 var daylightsavingWinter =
0;
82 var daylightsavingSummer =
0;
83 var summertime = false;
86 window.onresize = updateScreen;
87 window.onshow = updateScreen;
89 function isLeapYear( year ) {
90 if (( year %
4 ==
0 && year %
100 !=
0 ) || year %
400 ==
0 )
96 function calcLeapYear(year, days)
104 function subToSunday(myDate, year, days, prevMonthDays)
106 for (i = myDate.getDay(); i
> 0 ;i--)
108 days -= prevMonthDays;
109 days = isLeapYear(year) ? --days : days;
113 function calcDaylightSaving()
115 var thisYearS = new Date(now.getFullYear(),
3,
0,
0,
0,
0 );
116 var thisYearW = new Date(now.getFullYear(),
10,
0,
0,
0,
0 );
117 var nextYearS = new Date(now.getFullYear() +
1,
3,
0,
0,
0,
0 );
118 var nextYearW = new Date(now.getFullYear() +
1,
10,
0,
0,
0,
0 );
122 thisYearSDays = nextYearSDays =
90;
123 thisYearWDays = nextYearWDays =
304;
125 thisYearSDays = calcLeapYear(now.getFullYear(), thisYearSDays);
126 thisYearWDays = calcLeapYear(now.getFullYear(), thisYearWDays);
127 nextYearSDays = calcLeapYear(now.getFullYear() +
1, nextYearSDays);
128 nextYearWDays = calcLeapYear(now.getFullYear() +
1, nextYearWDays);
130 thisYearSDays = subToSunday(thisYearS, now.getFullYear(), thisYearSDays,
59);
131 thisYearWDays = subToSunday(thisYearW, now.getFullYear(), thisYearWDays,
273);
132 nextYearSDays = subToSunday(nextYearS, now.getFullYear() +
1, nextYearSDays,
59);
133 nextYearWDays = subToSunday(nextYearW, now.getFullYear() +
1, nextYearWDays,
273);
135 daylightsavingSummer = new Date (now.getFullYear(),
03-
1, thisYearSDays,
2,
0,
0);
136 daylightsavingWinter = new Date (now.getFullYear(),
10-
1, thisYearWDays,
2,
0,
0);
137 if (daylightsavingSummer < now) {
138 daylightsavingSummer = new Date (now.getFullYear()+
1,
03-
1, nextYearSDays,
2,
0,
0);
141 if (daylightsavingWinter < now) {
142 daylightsavingWinter = new Date (now.getFullYear()+
1,
10-
1, nextYearWDays,
2,
0,
0);
145 if (summer && !winter)
151 function error(message)
153 console.info('Error: ' + message);
154 document.getElementById(
"calendarList").innerHTML = 'Error: ' + message;
157 function areDatesEqual(date1, date2)
159 return (date1.getFullYear() == date2.getFullYear() &&
160 date1.getMonth() == date2.getMonth() &&
161 date1.getDate() == date2.getDate());
164 function isTomorrow(date)
166 // tommorow = now +
1 day
167 // ToDo: some days can be shorter as
24 hours(daylight saving change day)
168 return areDatesEqual(date, new Date (now.getTime() +
24*
60*
60*
1000));
171 function isToday(date)
173 return areDatesEqual(date, now);
176 function collectLocales()
178 var tmpyear = ((panelNum ==
0) ?
2000 :
2001);
181 if (months_translated.length
> 0)
183 for (month =
0; month <
12; month++) {
184 var startDate = new Date(tmpyear, month,
15);
186 var item = new Object();
187 item.Type =
"DayEvent";
188 item.StartTime = startDate;
189 item.Summary =
"__temp" + month;
191 var criteria = new Object();
192 criteria.Type =
"CalendarEntry";
193 criteria.Item = item;
196 var result = calendarService.IDataSource.Add(criteria);
197 if (result.ErrorCode)
198 error(result.ErrorMessage);
200 error(
"collectLocales: " + e + ', line ' + e.line);
204 var startTime = new Date(tmpyear,
0,
1);
205 var endTime = new Date(tmpyear,
11,
31);
206 var listFiltering = {
207 Type:'CalendarEntry',
209 StartRange: startTime,
211 SearchText: '__temp',
215 var result = calendarService.IDataSource.GetList(listFiltering);
216 if (result.ErrorCode) {
217 error(result.ErrorMessage);
220 var list = result.ReturnValue;
222 error(e + ', line ' + e.line);
225 var ids = new Array();
231 while (list && (entry = list.getNext()) != undefined) {
232 dateArr = entry.StartTime.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
233 var day = dateArr[
1];
234 var month = dateArr[
2];
235 var year = dateArr[
3];
237 // make sure month is set properly
238 if (isNaN(parseInt(day))) {
242 } else if (isNaN(parseInt(year))) {
248 console.info(entry.StartTime + ' -
> ' + month + ' ' + counter);
249 ids[counter] = entry.id;
250 months_translated[month] = counter +
1;
254 error(e + ', line ' + e.line);
259 var criteria = new Object();
260 criteria.Type =
"CalendarEntry";
265 var result = calendarService.IDataSource.Delete(criteria);
266 if (result.ErrorCode)
267 error(result.ErrorMessage);
269 error('deleting temp calendar entries:' + e + ', line ' + e.line);
274 function requestNotification()
276 var criteria = new Object();
277 criteria.Type =
"CalendarEntry";
280 var result = calendarService.IDataSource.RequestNotification(criteria, callback);
281 if (result.ErrorCode)
282 error('loading Calendar items list');
284 error(
"requestNotification: " + e + ', line ' + e.line);
288 function callback(transId, eventCode, result)
293 function parseDate(dateString)
296 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:
297 Wednesday,
26 August,
2009 24:
00:
00
298 Wednesday,
26 August,
2009 12:
00:
00 am
299 Wednesday, August
26,
2009 12:
00:
00 am
300 Wednesday,
2009 August,
26 12:
00:
00 am
301 Wednesday,
2009 August,
28 8.00.00 pm
302 Wednesday,
2009 August,
28 08:
00:
00 PM
305 if (dateString ==
"" || dateString == null)
307 var dateArr = dateString.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
308 if (dateArr.length !=
5 && dateArr.length !=
6)
312 var weekDay = dateArr[
0];
313 var day = dateArr[
1];
314 var month = dateArr[
2];
315 var year = dateArr[
3];
316 // make sure month is set properly
317 if (isNaN(parseInt(day))) {
321 } else if (isNaN(parseInt(year))) {
326 // make sure day and year are set properly
327 if (Number(day)
> Number(year)) {
332 month = months_translated[month];
335 var timeArr = dateArr[
4].split(':');
336 if (timeArr.length !=
3)
338 var hours = Number(timeArr[
0]);
339 var minutes = Number(timeArr[
1]);
340 var seconds = Number(timeArr[
2]);
341 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'pm' && hours <
12)
343 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'am' && hours ==
12)
346 console.info('year=' + year + ' month=' + month + ' day=' + day + ' hours=' + hours + ' minutes=' + minutes+ ' seconds=' + seconds);
348 // take care of daylight saving time
349 if (config['enableDaylightSaving'].Value) {
350 var date = new Date(year, month -
1, day, hours, minutes, seconds);
351 if (summertime && date
> daylightsavingWinter && date < daylightsavingSummer)
353 else if (!summertime && date
> daylightsavingSummer && date < daylightsavingWinter)
357 return new Date(year, month -
1, day, hours, minutes, seconds);
360 // 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"
361 function formatDate(date, format)
363 var day = date.getDate().toString();
364 var month = (date.getMonth() +
1).toString();
365 while (day.length <
2) { day = '
0' + day; }
366 while (month.length <
2) { month = '
0' + month; }
368 if (config['showTodayAsText'].Value && isToday(date))
369 return '
<span class=
"today">' + config['todayText'].Value + '
</span>';
370 if (config['showTodayAsText'].Value && isTomorrow(date))
371 return '
<span class=
"tomorrow">' + config['tomorrowText'].Value + '
</span>';
373 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
374 if (dateArr.length !=
5 && dateArr.length !=
6) {
375 // we don't know how to format this
376 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
377 return day + config['dateSeparator'].Value + month;
379 return month + config['dateSeparator'].Value + day;
383 if (config['dateFormat'].Value == 'MMDD')
385 else if (config['dateFormat'].Value == 'DDMM')
388 // config['dateFormat'].Value == 'auto', try to detect system setting
390 var day_ = dateArr[
1];
391 var month_ = dateArr[
2];
392 var year_ = dateArr[
3];
393 // make sure month is set properly
394 if (isNaN(parseInt(day_))) {
399 } else if (isNaN(parseInt(year_))) {
405 // make sure day and year are set properly
406 if (Number(day_)
> Number(year_))
411 return day + config['dateSeparator'].Value + month;
413 return month + config['dateSeparator'].Value + day;
416 function formatTime(date)
418 // date is a Date() object
419 date.setSeconds(
0); // we don't care about seconds
420 var time = date.toLocaleTimeString().replace(/[\.:]
00/, ''); // remove seconds from string
421 if (time.replace(/\./, ':').split(':')[
0].length <
2)
423 if (config['showNowAsText'].Value && date.getTime() == now.getTime())
424 time = '
<span class=
"now">' + config['nowText'].Value + '
</span>';
428 function updateData()
430 console.info('updateData()');
431 calcDaylightSaving();
433 // meetings have time
434 // 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
436 var meetingListFiltering = {
437 Type:'CalendarEntry',
439 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
440 EndRange: (new Date(now.getFullYear(), now.getMonth() + config['monthRange'].Value, now.getDate(),
0,
0,
0))
443 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
444 if (meetingResult.ErrorCode !=
0)
445 throw(
"Error fetching calendar data: " + meetingResult.ErrorCode + ': ' + meetingResult.ErrorMessage);
446 var meetingList = meetingResult.ReturnValue;
448 // todos don't, they start on
00:
00 hrs., but should be visible anyway
449 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
450 if (config['includeTodos'].Value) {
451 var todayTodoListFiltering = {
452 Type:'CalendarEntry',
455 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
456 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
459 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
460 var todayTodoList = todayTodoResult.ReturnValue;
461 var entryLists = [todayTodoList, meetingList];
463 var entryLists = [meetingList];
466 error('loading Calendar items list:' + e + ', line ' + e.line);
475 var entriesHtml = '
<table>';
479 max = ((panelNum ==
0) ? config['eventsPerWidget'].Value :
2 * config['eventsPerWidget'].Value);
481 max =
30; // we can display a lot more events in fullscreen mode
483 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
484 for (var i=
0; counter < max && i < entryLists.length; i++) {
485 while (counter < max && (entry = entryLists[i].getNext()) != undefined) {
488 // output event info for debugging
490 'event: Id=' + entry.id +
491 ',Type=' + entry.Type +
492 ',Summary=' + entry.Summary +
493 ',Location=' + entry.Location +
494 ',Status=' + entry.Status +
495 ',StartTime=' + entry.StartTime +
496 ',EndTime=' + entry.EndTime +
497 ',InstanceStartTime=' + entry.InstanceStartTime +
498 ',InstanceEndTime=' + entry.InstanceEndTime
501 // we don't want ToDos when includeTodos == false or when they are completed
502 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !config['includeTodos'].Value)) {
503 console.info('skipping ' + entry.id );
508 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
509 if (eventIds[entry.id] ==
1 && entry.Type == 'ToDo') {
510 console.info('skipped (already included) ' + entry.id);
514 eventIds[entry.id] =
1;
516 // summary can be undefined!
517 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
518 if (entry.Type == 'Meeting' && entry.Location != '' && config['showLocation'].Value)
519 Summary += ', ' + entry.Location;
521 // fix by yves: determine start and end dates/times
522 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
523 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
525 // there can be ToDos that have no date at all!
526 if (entry.Type == 'ToDo' && entry.EndTime == null)
527 entryDate =
""; // this will cause parseDate(entryDate) to return null;
529 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
531 // Convert date/time string to Date object
532 var date = parseDate(entryDate);
533 console.info('date: ' + date);
534 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
535 console.info('endDate: ' + endDate);
537 // check if meeting event has already passed
538 if (entry.Type == 'Meeting') {
539 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
540 if (now.getTime()
> compareTime) {
541 console.info('skipping Meeting (already passed) ' + entry.id);
543 eventIds[entry.id] =
0;
548 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
549 if (entry.Type == 'Anniversary') {
550 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
551 if (date.getTime() < tmp.getTime()) {
552 console.info('skipping Anniversary (already passed) ' + entry.id);
554 eventIds[entry.id] =
0;
559 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
560 if (entry.Type == 'DayEvent' && endDate != null) {
561 endDate.setMinutes(endDate.getMinutes() -
1);
562 console.info('fixing DayEvent endDate: ' + endDate);
563 if (now.getTime()
> endDate.getTime()) {
564 console.info('event already passed ' + entry.id);
566 eventIds[entry.id] =
0;
571 // check if the event is currently taking place
572 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
573 // check if we are between start and endtime
574 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
575 date = now; // change appointment date/time to now
576 console.info('event is currently taking place: ' + date);
580 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
581 if (mode ==
0 && panelNum ==
1 && counter < config['eventsPerWidget'].Value +
1) {
582 console.info('skipping (already in first widget) ' + entry.id);
586 // mark overdue todos
588 if (entry.Type == 'ToDo') {
589 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(),
0,
0,
0);
590 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
591 if (tmp1.getTime() < tmp2.getTime()) {
596 // generate html output
597 entriesHtml += '
<tr><td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
599 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
600 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
602 var weekDay = date.toLocaleDateString().substr(
0,config['weekDayLength'].Value);
603 var time = formatTime(date);
604 var dateStr = formatDate(date, entryDate);
605 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
606 dateStr = '
<span class=
"overdue">Overdue
</span>';
607 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
608 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
609 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
610 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"date">' + dateStr + '
</span> ';
612 entriesHtml += '
<td class=
"weekDay" width=
"1px">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
613 } else if (entry.Type == 'Meeting') {
614 if (config['showCombinedDateTime'].Value) {
616 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
617 else if (isTomorrow(date))
618 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
620 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
622 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
623 entriesHtml += '
<td colspan=
"4" width=
"1px"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
625 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
629 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
632 entriesHtml += '
</table>';
633 if (config['showNothingText'].Value && entriesHtml == '
<table></table>') {
634 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
635 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '
</div>';
637 if (cacheEntriesHtml != entriesHtml) {
639 document.getElementById('calendarList').innerHTML = entriesHtml;
641 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
642 cacheEntriesHtml = entriesHtml;
645 error('displaying list:' + e + ', line ' + e.line);
650 function updateScreen()
652 // check if opening fullscreen
653 if( window.innerHeight
> 91 && mode ==
0) {
655 cacheEntriesHtml = '';
656 document.getElementById('body').style.backgroundImage =
"";
659 else if (window.innerHeight <=
91 && mode !=
0) {
661 cacheEntriesHtml = '';
671 function launchCalendar()
674 widget.openApplication(config['calendarApp'].Value,
"");
675 if (config['hideWidgetOnCalendarOpen'].Value)
678 error('starting Calendar App');
685 console.info('New widget instance starting up...');
688 // call calendar service
689 if (device !=
"undefined")
690 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
692 throw('device object does not exist');
694 error('loading Calendar service: ' + e + ', line ' + e.line);
702 requestNotification();
703 window.setInterval('updateData()',
1000 *
60 * config['updateDataInterval'].Value);
708 if (config['useBackgroundImage'].Value)
709 // check for screen rotation every
1 secs
710 window.setInterval('updateScreen()',
1000 *
1);
713 function createMenu()
715 window.menu.setLeftSoftkeyLabel(
"",null);
716 window.menu.setRightSoftkeyLabel(
"",null);
718 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
719 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
720 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
721 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
722 menuSettings.onSelect = showSettings;
723 menuAbout.onSelect = showAbout;
724 menuCallApp.onSelect = launchCalendar;
725 menuUpdate.onSelect = showUpdate;
727 window.menu.append(menuCallApp);
728 window.menu.append(menuSettings);
729 window.menu.append(menuUpdate);
730 window.menu.append(menuAbout);
733 function showSettings()
737 document.getElementById(
"settingsView").style.display =
"block";
738 document.onclick = null;
740 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
742 for (var key in config) {
743 if (config[key].Type == 'String')
744 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
745 else if (config[key].Type == 'Int') {
746 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
747 if (config[key].Value <
0)
748 config[key].Value = config[key].Default;
750 else if (config[key].Type == 'Bool')
751 config[key].Value = document.forms[
0].elements[
"settings." + key].checked;
752 else if (config[key].Type == 'UID')
753 config[key].Value = parseInt(document.forms[
0].elements[
"settings." + key].value);
754 else if (config[key].Type == 'Enum') {
755 config[key].Value = document.forms[
0].elements[
"settings." + key].value;
756 if (config[key].ValidValues.indexOf(config[key].Value) == -
1)
757 config[key].Value = config[key].Default;
768 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
774 var settingsHtml = '
<form>';
775 for (var key in config) {
776 if (config[key].Type == 'String')
777 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 />';
778 else if (config[key].Type == 'Int')
779 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 />';
780 else if (config[key].Type == 'Bool')
781 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 />';
782 else if (config[key].Type == 'UID')
783 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 />';
784 else if (config[key].Type == 'Enum') {
785 settingsHtml += '
<table><tr><td>' + getLocalizedText('settings.name.' + key) + '
<br /><select name=
"settings.' + key + '" size=
"1">';
786 for(var i =
0; i < config[key].ValidValues.length; i++)
787 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>';
788 settingsHtml += '
</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '
<hr />';
791 settingsHtml += '
<input name=
"reset" type=
"button" value=
"' + getLocalizedText('settings.restoreDefaults') + '" onclick=
"javascript:restoreDefaultSettings();showSettings();" />';
792 settingsHtml += '
</form>';
793 document.getElementById(
"settingsList").innerHTML = settingsHtml;
796 function changeCssClass(classname, properties)
798 for(var i =
0; i < document.styleSheets[
0]['cssRules'].length; i++)
800 if (document.styleSheets[
0]['cssRules'][i].selectorText == classname) {
801 document.styleSheets[
0].deleteRule(i);
802 document.styleSheets[
0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[
0]['cssRules'].length);
808 function updateCssClasses()
810 for(var key in config) {
811 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
815 function restoreDefaultSettings()
817 for (var key in config)
818 config[key].Value = config[key].Default;
821 function loadSettings()
823 for (var key in config) {
824 if (widget.preferenceForKey(key)) {
825 if (config[key].Type == 'Int')
826 config[key].Value = Number(widget.preferenceForKey(key));
827 else if (config[key].Type == 'String')
828 config[key].Value = widget.preferenceForKey(key);
829 else if (config[key].Type == 'Bool')
830 config[key].Value = (widget.preferenceForKey(key) == 'true')
831 else if (config[key].Type == 'Enum')
832 config[key].Value = widget.preferenceForKey(key);
833 else if (config[key].Type == 'UID')
834 config[key].Value = Number(widget.preferenceForKey(key));
837 config[key].Value = config[key].Default;
838 console.info('Settings: ' + key + '=\'' + config[key].Value + '\'');
842 function saveSettings()
844 for (var key in config) {
845 if (config[key].Type == 'Int')
846 widget.setPreferenceForKey(config[key].Value.toString(), key);
847 else if (config[key].Type == 'String')
848 widget.setPreferenceForKey(config[key].Value, key);
849 else if (config[key].Type == 'Bool')
850 widget.setPreferenceForKey(config[key].Value ? 'true' : 'false', key);
851 else if (config[key].Type == 'Enum')
852 widget.setPreferenceForKey(config[key].Value, key);
853 else if (config[key].Type == 'UID')
854 widget.setPreferenceForKey(config[key].Value.toString(), key);
858 function toggleVisibility(elementId)
860 if (document.getElementById(elementId).style.display ==
"none")
861 document.getElementById(elementId).style.display =
"block";
863 document.getElementById(elementId).style.display =
"none";
867 function printHintBox(text)
870 return '
<td width=
"1%" align=
"right" onclick=
"javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '
</td></tr></table>'+
871 '
<div class=
"settingsInfo" id=
"info' + uniqueId + '">' + text + '
</div>';
878 document.getElementById(
"aboutView").style.display =
"block";
879 document.onclick = null;
881 window.menu.setLeftSoftkeyLabel(
" ", function(){});
882 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
888 //document.getElementById(
"aboutView").innerHTML = 'aboutView';
889 document.getElementById(
"name").innerHTML =
"Coming Next " + version;
892 function updateFullscreen()
896 function showFullscreen()
899 document.getElementById(
"fullscreenView").style.display =
"block";
900 document.getElementById('body').className =
"backgroundFullscreen";
901 document.onclick = launchCalendar;
906 function getBackgroundImage()
909 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[
0]) // internal
910 bgImage = 'background_' + orientation + '.png';
912 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
916 function updateHomescreen()
918 if (config['useBackgroundImage'].Value) {
919 // check for screen rotation
920 if (orientation != 'portrait' && screen.width ==
360 && screen.height ==
640) {
921 window.widget.prepareForTransition(
"fade");
922 orientation = 'portrait';
923 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
924 document.getElementById('body').style.backgroundColor = 'none';
925 window.widget.performTransition();
926 } else if (orientation != 'landscape' && screen.width ==
640 && screen.height ==
360) {
927 window.widget.prepareForTransition(
"fade");
928 orientation = 'landscape';
929 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
930 document.getElementById('body').style.backgroundColor = 'none';
931 window.widget.performTransition();
933 else if (document.getElementById('body').style.backgroundImage ==
"")
935 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
940 function showHomescreen()
943 document.getElementById(
"homescreenView").style.display =
"block";
944 document.getElementById('body').className =
"background";
945 document.onclick = null;
949 function getLocalizedText(p_Txt)
951 if (localizedText[p_Txt])
952 return localizedText[p_Txt];
954 return 'ERROR: missing translation for ' + p_Txt;
957 function showUpdate()
961 document.getElementById(
"updateView").style.display =
"block";
962 document.onclick = null;
964 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
967 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
973 document.getElementById(
"currentVersion").innerHTML = getLocalizedText(
"update.current") + version;
977 function checkForUpdate()
979 // asynch XHR to server url
980 reqV = new XMLHttpRequest();
981 reqV.onreadystatechange = checkForUpdateCallback;
982 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.checking");
983 reqV.open(
"GET", versionURL, true);
984 reqV.setRequestHeader(
"If-Modified-Since",
"Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
988 function checkForUpdateCallback()
990 if (reqV.readyState ==
4) {
991 if (reqV.status ==
200) {
992 var resultXml = reqV.responseText;
994 var div = document.getElementById(
"tmp");
995 div.innerHTML = resultXml;
996 var newVersion = div.getElementsByTagName('version')[
0].innerHTML;
997 var newVersionURL = div.getElementsByTagName('url')[
0].innerHTML;
999 if (version != newVersion) {
1000 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.download").replace(/%
1/, newVersion).replace(/%
2/, newVersionURL);
1003 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.nonewversion");
1008 document.getElementById(
"updateDiv").innerHTML = getLocalizedText(
"update.error") + reqV.status +
" " + reqV.responseText;
1013 function hideViews()
1015 document.getElementById(
"homescreenView").style.display =
"none";
1016 document.getElementById(
"fullscreenView").style.display =
"none";
1017 document.getElementById(
"aboutView").style.display =
"none";
1018 document.getElementById(
"settingsView").style.display =
"none";
1019 document.getElementById(
"updateView").style.display =
"none";
1023 <style type=
"text/css">
1024 table { margin:
0px; padding:
0px; border-spacing:
0px; }
1025 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
1026 hr { color:#ffffff; background-color:#ffffff; height:
1px; text-align:left; border-style:none; }
1027 .settingsInfo { display:none; font-style:italic; }
1028 .title { font-weight:bold; font-size:
14pt; }
1029 .textInput { width:
90%; }
1030 .credits { margin-left:
40px; text-indent: -
20px; margin-bottom:
0px; }
1031 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
1032 #calendarList { position:absolute; left:
10px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
1033 #name { text-align:center; }
1034 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top:
10px; }
1035 #smallappicon { width:
22px; height:
22px; margin-right:
10px; float:left; }
1040 <body id=
"body" class=
"background">
1041 <div id=
"homescreenView">
1042 <div id=
"calendarList"></div>
1044 <div id=
"fullscreenView" style=
"display:none;">
1045 <img src=
"Icon.png" id=
"smallappicon">
1046 <h1 class=
"title">Coming Next
</h1>
1048 <div id=
"fullscreenCalendarList">loading...
</div>
1050 <div id=
"settingsView" style=
"display:none">
1051 <img src=
"Icon.png" id=
"smallappicon">
1052 <h1 class=
"title">Settings
</h1>
1054 <div id=
"settingsList"></div>
1056 <div id=
"aboutView" style=
"display:none">
1057 <img src=
"Icon.png" id=
"appicon">
1058 <h1 id=
"name">Coming Next
</h1>
1060 <p>Created by Dr. Cochambre and Michael Prager.
</p>
1061 <p>Contributions:
</p>
1062 <p class=
"credits">Paul Moore (bug fixes, new features and code cleanup)
</p>
1063 <p class=
"credits">Manfred Hanselmann (DST support)
</p>
1064 <p class=
"credits">Christophe Milsent (translation support & french translation
</p>
1065 <p class=
"credits">Flavio Nathan (portuguese-brazilian translation
</p>
1066 <p>This software is open source and licensed under the GPLv3.
</p>
1067 <p>Visit sourceforge.net/projects/comingnext for free updates.
</p>
1070 <div id=
"updateView" style=
"display:none">
1071 <img src=
"Icon.png" id=
"smallappicon">
1072 <h1 class=
"title">Check for update
</h1>
1074 <div id=
"currentVersion">Coming Next ??
</div>
1075 <div id=
"updateDiv"></div>
1076 <div id=
"tmp" style=
"display:none;"></div>