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