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 .tomorrow { color:#
0000ff; } /* Defines the appearance of
"Tomorrow" text */
18 .time { } /* Defines the appearance of all time texts */
19 .now { color:#ff00ff; } /* Defines the appearance of
"Now" text */
20 .description { } /* Defines the appearance of all event descriptions */
21 .icon { width:
15px; height:
15px; } /* Defines size and appearance of icons */
26 //---------------------------------------------------------------
27 // The following section contains settings you may want to tweak
28 //---------------------------------------------------------------
29 var monthRange =
2; // number of months to include in the event list
30 var includeTodos = true; // disable to remove ToDos from event list
31 var useBackgroundImage = true; // use background_portrait.png and background_landscape.png to fake transparency. Set to
"false" to use a solid background color
32 var showCombinedDateTime = false;// only show the time for events happening today, otherwise just show the date
33 var showLocation = true; // show the location for meeting events
34 var showTodayAsText = true; // if enabled, the current date will be shown as
"Today" instead of
"31.12"
35 var todayText = 'Today'; // text to display for
"Today"
36 var tomorrowText = 'Tomorrow'; // text to display for
"Tomorrow"
37 var showNowAsText = true; // if enabled, the appointment time will be shown as
"Now" instead of
"12:00"
38 var nowText = 'Now'; // text to display for
"Now"
39 var dateSeparator = '.'; // separator for dates. e.g.
"31.12" or
"31/12"
40 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
41 var weekDayLength =
2; // defines how many characters of the weekday will be shown. E.g.
2 will cut
"Friday" to
"Fr"
42 var updateDataInterval =
5; // how many minutes to wait before updating the displayed data. The higher the number, the less battery is used
43 var calendarApp =
0x10005901; // UID of the calendar app to run when clicking the widget.
0x10005901 = buildin calendar,
0x20004ec1 = Epocware Handy Calendar
44 var eventsPerWidget =
4; // number of events to show per widget. Default is
4
45 var showNothingText = true; // if set to
"true", show a text if no events are in the list
46 var nothingText = 'No further events within ' + monthRange + ' months'; // text to show when no events are in the list
47 var enableDaylightSaving = true;// enable this if you are in a timezone that has daylight saving time (+
1h)
49 //-------------------------------------------------------
50 // Nothing of interest from here on...
51 //-------------------------------------------------------
52 var panelNum =
0; // use
1 for second panel
53 var calendarService = null;
54 var cacheEntriesHtml = [];
55 var months_translated = [];
59 // vars for daylight saving time
60 var daylightsavingWinter =
0;
61 var daylightsavingSummer =
0;
62 var summertime = false;
65 window.onresize = updateScreen;
66 window.onshow = updateScreen;
68 function isLeapYear( year ) {
69 if (( year %
4 ==
0 && year %
100 !=
0 ) || year %
400 ==
0 )
75 function calcLeapYear(year, days)
83 function subToSunday(myDate, year, days, prevMonthDays)
85 for (i = myDate.getDay(); i
> 0 ;i--)
87 days -= prevMonthDays;
88 days = isLeapYear(year) ? --days : days;
92 function calcDaylightSaving()
94 var thisYearS = new Date(now.getFullYear(),
3,
0,
0,
0,
0 );
95 var thisYearW = new Date(now.getFullYear(),
10,
0,
0,
0,
0 );
96 var nextYearS = new Date(now.getFullYear() +
1,
3,
0,
0,
0,
0 );
97 var nextYearW = new Date(now.getFullYear() +
1,
10,
0,
0,
0,
0 );
101 thisYearSDays = nextYearSDays =
90;
102 thisYearWDays = nextYearWDays =
304;
104 thisYearSDays = calcLeapYear(now.getFullYear(), thisYearSDays);
105 thisYearWDays = calcLeapYear(now.getFullYear(), thisYearWDays);
106 nextYearSDays = calcLeapYear(now.getFullYear() +
1, nextYearSDays);
107 nextYearWDays = calcLeapYear(now.getFullYear() +
1, nextYearWDays);
109 thisYearSDays = subToSunday(thisYearS, now.getFullYear(), thisYearSDays,
59);
110 thisYearWDays = subToSunday(thisYearW, now.getFullYear(), thisYearWDays,
273);
111 nextYearSDays = subToSunday(nextYearS, now.getFullYear() +
1, nextYearSDays,
59);
112 nextYearWDays = subToSunday(nextYearW, now.getFullYear() +
1, nextYearWDays,
273);
114 daylightsavingSummer = new Date (now.getFullYear(),
03-
1, thisYearSDays,
2,
0,
0);
115 daylightsavingWinter = new Date (now.getFullYear(),
10-
1, thisYearWDays,
2,
0,
0);
116 if (daylightsavingSummer < now) {
117 daylightsavingSummer = new Date (now.getFullYear()+
1,
03-
1, nextYearSDays,
2,
0,
0);
120 if (daylightsavingWinter < now) {
121 daylightsavingWinter = new Date (now.getFullYear()+
1,
10-
1, nextYearWDays,
2,
0,
0);
124 if (summer && !winter)
130 function error(message)
132 console.info('Error: ' + message);
133 document.getElementById(
"calendarList").innerHTML = 'Error: ' + message;
136 function isToday(date)
138 if (date.getDate() == now.getDate() && date.getMonth() == now.getMonth())
143 function isTomorrow(date)
145 if ((date.getDate() == now.getDate() +
1 && date.getMonth() == now.getMonth()) ||
146 (date.getDate() ==
0 && date.getMonth() == now.getMonth() +
1) ||
147 (date.getDate() ==
0 && date.getMonth() == now.getMonth() +
1 && date.getYear() == now.getYear() +
1))
152 function collectLocales()
154 var tmpyear = ((panelNum ==
0) ?
2000 :
2001);
157 if (months_translated.length
> 0)
159 for (month =
0; month <
12; month++) {
160 var startDate = new Date(tmpyear, month,
15);
162 var item = new Object();
163 item.Type =
"DayEvent";
164 item.StartTime = startDate;
165 item.Summary =
"__temp" + month;
167 var criteria = new Object();
168 criteria.Type =
"CalendarEntry";
169 criteria.Item = item;
172 var result = calendarService.IDataSource.Add(criteria);
173 if (result.ErrorCode)
174 error(result.ErrorMessage);
176 error(
"collectLocales: " + e + ', line ' + e.line);
180 var startTime = new Date(tmpyear,
0,
1);
181 var endTime = new Date(tmpyear,
11,
31);
182 var listFiltering = {
183 Type:'CalendarEntry',
185 StartRange: startTime,
187 SearchText: '__temp',
191 var result = calendarService.IDataSource.GetList(listFiltering);
192 if (result.ErrorCode) {
193 error(result.ErrorMessage);
196 var list = result.ReturnValue;
198 error(e + ', line ' + e.line);
201 var ids = new Array();
207 while (list && (entry = list.getNext()) != undefined) {
208 dateArr = entry.StartTime.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
209 var day = dateArr[
1];
210 var month = dateArr[
2];
211 var year = dateArr[
3];
213 // make sure month is set properly
214 if (isNaN(parseInt(day))) {
218 } else if (isNaN(parseInt(year))) {
224 console.info(entry.StartTime + ' -
> ' + month + ' ' + counter);
225 ids[counter] = entry.id;
226 months_translated[month] = counter +
1;
230 error(e + ', line ' + e.line);
235 var criteria = new Object();
236 criteria.Type =
"CalendarEntry";
241 var result = calendarService.IDataSource.Delete(criteria);
242 if (result.ErrorCode)
243 error(result.ErrorMessage);
245 error('deleting temp calendar entries:' + e + ', line ' + e.line);
250 function requestNotification()
252 var criteria = new Object();
253 criteria.Type =
"CalendarEntry";
256 var result = calendarService.IDataSource.RequestNotification(criteria, callback);
257 if (result.ErrorCode)
258 error('loading Calendar items list');
260 error(
"requestNotification: " + e + ', line ' + e.line);
264 function callback(transId, eventCode, result)
269 function parseDate(dateString)
272 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:
273 Wednesday,
26 August,
2009 24:
00:
00
274 Wednesday,
26 August,
2009 12:
00:
00 am
275 Wednesday, August
26,
2009 12:
00:
00 am
276 Wednesday,
2009 August,
26 12:
00:
00 am
277 Wednesday,
2009 August,
28 8.00.00 pm
278 Wednesday,
2009 August,
28 08:
00:
00 PM
281 if (dateString ==
"" || dateString == null)
283 var dateArr = dateString.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
284 if (dateArr.length !=
5 && dateArr.length !=
6)
288 var weekDay = dateArr[
0];
289 var day = dateArr[
1];
290 var month = dateArr[
2];
291 var year = dateArr[
3];
292 // make sure month is set properly
293 if (isNaN(parseInt(day))) {
297 } else if (isNaN(parseInt(year))) {
302 // make sure day and year are set properly
303 if (Number(day)
> Number(year)) {
308 month = months_translated[month];
311 var timeArr = dateArr[
4].split(':');
312 if (timeArr.length !=
3)
314 var hours = Number(timeArr[
0]);
315 var minutes = Number(timeArr[
1]);
316 var seconds = Number(timeArr[
2]);
317 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'pm' && hours <
12)
319 if (dateArr.length ==
6 && dateArr[
5].toLowerCase() == 'am' && hours ==
12)
322 console.info('year=' + year + ' month=' + month + ' day=' + day + ' hours=' + hours + ' minutes=' + minutes+ ' seconds=' + seconds);
324 // take care of daylight saving time
325 if (enableDaylightSaving) {
326 var date = new Date(year, month -
1, day, hours, minutes, seconds);
327 if (summertime && date
> daylightsavingWinter && date < daylightsavingSummer)
329 else if (!summertime && date
> daylightsavingSummer && date < daylightsavingWinter)
333 return new Date(year, month -
1, day, hours, minutes, seconds);
336 // 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"
337 function formatDate(date, format)
339 var day = date.getDate().toString();
340 var month = (date.getMonth() +
1).toString();
341 while (day.length <
2) { day = '
0' + day; }
342 while (month.length <
2) { month = '
0' + month; }
344 if (showTodayAsText && isToday(date))
345 return '
<span class=
"today">' + todayText + '
</span>';
346 if (showTodayAsText && isTomorrow(date))
347 return '
<span class=
"tomorrow">' + tomorrowText + '
</span>';
349 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
350 if (dateArr.length !=
5 && dateArr.length !=
6) {
351 // we don't know how to format this
352 if (dateFormat == 'auto' || dateFormat == 'DDMM')
353 return day + dateSeparator + month;
355 return month + dateSeparator + day;
359 if (dateFormat == 'MMDD')
361 else if (dateFormat == 'DDMM')
364 // dateFormat == 'auto', try to detect system setting
366 var day_ = dateArr[
1];
367 var month_ = dateArr[
2];
368 var year_ = dateArr[
3];
369 // make sure month is set properly
370 if (isNaN(parseInt(day_))) {
375 } else if (isNaN(parseInt(year_))) {
381 // make sure day and year are set properly
382 if (Number(day_)
> Number(year_))
387 return day + dateSeparator + month;
389 return month + dateSeparator + day;
392 function formatTime(date)
394 // date is a Date() object
395 date.setSeconds(
0); // we don't care about seconds
396 var time = date.toLocaleTimeString().replace(/[\.:]
00/, ''); // remove seconds from string
397 if (time.replace(/\./, ':').split(':')[
0].length <
2)
399 if (showNowAsText && date.getTime() == now.getTime())
400 time = '
<span class=
"now">' + nowText + '
</span>';
404 function updateData()
406 calcDaylightSaving();
408 // meetings have time
409 // 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
411 var meetingListFiltering = {
412 Type:'CalendarEntry',
414 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0)),
415 EndRange: (new Date(now.getFullYear(), now.getMonth() + monthRange, now.getDate(),
0,
0,
0))
418 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
419 var meetingList = meetingResult.ReturnValue;
421 // todos don't, they start on
00:
00 hrs., but should be visible anyway
422 // this will generate a list of passed todos. We have to check if they have been marked as
"done" yet
424 var todayTodoListFiltering = {
425 Type:'CalendarEntry',
428 StartRange: (new Date(now.getFullYear() -
1, now.getMonth(), now.getDate(),
0,
0,
0)),
429 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
1))
432 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
433 var todayTodoList = todayTodoResult.ReturnValue;
434 var entryLists = [todayTodoList, meetingList];
436 var entryLists = [meetingList];
439 error('loading Calendar items list:' + e + ', line ' + e.line);
448 var entriesHtml = '
<table>';
450 var max = ((panelNum ==
0) ? eventsPerWidget :
2 * eventsPerWidget);
452 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
453 for (var i=
0; counter < max && i < entryLists.length; i++) {
454 while (counter < max && (entry = entryLists[i].getNext()) != undefined) {
457 // output event info for debugging
459 'event: Id=' + entry.id +
460 ',Type=' + entry.Type +
461 ',Summary=' + entry.Summary +
462 ',Location=' + entry.Location +
463 ',Status=' + entry.Status +
464 ',StartTime=' + entry.StartTime +
465 ',EndTime=' + entry.EndTime +
466 ',InstanceStartTime=' + entry.InstanceStartTime +
467 ',InstanceEndTime=' + entry.InstanceEndTime
470 // we don't want ToDos when includeTodos == false or when they are completed
471 if (entry.Type == 'ToDo' && (entry.Status ==
"TodoCompleted" || !includeTodos)) {
472 console.info('skipping ' + entry.id );
477 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
478 if (eventIds[entry.id] ==
1) {
479 console.info('skipped (already included) ' + entry.id);
483 eventIds[entry.id] =
1;
485 // summary can be undefined!
486 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
487 if (entry.Type == 'Meeting' && entry.Location != '' && showLocation)
488 Summary += ', ' + entry.Location;
490 // fix by yves: determine start and end dates/times
491 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
492 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
494 // there can be ToDos that have no date at all!
495 if (entry.Type == 'ToDo' && entry.EndTime == null)
496 entryDate =
""; // this will cause parseDate(entryDate) to return null;
498 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
500 // Convert date/time string to Date object
501 var date = parseDate(entryDate);
502 console.info('date: ' + date);
503 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
504 console.info('endDate: ' + endDate);
506 // check if meeting event has already passed
507 if (entry.Type == 'Meeting') {
508 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
509 if (now.getTime()
> compareTime) {
510 console.info('skipping Meeting (already passed) ' + entry.id);
512 eventIds[entry.id] =
0;
517 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
518 if (entry.Type == 'Anniversary') {
519 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(),
0,
0,
0);
520 if (date.getTime() < tmp.getTime()) {
521 console.info('skipping Anniversary (already passed) ' + entry.id);
523 eventIds[entry.id] =
0;
528 // fix DayEvents end time. End times are off by
1 Second. It's possible that the event has already passed
529 if (entry.Type == 'DayEvent' && endDate != null) {
530 endDate.setMinutes(endDate.getMinutes() -
1);
531 console.info('fixing DayEvent endDate: ' + endDate);
532 if (now.getTime()
> endDate.getTime()) {
533 console.info('event already passed ' + entry.id);
535 eventIds[entry.id] =
0;
540 // check if the event is currently taking place
541 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
542 // check if we are between start and endtime
543 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
544 date = now; // change appointment date/time to now
545 console.info('event is currently taking place: ' + date);
549 // skip events for the first panel in case this is the second one
550 if (panelNum ==
1 && counter < eventsPerWidget +
1) {
551 console.info('skipping (already in first widget) ' + entry.id);
555 // generate html output
556 entriesHtml += '
<tr><td><img class=
"icon" src=
"' + entry.Type + '.png" /></td>';
558 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
559 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + entryDate + '
</span> ';
561 var weekDay = date.toLocaleDateString().substr(
0,weekDayLength);
562 var time = formatTime(date);
563 var dateStr = formatDate(date, entryDate);
564 if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
565 if ((isToday(date) || isTomorrow(date)) && showTodayAsText) // show weekday if the date string is not text. looks odd otherwise
566 entriesHtml += '
<td colspan=
"4"><span class=
"date">' + dateStr + '
</span> ';
568 entriesHtml += '
<td class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
569 } else if (entry.Type == 'Meeting') {
570 if (showCombinedDateTime) {
572 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"today">' + time + '
</span> ';
573 else if (isTomorrow(date))
574 entriesHtml += '
<td width=
"1px" colspan=
"4"><span class=
"tomorrow">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
576 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td colspan=
"2">';
578 if ((isToday(date) || isTomorrow(date)) && showTodayAsText)
579 entriesHtml += '
<td colspan=
"4"><span class=
"today">' + dateStr + '
</span> <span class=
"time">' + time + '
</span> ';
581 entriesHtml += '
<td width=
"1px" class=
"weekDay">' + weekDay + '
</td><td width=
"1px" class=
"date">' + dateStr + '
</td><td width=
"1px" class=
"time">' + time + '
</td><td>';
585 entriesHtml += '
<span class=
"description">' + Summary + '
</span></td></tr>';
588 entriesHtml += '
</table>';
589 if (showNothingText && entriesHtml == '
<table></table>')
590 entriesHtml = '
<div style=
"width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + nothingText + '
</div>';
591 if (cacheEntriesHtml != entriesHtml) {
592 document.getElementById('calendarList').innerHTML = entriesHtml;
593 cacheEntriesHtml = entriesHtml;
596 error('displaying list:' + e + ', line ' + e.line);
601 function updateScreen()
603 // check if opening fullscreen
604 if( window.innerHeight
> 91)
607 if (useBackgroundImage) {
608 // check for screen rotation
609 if (orientation != 'portrait' && screen.width ==
360 && screen.height ==
640) {
610 window.widget.prepareForTransition(
"fade");
611 orientation = 'portrait';
612 document.getElementById('body').style.backgroundImage = 'url(background_' + orientation + '.png)';
613 document.getElementById('body').style.backgroundColor = 'none';
614 window.widget.performTransition();
615 } else if (orientation != 'landscape' && screen.width ==
640 && screen.height ==
360) {
616 window.widget.prepareForTransition(
"fade");
617 orientation = 'landscape';
618 document.getElementById('body').style.backgroundImage = 'url(background_' + orientation + '.png)';
619 document.getElementById('body').style.backgroundColor = 'none';
620 window.widget.performTransition();
625 function launchCalendar()
628 widget.openApplication(calendarApp,
"");
631 error('starting Calendar App');
639 // call calendar service
640 calendarService = device.getServiceObject(
"Service.Calendar",
"IDataSource");
642 error('loading Calendar service');
648 requestNotification();
649 window.setInterval('updateData()',
1000 *
60 * updateDataInterval);
652 if (useBackgroundImage)
653 // check for screen rotation every
3 secs
654 window.setInterval('updateScreen()',
1000 *
3);
659 <style type=
"text/css">
660 table { margin:
0px; padding:
0px; border-spacing:
0px; }
661 td { padding:
0px
5px
0px
0px; white-space:nowrap; overflow:hidden; }
662 #homescreenView { width:
315px; height:
91px; overflow:hidden; }
663 #calendarList { position:absolute; left:
10px; top:
4px; width:
295px; height:
75px; overflow:hidden; }
668 <body id=
"body" class=
"background">
669 <div id=
"homescreenView">
670 <div id=
"calendarList"></div>