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