]> code.delx.au - comingnext/blob - comingNextB/index.html
* fixed memos/anniversaries showing although they have already passed
[comingnext] / comingNextB / index.html
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">
4 <head>
5 <title>Coming Next</title>
6 <style type="text/css">
7 /* -----------------------------------------------------------------------
8 here you can customize background color, font color, font size etc...
9 --------------------------------------------------------------------------- */
10 .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 */
11 .weekDay { } /* Defines the appearance of all week day texts */
12 .date { } /* Defines the appearance of all date texts */
13 .today { color:#ff0000; } /* Defines the appearance of "Today" text */
14 .time { } /* Defines the appearance of all time texts */
15 .now { color:#ff00ff; } /* Defines the appearance of "Now" text */
16 .description { } /* Defines the appearance of all event descriptions */
17 .icon { width:15px; height:15px; } /* Defines size and appearance of icons */
18 </style>
19 <script>
20 //---------------------------------------------------------------
21 // The following section contains settings you may want to tweak
22 //---------------------------------------------------------------
23 var monthRange = 2; // number of months to include in the event list
24 var includeTodos = true; // disable to remove ToDos from event list
25 var useBackgroundImage = true; // use background_portrait.png and background_landscape.png to fake transparency. Set to "false" to use a solid background color
26 var showCombinedDateTime = false;// only show the time for events happening today, otherwise just show the date
27 var showLocation = true; // show the location for meeting events
28 var showTodayAsText = true; // if enabled, the current date will be shown as "Today" instead of "31.12"
29 var todayText = 'Today'; // text to display for "Today"
30 var showNowAsText = true; // if enabled, the appointment time will be shown as "Now" instead of "12:00"
31 var nowText = 'Now'; // text to display for "Now"
32 var dateSeparator = '.'; // separator for dates. e.g. "31.12" or "31/12"
33 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
34 var weekDayLength = 2; // defines how many characters of the weekday will be shown. E.g. 2 will cut "Friday" to "Fr"
35 var updateDataInterval = 5; // how many minutes to wait before updating the displayed data. The higher the number, the less battery is used
36 var calendarApp = 0x10005901; // UID of the calendar app to run when clicking the widget. 0x10005901 = buildin calendar, 0x20004ec1 = Epocware Handy Calendar
37 var eventsPerWidget = 4; // number of events to show per widget. Default is 4
38 var showNothingText = true; // if set to "true", show a text if no events are in the list
39 var nothingText = 'No further events within '+monthRange+' months'; // text to show when no events are in the list
40
41 //-------------------------------------------------------
42 // Nothing of interest from here on...
43 //-------------------------------------------------------
44 var panelNum = 1; // use 1 for second panel
45 var calendarService = null;
46 var cacheEntriesHtml = [];
47 var months_translated = [];
48 var orientation = '';
49 var now = new Date();
50
51 window.onload = init;
52 window.onresize = updateScreen;
53 window.onshow = updateScreen;
54
55 function error(message){
56 console.info('Error: ' + message);
57 document.getElementById("calendarList").innerHTML = 'Error: ' + message;
58 }
59
60 function collectLocales(){
61 if (months_translated.length > 0){
62 return;
63 }
64 var tmpyear = ((panelNum == 0) ? 2000 : 2001);
65 var month = 0;
66 for(month = 0; month < 12; month++){
67 var startDate = new Date(tmpyear, month, 15);
68 var item = new Object();
69 item.Type = "DayEvent";
70 item.StartTime = startDate;
71 item.Summary = "__temp" + month;
72
73 var criteria = new Object();
74 criteria.Type = "CalendarEntry";
75 criteria.Item = item;
76
77 try {
78 var result = calendarService.IDataSource.Add(criteria);
79 if (result.ErrorCode){
80 error(result.ErrorMessage);
81 }
82 }
83 catch (e) {
84 error("collectLocales: " + e + ', line ' + e.line);
85 }
86 }
87 try{
88 var startTime = new Date(tmpyear,0,1);
89 var endTime = new Date(tmpyear,11,31);
90 var listFiltering = {
91 Type:'CalendarEntry',
92 Filter:{
93 StartRange: startTime,
94 EndRange: endTime,
95 SearchText: '__temp',
96 Type: 'DayEvent'
97 }
98 }
99 var result = calendarService.IDataSource.GetList(listFiltering);
100 if (result.ErrorCode){
101 error(result.ErrorMessage);
102 return;
103 }
104 var list = result.ReturnValue;
105 }catch(e){
106 error(e + ', line ' + e.line);
107 return;
108 }
109 var ids = new Array();
110 try{
111 var entry;
112 var counter = 0;
113 var dateArr = [];
114 while( list && (entry = list.getNext()) != undefined ){
115 dateArr = entry.StartTime.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
116 var day = dateArr[1];
117 var month = dateArr[2];
118 var year = dateArr[3];
119 // make sure month is set properly
120 if (isNaN(parseInt(day))){
121 var tmp = day;
122 day = month;
123 month = tmp;
124 }
125 else if (isNaN(parseInt(year))){
126 var tmp = year;
127 year = month;
128 month = tmp;
129 }
130 console.info(entry.StartTime + ' -> ' + month + ' ' + counter);
131 ids[counter] = entry.id;
132 months_translated[month] = counter + 1;
133 counter++;
134 }
135 }catch(e){
136 error(e + ', line ' + e.line);
137 return;
138 }
139 console.info(ids);
140 try{
141 var criteria = new Object();
142 criteria.Type = "CalendarEntry";
143 criteria.Data = {
144 IdList: ids
145 }
146 var result = calendarService.IDataSource.Delete(criteria);
147 if (result.ErrorCode)
148 error(result.ErrorMessage);
149 }catch(e){
150 error('deleting temp calendar entries:' + e + ', line ' + e.line);
151 return;
152 }
153 }
154
155 function requestNotification(){
156 var criteria = new Object();
157 criteria.Type = "CalendarEntry";
158 try {
159 var result = calendarService.IDataSource.RequestNotification(criteria, callback);
160 if (result.ErrorCode)
161 error('loading Calendar items list');
162 }
163 catch (e) {
164 error("requestNotification: " + e + ', line ' + e.line);
165 }
166 }
167
168 function callback(transId, eventCode, result){
169 updateData();
170 }
171
172 function parseDate(dateString)
173 {
174 /*
175 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:
176 Wednesday, 26 August, 2009 24:00:00
177 Wednesday, 26 August, 2009 12:00:00 am
178 Wednesday, August 26, 2009 12:00:00 am
179 Wednesday, 2009 August, 26 12:00:00 am
180 Wednesday, 2009 August, 28 8.00.00 pm
181 Wednesday, 2009 August, 28 08:00:00 PM
182 */
183 if (dateString == "" || dateString == null)
184 return null;
185
186 var dateArr = dateString.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
187
188 if (dateArr.length != 5 && dateArr.length != 6)
189 return null;
190
191 // parse date
192 var weekDay = dateArr[0];
193 var day = dateArr[1];
194 var month = dateArr[2];
195 var year = dateArr[3];
196 // make sure month is set properly
197 if (isNaN(parseInt(day))){
198 var tmp = day;
199 day = month;
200 month = tmp;
201 }
202 else if (isNaN(parseInt(year))){
203 var tmp = year;
204 year = month;
205 month = tmp;
206 }
207 // make sure day and year are set properly
208 if (Number(day) > Number(year))
209 {
210 var tmp = year;
211 year = day;
212 day = tmp;
213 }
214 month = months_translated[month];
215
216 // parse time
217 var timeArr = dateArr[4].split(':');
218 if (timeArr.length != 3)
219 return null;
220 var hours = Number(timeArr[0]);
221 var minutes = Number(timeArr[1]);
222 var seconds = Number(timeArr[2]);
223 if (dateArr.length == 6 && dateArr[5].toLowerCase() == 'pm' && hours < 12)
224 hours += 12;
225 if (dateArr.length == 6 && dateArr[5].toLowerCase() == 'am' && hours == 12)
226 hours = 0;
227
228 console.info('year=' + year + ' month=' + month + ' day=' + day + ' hours=' + hours + ' minutes=' + minutes+ ' seconds=' + seconds);
229
230 return new Date(year, month - 1, day, hours, minutes, seconds);
231 }
232
233 // 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"
234 function formatDate(date, format)
235 {
236 var day = date.getDate().toString();
237 var month = (date.getMonth() + 1).toString();
238 while (day.length < 2) { day = '0' + day; }
239 while (month.length < 2) { month = '0' + month; }
240
241 if (showTodayAsText && now.getDate() == date.getDate() && now.getMonth() == date.getMonth())
242 return '<span class="today">' + todayText + '</span>';
243
244 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
245
246 if (dateArr.length != 5 && dateArr.length != 6){
247 // we don't know how to format this
248 if (dateFormat == 'auto' || dateFormat == 'DDMM')
249 return day + dateSeparator + month;
250 else
251 return month + dateSeparator + day;
252 }
253
254 var dayFirst = true;
255 if (dateFormat == 'MMDD')
256 dayFirst = false;
257 else if (dateFormat == 'DDMM')
258 dayFirst = true;
259 else { // dateFormat == 'auto', try to detect system setting
260 // parse date
261 var day_ = dateArr[1];
262 var month_ = dateArr[2];
263 var year_ = dateArr[3];
264 // make sure month is set properly
265 if (isNaN(parseInt(day_))){
266 var tmp = day_;
267 day_ = month_;
268 month_ = tmp;
269 dayFirst = false;
270 }
271 else if (isNaN(parseInt(year_))){
272 var tmp = year_;
273 year_ = month_;
274 month_ = tmp;
275 dayFirst = true;
276 }
277 // make sure day and year are set properly
278 if (Number(day_) > Number(year_))
279 dayFirst = false;
280 }
281
282 if (dayFirst)
283 return day + dateSeparator + month;
284 else
285 return month + dateSeparator + day;
286 }
287
288 function formatTime(date)
289 {
290 // date is a Date() object
291 date.setSeconds(0); // we don't care about seconds
292 var time = date.toLocaleTimeString().replace(/[\.:]00/, ''); // remove seconds from string
293 if (time.replace(/\./, ':').split(':')[0].length < 2)
294 time = '0' + time;
295 if (showNowAsText && date.getTime() == now.getTime())
296 time = '<span class="now">' + nowText + '</span>';
297 return time;
298 }
299
300 function updateData(){
301 try{
302 // meetings have time
303 // 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
304 now = new Date();
305 var meetingListFiltering = {
306 Type:'CalendarEntry',
307 Filter:{
308 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0)),
309 EndRange: (new Date(now.getFullYear(), now.getMonth() + monthRange, now.getDate(), 0, 0, 0))
310 }
311 }
312 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
313 var meetingList = meetingResult.ReturnValue;
314 // todos don't, they start on 00:00 hrs., but should be visible anyway
315 // this will generate a list of passed todos. We have to check if they have been marked as "done" yet
316 if (includeTodos){
317 var todayTodoListFiltering = {
318 Type:'CalendarEntry',
319 Filter:{
320 Type: 'ToDo',
321 StartRange: (new Date(now.getFullYear() - 1, now.getMonth(), now.getDate(), 0, 0, 0)),
322 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 1))
323 }
324 }
325 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
326 var todayTodoList = todayTodoResult.ReturnValue;
327 var entryLists = [todayTodoList, meetingList];
328 } else {
329 var entryLists = [meetingList];
330 }
331 }catch(e){
332 error('loading Calendar items list:' + e + ', line ' + e.line);
333 return;
334 }
335
336 try{
337 var entry;
338 var counter = 0;
339 var entryDate = '';
340 var dateArr = [];
341 var entriesHtml = '<table>';
342 var eventIds = [];
343 var max = ((panelNum == 0) ? eventsPerWidget : 2 * eventsPerWidget);
344 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
345 for(var i=0; counter < max && i < entryLists.length; i++){
346 while( counter < max && (entry = entryLists[i].getNext()) != undefined ){
347 counter++;
348
349 // output event info for debugging
350 console.info(
351 'event: Id=' + entry.id +
352 ',Type=' + entry.Type +
353 ',Summary=' + entry.Summary +
354 ',Location=' + entry.Location +
355 ',Status=' + entry.Status +
356 ',StartTime=' + entry.StartTime +
357 ',EndTime=' + entry.EndTime +
358 ',InstanceStartTime=' + entry.InstanceStartTime +
359 ',InstanceEndTime=' + entry.InstanceEndTime
360 );
361
362 // we don't want ToDos when includeTodos == false or when they are completed
363 if (entry.Type == 'ToDo' && (entry.Status == "TodoCompleted" || !includeTodos)){
364 console.info('skipping ' + entry.id );
365 counter--;
366 continue;
367 }
368
369 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
370 if (eventIds[entry.id] == 1){
371 console.info('skipped (already included) ' + entry.id);
372 counter--;
373 continue;
374 } else
375 eventIds[entry.id] = 1;
376
377 // summary can be undefined!
378 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
379 if (entry.Type == 'Meeting' && entry.Location != '' && showLocation){
380 Summary += ', ' + entry.Location;
381 }
382
383 // fix by yves: determine start and end dates/times
384 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
385 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
386
387 // there can be ToDos that have no date at all!
388 if (entry.Type == 'ToDo' && entry.EndTime == null)
389 entryDate = ""; // this will cause parseDate(entryDate) to return null;
390 else
391 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
392
393 // Convert date/time string to Date object
394 var date = parseDate(entryDate);
395 console.info('date: ' + date);
396 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
397 console.info('endDate: ' + endDate);
398
399 // check if meeting event has already passed
400 if (entry.Type == 'Meeting'){
401 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
402 if (now.getTime() > compareTime){
403 console.info('skipping Meeting (already passed) ' + entry.id);
404 counter--;
405 eventIds[entry.id] = 0;
406 continue;
407 }
408 }
409
410 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
411 if (entry.Type == 'Anniversary'){
412 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0,0,0);
413 if ( date.getTime() < tmp.getTime() ){
414 console.info('skipping Anniversary (already passed) ' + entry.id);
415 counter--;
416 eventIds[entry.id] = 0;
417 continue;
418 }
419 }
420
421 // fix DayEvents end time. End times are off by 1 Second. It's possible that the event has already passed
422 if (entry.Type == 'DayEvent' && endDate != null){
423 endDate.setMinutes(endDate.getMinutes() - 1);
424 console.info('fixing DayEvent endDate: ' + endDate);
425 if (now.getTime() > endDate.getTime()){
426 console.info('event already passed ' + entry.id);
427 counter--;
428 eventIds[entry.id] = 0;
429 continue;
430 }
431 }
432
433 // check if the event is currently taking place
434 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null)
435 {
436 // check if we are between start and endtime
437 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
438 date = now; // change appointment date/time to now
439 console.info('event is currently taking place: ' + date);
440 }
441 }
442
443 // skip events for the first panel in case this is the second one
444 if (panelNum == 1 && counter < eventsPerWidget + 1){
445 console.info('skipping (already in first widget) ' + entry.id);
446 continue;
447 }
448
449 // generate html output
450 entriesHtml += '<tr><td><img class="icon" src="' + entry.Type + '.png" /></td>';
451 if(date == null){ // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
452 entriesHtml += '<td colspan="4"><span class="date">' + entryDate + '</span> ';
453 }else{
454 var weekDay = date.toLocaleDateString().substr(0,weekDayLength);
455 var time = formatTime(date);
456 var dateStr = formatDate(date, entryDate);
457 if( entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder' ){
458 // decide if we want to leave off the weekday
459 if (dateStr.search(/Today/) != -1)
460 entriesHtml += '<td colspan="4"><span class="date">'+ dateStr +'</span> ';
461 else
462 entriesHtml += '<td><span class="weekDay">' + weekDay +'</span></td><td><span class="date">'+ dateStr +'</span></td><td colspan="2">';
463 }else if( entry.Type == 'Meeting' ){
464 if (showCombinedDateTime) {
465 if (now.getDate() == date.getDate() && now.getMonth() == date.getMonth())
466 entriesHtml += '<td colspan="4"><span class="today">'+ time +'</span> ';
467 else {
468 // decide if we want to leave off the weekday
469 if (dateStr.search(/Today/) != -1)
470 entriesHtml += '<td colspan="4"><span class="date">'+ dateStr +'</span> ';
471 else
472 entriesHtml += '<td><span class="weekDay">' + weekDay +'</span></td><td><span class="date">'+ dateStr +'</span></td><td colspan="2">';
473 }
474 } else {
475 // decide if we want to leave off the weekday
476 if (dateStr.search(/Today/) != -1)
477 entriesHtml += '<td colspan="4"><span class="date">'+ dateStr +'</span> <span class="time">'+ time +'</span> ';
478 else
479 entriesHtml += '<td><span class="weekDay">' + weekDay +'</span></td><td><span class="date">'+ dateStr +'</span></td><td width="1px"><span class="time">'+ time +'</span></td><td>';
480 }
481 }
482 }
483 entriesHtml += '<span class="description">' + Summary +'</span></td></tr>';
484 }
485 }
486 entriesHtml += '</table>';
487 if (showNothingText && entriesHtml == '<table></table>')
488 entriesHtml = '<div style="width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + nothingText + '</div>';
489 if( cacheEntriesHtml != entriesHtml ){
490 document.getElementById('calendarList').innerHTML = entriesHtml;
491 cacheEntriesHtml = entriesHtml;
492 }
493 }catch(e){
494 error('displaying list:' + e + ', line ' + e.line);
495 return;
496 }
497 }
498
499 function updateScreen(){
500 // Check if opening fullscreen
501 if( window.innerHeight > 91){
502 launchCalendar();
503 }
504
505 if (useBackgroundImage){
506 // check for screen rotation
507 if (orientation != 'portrait' && screen.width == 360 && screen.height == 640){
508 window.widget.prepareForTransition("fade");
509 orientation = 'portrait';
510 document.getElementById('body').style.backgroundImage = 'url(background_' + orientation + '.png)';
511 document.getElementById('body').style.backgroundColor = 'none';
512 window.widget.performTransition();
513 }else if (orientation != 'landscape' && screen.width == 640 && screen.height == 360){
514 window.widget.prepareForTransition("fade");
515 orientation = 'landscape';
516 document.getElementById('body').style.backgroundImage = 'url(background_' + orientation + '.png)';
517 document.getElementById('body').style.backgroundColor = 'none';
518 window.widget.performTransition();
519 }
520 }
521 }
522
523 function launchCalendar(){
524 try{
525 widget.openApplication(calendarApp, "");
526 window.close();
527 }catch(e){
528 error('starting Calendar App');
529 return;
530 }
531 }
532
533 function init(){
534 try{
535 calendarService = device.getServiceObject("Service.Calendar", "IDataSource"); // call calendar service
536 }catch(e){
537 error('loading Calendar service');
538 return;
539 }
540 collectLocales();
541 updateData();
542 requestNotification();
543 window.setInterval('updateData()', 1000 * 60 * updateDataInterval); // start update interval every 5 minutes
544
545 updateScreen();
546 if (useBackgroundImage)
547 window.setInterval('updateScreen()', 1000 * 3); // check for screen rotation every 3 secs
548 }
549 </script>
550 <style type="text/css">
551 table{ margin:0px; padding:0px; border-spacing:0px; }
552 td{ padding:0px 5px 0px 0px; white-space:nowrap; overflow:hidden; }
553 #homescreenView{ width: 315px; height:91px; overflow:hidden; }
554 #calendarList{ position:absolute; left:10px; top:4px; width:295px; height:75px; overflow:hidden; }
555 </style>
556 </head>
557 <body id="body" class="background">
558 <div id="homescreenView">
559 <div id="calendarList"></div>
560 </div>
561 </body>
562 </html>