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