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 /* -----------------------------------------------------------------------
10 here you can customize background color, font color, font size etc...
11 --------------------------------------------------------------------------- */
12 .background { color:#ffffff; background-color:#
000000; font:normal
12pt; } /* Defines the background of the widget. If you want to use a background image, set useBackgroundImage = true below */
13 /* for the default themes, black, gray, and light blue, codes are #
292029, #e7dfe7, #
009aef */
14 .weekDay { } /* Defines the appearance of all week day texts */
15 .date { } /* Defines the appearance of all date texts */
16 .today { color:#ff0000; } /* Defines the appearance of
"Today" text */
17 .time { } /* Defines the appearance of all time texts */
18 .now { color:#ff00ff; } /* Defines the appearance of
"Now" text */
19 .description { } /* Defines the appearance of all event descriptions */
20 .icon { width:
15px; height:
15px; } /* Defines size and appearance of icons */
25 //---------------------------------------------------------------
26 // The following section contains settings you may want to tweak
27 //---------------------------------------------------------------
28 var monthRange =
2; // number of months to include in the event list
29 var includeTodos = true; // disable to remove ToDos from event list
30 var useBackgroundImage = true; // use background_portrait.png and background_landscape.png to fake transparency. Set to
"false" to use a solid background color
31 var showCombinedDateTime = false;// only show the time for events happening today, otherwise just show the date
32 var showLocation = true; // show the location for meeting events
33 var showTodayAsText = true; // if enabled, the current date will be shown as
"Today" instead of
"31.12"
34 var todayText = 'Today'; // text to display for
"Today"
35 var showNowAsText = true; // if enabled, the appointment time will be shown as
"Now" instead of
"12:00"
36 var nowText = 'Now'; // text to display for
"Now"
37 var dateSeparator = '.'; // separator for dates. e.g.
"31.12" or
"31/12"
38 var dateFormat = 'auto' // how dates will be displayed. 'auto' will autodetect your phone's date format setting. 'MMDD' will write month first, 'DDMM' will write day first
39 var weekDayLength =
2; // defines how many characters of the weekday will be shown. E.g.
2 will cut
"Friday" to
"Fr"
40 var updateDataInterval =
5; // how many minutes to wait before updating the displayed data. The higher the number, the less battery is used
41 var calendarApp =
0x10005901; // UID of the calendar app to run when clicking the widget.
0x10005901 = buildin calendar,
0x20004ec1 = Epocware Handy Calendar
42 var eventsPerWidget =
4; // number of events to show per widget. Default is
4
43 var showNothingText = true; // if set to
"true", show a text if no events are in the list
44 var nothingText = 'No further events within ' + monthRange + ' months'; // text to show when no events are in the list
45 var enableDaylightSaving = true;// enable this if you are in a timezone that has daylight saving time (+
1h)
47 //-------------------------------------------------------
48 // Nothing of interest from here on...
49 //-------------------------------------------------------
50 var panelNum =
0; // use
1 for second panel
51 var calendarService = null;
52 var cacheEntriesHtml = [];
53 var months_translated = [];
57 // vars for daylight saving time
58 var daylightsavingWinter =
0;
59 var daylightsavingSummer =
0;
60 var summertime = false;
63 window.onresize = updateScreen;
64 window.onshow = updateScreen;
66 function isLeapYear( year ) {
67 if (( year %
4 ==
0 && year %
100 !=
0 ) || year %
400 ==
0 )
73 function calcLeapYear(year, days)
81 function subToSunday(myDate, year, days, prevMonthDays)
83 for (i = myDate.getDay(); i
> 0 ;i--)
85 days -= prevMonthDays;
86 days = isLeapYear(year) ? --days : days;
90 function calcDaylightSaving()
92 var thisYearS = new Date(now.getFullYear(),
3,
0,
0,
0,
0 );
93 var thisYearW = new Date(now.getFullYear(),
10,
0,
0,
0,
0 );
94 var nextYearS = new Date(now.getFullYear() +
1,
3,
0,
0,
0,
0 );
95 var nextYearW = new Date(now.getFullYear() +
1,
10,
0,
0,
0,
0 );
99 thisYearSDays = nextYearSDays =
90;
100 thisYearWDays = nextYearWDays =
304;
102 thisYearSDays = calcLeapYear(now.getFullYear(), thisYearSDays);
103 thisYearWDays = calcLeapYear(now.getFullYear(), thisYearWDays);
104 nextYearSDays = calcLeapYear(now.getFullYear() +
1, nextYearSDays);
105 nextYearWDays = calcLeapYear(now.getFullYear() +
1, nextYearWDays);
107 thisYearSDays = subToSunday(thisYearS, now.getFullYear(), thisYearSDays,
59);
108 thisYearWDays = subToSunday(thisYearW, now.getFullYear(), thisYearWDays,
273);
109 nextYearSDays = subToSunday(nextYearS, now.getFullYear() +
1, nextYearSDays,
59);
110 nextYearWDays = subToSunday(nextYearW, now.getFullYear() +
1, nextYearWDays,
273);
112 daylightsavingSummer = new Date (now.getFullYear(),
03-
1, thisYearSDays,
2,
0,
0);
113 daylightsavingWinter = new Date (now.getFullYear(),
10-
1, thisYearWDays,
2,
0,
0);
114 if (daylightsavingSummer < now) {
115 daylightsavingSummer = new Date (now.getFullYear()+
1,
03-
1, nextYearSDays,
2,
0,
0);
118 if (daylightsavingWinter < now) {
119 daylightsavingWinter = new Date (now.getFullYear()+
1,
10-
1, nextYearWDays,
2,
0,
0);
122 if (summer && !winter)
128 function error(message)
130 console.info('Error: ' + message);
131 document.getElementById(
"calendarList").innerHTML = 'Error: ' + message;
134 function isToday(date)
136 if (date.getDate() == now.getDate() && date.getMonth() == now.getMonth())
141 function collectLocales()
143 var tmpyear = ((panelNum ==
0) ?
2000 :
2001);
146 if (months_translated.length
> 0)
148 for (month =
0; month <
12; month++) {
149 var startDate = new Date(tmpyear, month,
15);
151 var item = new Object();
152 item.Type =
"DayEvent";
153 item.StartTime = startDate;
154 item.Summary =
"__temp" + month;
156 var criteria = new Object();
157 criteria.Type =
"CalendarEntry";
158 criteria.Item = item;
161 var result = calendarService.IDataSource.Add(criteria);
162 if (result.ErrorCode)
163 error(result.ErrorMessage);
165 error(
"collectLocales: " + e + ', line ' + e.line);
169 var startTime = new Date(tmpyear,
0,
1);
170 var endTime = new Date(tmpyear,
11,
31);
171 var listFiltering = {
172 Type:'CalendarEntry',
174 StartRange: startTime,
176 SearchText: '__temp',
180 var result = calendarService.IDataSource.GetList(listFiltering);
181 if (result.ErrorCode) {
182 error(result.ErrorMessage);
185 var list = result.ReturnValue;
187 error(e + ', line ' + e.line);
190 var ids = new Array();
196 while (list && (entry = list.getNext()) != undefined) {
197 dateArr = entry.StartTime.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
198 var day = dateArr[
1];
199 var month = dateArr[
2];
200 var year = dateArr[
3];
202 // make sure month is set properly
203 if (isNaN(parseInt(day))) {
207 } else if (isNaN(parseInt(year))) {
213 console.info(entry.StartTime + ' -
> ' + month + ' ' + counter);
214 ids[counter] = entry.id;
215 months_translated[month] = counter +
1;
219 error(e + ', line ' + e.line);
224 var criteria = new Object();
225 criteria.Type =
"CalendarEntry";
230 var result = calendarService.IDataSource.Delete(criteria);
231 if (result.ErrorCode)
232 error(result.ErrorMessage);
234 error('deleting temp calendar entries:' + e + ', line ' + e.line);
239 function requestNotification()
241 var criteria = new Object();
242 criteria.Type =
"CalendarEntry";
245 var result = calendarService.IDataSource.RequestNotification(criteria, callback);
246 if (result.ErrorCode)
247 error('loading Calendar items list');
249 error(
"requestNotification: " + e + ', line ' + e.line);
253 function callback(transId, eventCode, result)
258 function parseDate(dateString)
261 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:
262 Wednesday,
26 August,
2009 24:
00:
00
263 Wednesday,
26 August,
2009 12:
00:
00 am
264 Wednesday, August
26,
2009 12:
00:
00 am
265 Wednesday,
2009 August,
26 12:
00:
00 am
266 Wednesday,
2009 August,
28 8.00.00 pm
267 Wednesday,
2009 August,
28 08:
00:
00 PM
270 if (dateString ==
"" || dateString == null)
272 var dateArr = dateString.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
273 if (dateArr.length !=
5 && dateArr.length !=
6)
277 var weekDay = dateArr[
0];
278 var day = dateArr[
1];
279 var month = dateArr[
2];
280 var year = dateArr[
3];
281 // make sure month is set properly
282 if (isNaN(parseInt(day))) {
286 } else if (isNaN(parseInt(year))) {
291 // make sure day and year are set properly
292 if (Number(day)
> Number(year)) {
297 month = months_translated[month];
300 var timeArr = dateArr[
4].split(':');
301 if (timeArr.length !=
3)
303 var hours = Number(timeArr[
0]);
304 var minutes = Number(timeArr[
1]);
305 var seconds = Number(timeArr[
2]);
306 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'pm' && hours <
12)
308 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'am' && hours ==
12)
311 console.info('year=' + year + ' month=' + month + ' day=' + day + ' hours=' + hours + ' minutes=' + minutes+ ' seconds=' + seconds);
313 // take care of daylight saving time
314 if (enableDaylightSaving) {
315 var date = new Date(year, month -
1, day, hours, minutes, seconds);
316 if (summertime && date
> daylightsavingWinter && date < daylightsavingSummer)
318 else if (!summertime && date
> daylightsavingSummer && date < daylightsavingWinter)
322 return new Date(year, month -
1, day, hours, minutes, seconds);
325 // 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"
326 function formatDate(date, format)
328 var day = date.getDate().toString();
329 var month = (date.getMonth() +
1).toString();
330 while (day.length <
2) { day = '
0' + day; }
331 while (month.length <
2) { month = '
0' + month; }
333 if (showTodayAsText && isToday(date))
334 return '
<span class=
"today">' + todayText + '
</span>';
336 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
337 if (dateArr.length !=
5 && dateArr.length !=
6) {
338 // we don't know how to format this
339 if (dateFormat == 'auto' || dateFormat == 'DDMM')
340 return day + dateSeparator + month;
342 return month + dateSeparator + day;
346 if (dateFormat == 'MMDD')
348 else if (dateFormat == 'DDMM')
351 // dateFormat == 'auto', try to detect system setting
353 var day_ = dateArr[
1];
354 var month_ = dateArr[
2];
355 var year_ = dateArr[
3];
356 // make sure month is set properly
357 if (isNaN(parseInt(day_))) {
362 } else if (isNaN(parseInt(year_))) {
368 // make sure day and year are set properly
369 if (Number(day_)
> Number(year_))
374 return day + dateSeparator + month;
376 return month + dateSeparator + day;
379 function formatTime(date)
381 // date is a Date() object
382 date.setSeconds(
0); // we don't care about seconds
383 var time = date.toLocaleTimeString().replace(/[\.:]
00/, ''); // remove seconds from string
384 if (time.replace(/\./, ':').split(':')[
0].length <
2)
386 if (showNowAsText && date.getTime() == now.getTime())
387 time = '
<span class=
"now">' + nowText + '
</span>';
391 function updateData()
393 calcDaylightSaving();
395 // meetings have time
396 // 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
398 var meetingListFiltering = {
399 Type:'CalendarEntry',
401 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
402 EndRange: (new Date(now.getFullYear(), now.getMonth() + monthRange, now.getDate(),
0,
0,
0))
405 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
406 var meetingList = meetingResult.ReturnValue;
408 // todos don't, they start on
00:
00 hrs., but should be visible anyway
409 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
411 var todayTodoListFiltering = {
412 Type:'CalendarEntry',
415 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
416 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
419 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
420 var todayTodoList = todayTodoResult.ReturnValue;
421 var entryLists = [todayTodoList, meetingList];
423 var entryLists = [meetingList];
426 error('loading Calendar items list:' + e + ', line ' + e.line);
435 var entriesHtml = '
<table>';
437 var max = ((panelNum ==
0) ? eventsPerWidget :
2 * eventsPerWidget);
439 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
440 for (var i=
0; counter < max && i < entryLists.length; i++) {
441 while (counter < max && (entry = entryLists[i].getNext()) != undefined) {
444 // output event info for debugging
446 'event: Id=' + entry.id +
447 ',Type=' + entry.Type +
448 ',Summary=' + entry.Summary +
449 ',Location=' + entry.Location +
450 ',Status=' + entry.Status +
451 ',StartTime=' + entry.StartTime +
452 ',EndTime=' + entry.EndTime +
453 ',InstanceStartTime=' + entry.InstanceStartTime +
454 ',InstanceEndTime=' + entry.InstanceEndTime
457 // we don't want ToDos when includeTodos == false or when they are completed
458 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !includeTodos)) {
459 console.info('skipping ' + entry.id );
464 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
465 if (eventIds[entry.id] ==
1) {
466 console.info('skipped (already included) ' + entry.id);
470 eventIds[entry.id] =
1;
472 // summary can be undefined!
473 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
474 if (entry.Type == 'Meeting' && entry.Location != '' && showLocation)
475 Summary += ', ' + entry.Location;
477 // fix by yves: determine start and end dates/times
478 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
479 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
481 // there can be ToDos that have no date at all!
482 if (entry.Type == 'ToDo' && entry.EndTime == null)
483 entryDate =
""; // this will cause parseDate(entryDate) to return null;
485 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
487 // Convert date/time string to Date object
488 var date = parseDate(entryDate);
489 console.info('date: ' + date);
490 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
491 console.info('endDate: ' + endDate);
493 // check if meeting event has already passed
494 if (entry.Type == 'Meeting') {
495 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
496 if (now.getTime()
> compareTime) {
497 console.info('skipping Meeting (already passed) ' + entry.id);
499 eventIds[entry.id] =
0;
504 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
505 if (entry.Type == 'Anniversary') {
506 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
507 if (date.getTime() < tmp.getTime()) {
508 console.info('skipping Anniversary (already passed) ' + entry.id);
510 eventIds[entry.id] =
0;
515 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
516 if (entry.Type == 'DayEvent' && endDate != null) {
517 endDate.setMinutes(endDate.getMinutes() -
1);
518 console.info('fixing DayEvent endDate: ' + endDate);
519 if (now.getTime()
> endDate.getTime()) {
520 console.info('event already passed ' + entry.id);
522 eventIds[entry.id] =
0;
527 // check if the event is currently taking place
528 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
529 // check if we are between start and endtime
530 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
531 date = now; // change appointment date/time to now
532 console.info('event is currently taking place: ' + date);
536 // skip events for the first panel in case this is the second one
537 if (panelNum ==
1 && counter < eventsPerWidget +
1) {
538 console.info('skipping (already in first widget) ' + entry.id);
542 // generate html output
543 entriesHtml += '
<tr><td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
545 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
546 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
548 var weekDay = date.toLocaleDateString().substr(
0,weekDayLength);
549 var time = formatTime(date);
550 var dateStr = formatDate(date, entryDate);
551 if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
552 if (isToday(date) && showTodayAsText) // show weekday if the date string is not text. looks odd otherwise
553 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + dateStr + '
</span> ';
555 entriesHtml += '
<td class=
"weekDay">' + weekDay + '
</td><td class=
"date">' + dateStr + '
</td><td colspan=
"2">';
556 } else if (entry.Type == 'Meeting') {
557 if (showCombinedDateTime) {
559 entriesHtml += '
<td colspan=
"4"><span class=
"today">' + time + '
</span> ';
561 entriesHtml += '
<td class=
"weekDay">' + weekDay + '
</td><td class=
"date">' + dateStr + '
</td><td colspan=
"2">';
563 if (isToday(date) && showTodayAsText)
564 entriesHtml += '
<td colspan=
"4"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
566 entriesHtml += '
<td class=
"weekDay">' + weekDay + '
</td><td class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
570 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
573 entriesHtml += '
</table>';
574 if (showNothingText && entriesHtml == '
<table></table>')
575 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + nothingText + '
</div>';
576 if (cacheEntriesHtml != entriesHtml) {
577 document.getElementById('calendarList').innerHTML = entriesHtml;
578 cacheEntriesHtml = entriesHtml;
581 error('displaying list:' + e + ', line ' + e.line);
586 function updateScreen()
588 // check if opening fullscreen
589 if( window.innerHeight
> 91)
592 if (useBackgroundImage) {
593 // check for screen rotation
594 if (orientation != 'portrait' && screen.width ==
360 && screen.height ==
640) {
595 window.widget.prepareForTransition(
"fade");
596 orientation = 'portrait';
597 document.getElementById('body').style.backgroundImage = 'url(background_' + orientation + '.png)';
598 document.getElementById('body').style.backgroundColor = 'none';
599 window.widget.performTransition();
600 } else if (orientation != 'landscape' && screen.width ==
640 && screen.height ==
360) {
601 window.widget.prepareForTransition(
"fade");
602 orientation = 'landscape';
603 document.getElementById('body').style.backgroundImage = 'url(background_' + orientation + '.png)';
604 document.getElementById('body').style.backgroundColor = 'none';
605 window.widget.performTransition();
610 function launchCalendar()
613 widget.openApplication(calendarApp,
"");
616 error('starting Calendar App');
624 // call calendar service
625 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
627 error('loading Calendar service');
633 requestNotification();
634 window.setInterval('updateData()',
1000 *
60 * updateDataInterval);
637 if (useBackgroundImage)
638 // check for screen rotation every
3 secs
639 window.setInterval('updateScreen()',
1000 *
3);
644 <style type=
"text/css">
645 table { margin:
0px; padding:
0px; border-spacing:
0px; }
646 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
647 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
648 #calendarList { position:absolute; left:
10px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
653 <body id=
"body" class=
"background">
654 <div id=
"homescreenView">
655 <div id=
"calendarList"></div>