]> code.delx.au - comingnext/blob - comingNext/index.html
javascript: General whitespace and style cleanups
[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 collectLocales()
67 {
68 var tmpyear = ((panelNum == 0) ? 2000 : 2001);
69 var month = 0;
70
71 if (months_translated.length > 0)
72 return;
73 for (month = 0; month < 12; month++) {
74 var startDate = new Date(tmpyear, month, 15);
75
76 var item = new Object();
77 item.Type = "DayEvent";
78 item.StartTime = startDate;
79 item.Summary = "__temp" + month;
80
81 var criteria = new Object();
82 criteria.Type = "CalendarEntry";
83 criteria.Item = item;
84
85 try {
86 var result = calendarService.IDataSource.Add(criteria);
87 if (result.ErrorCode)
88 error(result.ErrorMessage);
89 } catch (e) {
90 error("collectLocales: " + e + ', line ' + e.line);
91 }
92 }
93 try {
94 var startTime = new Date(tmpyear,0,1);
95 var endTime = new Date(tmpyear,11,31);
96 var listFiltering = {
97 Type:'CalendarEntry',
98 Filter:{
99 StartRange: startTime,
100 EndRange: endTime,
101 SearchText: '__temp',
102 Type: 'DayEvent'
103 }
104 }
105 var result = calendarService.IDataSource.GetList(listFiltering);
106 if (result.ErrorCode) {
107 error(result.ErrorMessage);
108 return;
109 }
110 var list = result.ReturnValue;
111 } catch(e) {
112 error(e + ', line ' + e.line);
113 return;
114 }
115 var ids = new Array();
116 try {
117 var entry;
118 var counter = 0;
119 var dateArr = [];
120
121 while (list && (entry = list.getNext()) != undefined) {
122 dateArr = entry.StartTime.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
123 var day = dateArr[1];
124 var month = dateArr[2];
125 var year = dateArr[3];
126
127 // make sure month is set properly
128 if (isNaN(parseInt(day))) {
129 var tmp = day;
130 day = month;
131 month = tmp;
132 } else if (isNaN(parseInt(year))) {
133 var tmp = year;
134 year = month;
135 month = tmp;
136 }
137
138 console.info(entry.StartTime + ' -> ' + month + ' ' + counter);
139 ids[counter] = entry.id;
140 months_translated[month] = counter + 1;
141 counter++;
142 }
143 } catch(e) {
144 error(e + ', line ' + e.line);
145 return;
146 }
147 console.info(ids);
148 try {
149 var criteria = new Object();
150 criteria.Type = "CalendarEntry";
151 criteria.Data = {
152 IdList: ids
153 }
154
155 var result = calendarService.IDataSource.Delete(criteria);
156 if (result.ErrorCode)
157 error(result.ErrorMessage);
158 } catch(e) {
159 error('deleting temp calendar entries:' + e + ', line ' + e.line);
160 return;
161 }
162 }
163
164 function requestNotification()
165 {
166 var criteria = new Object();
167 criteria.Type = "CalendarEntry";
168
169 try {
170 var result = calendarService.IDataSource.RequestNotification(criteria, callback);
171 if (result.ErrorCode)
172 error('loading Calendar items list');
173 } catch (e) {
174 error("requestNotification: " + e + ', line ' + e.line);
175 }
176 }
177
178 function callback(transId, eventCode, result)
179 {
180 updateData();
181 }
182
183 function parseDate(dateString)
184 {
185 /*
186 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:
187 Wednesday, 26 August, 2009 24:00:00
188 Wednesday, 26 August, 2009 12:00:00 am
189 Wednesday, August 26, 2009 12:00:00 am
190 Wednesday, 2009 August, 26 12:00:00 am
191 Wednesday, 2009 August, 28 8.00.00 pm
192 Wednesday, 2009 August, 28 08:00:00 PM
193 */
194
195 if (dateString == "" || dateString == null)
196 return null;
197 var dateArr = dateString.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
198 if (dateArr.length != 5 && dateArr.length != 6)
199 return null;
200
201 // parse date
202 var weekDay = dateArr[0];
203 var day = dateArr[1];
204 var month = dateArr[2];
205 var year = dateArr[3];
206 // make sure month is set properly
207 if (isNaN(parseInt(day))) {
208 var tmp = day;
209 day = month;
210 month = tmp;
211 } else if (isNaN(parseInt(year))) {
212 var tmp = year;
213 year = month;
214 month = tmp;
215 }
216 // make sure day and year are set properly
217 if (Number(day) > Number(year)) {
218 var tmp = year;
219 year = day;
220 day = tmp;
221 }
222 month = months_translated[month];
223
224 // parse time
225 var timeArr = dateArr[4].split(':');
226 if (timeArr.length != 3)
227 return null;
228 var hours = Number(timeArr[0]);
229 var minutes = Number(timeArr[1]);
230 var seconds = Number(timeArr[2]);
231 if (dateArr.length == 6 && dateArr[5].toLowerCase() == 'pm' && hours < 12)
232 hours += 12;
233 if (dateArr.length == 6 && dateArr[5].toLowerCase() == 'am' && hours == 12)
234 hours = 0;
235
236 console.info('year=' + year + ' month=' + month + ' day=' + day + ' hours=' + hours + ' minutes=' + minutes+ ' seconds=' + seconds);
237
238 return new Date(year, month - 1, day, hours, minutes, seconds);
239 }
240
241 // 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"
242 function formatDate(date, format)
243 {
244 var day = date.getDate().toString();
245 var month = (date.getMonth() + 1).toString();
246 while (day.length < 2) { day = '0' + day; }
247 while (month.length < 2) { month = '0' + month; }
248
249 if (showTodayAsText && now.getDate() == date.getDate() && now.getMonth() == date.getMonth())
250 return '<span class="today">' + todayText + '</span>';
251
252 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
253 if (dateArr.length != 5 && dateArr.length != 6) {
254 // we don't know how to format this
255 if (dateFormat == 'auto' || dateFormat == 'DDMM')
256 return day + dateSeparator + month;
257 else
258 return month + dateSeparator + day;
259 }
260
261 var dayFirst = true;
262 if (dateFormat == 'MMDD')
263 dayFirst = false;
264 else if (dateFormat == 'DDMM')
265 dayFirst = true;
266 else {
267 // dateFormat == 'auto', try to detect system setting
268 // parse date
269 var day_ = dateArr[1];
270 var month_ = dateArr[2];
271 var year_ = dateArr[3];
272 // make sure month is set properly
273 if (isNaN(parseInt(day_))) {
274 var tmp = day_;
275 day_ = month_;
276 month_ = tmp;
277 dayFirst = false;
278 } else if (isNaN(parseInt(year_))) {
279 var tmp = year_;
280 year_ = month_;
281 month_ = tmp;
282 dayFirst = true;
283 }
284 // make sure day and year are set properly
285 if (Number(day_) > Number(year_))
286 dayFirst = false;
287 }
288
289 if (dayFirst)
290 return day + dateSeparator + month;
291 else
292 return month + dateSeparator + day;
293 }
294
295 function formatTime(date)
296 {
297 // date is a Date() object
298 date.setSeconds(0); // we don't care about seconds
299 var time = date.toLocaleTimeString().replace(/[\.:]00/, ''); // remove seconds from string
300 if (time.replace(/\./, ':').split(':')[0].length < 2)
301 time = '0' + time;
302 if (showNowAsText && date.getTime() == now.getTime())
303 time = '<span class="now">' + nowText + '</span>';
304 return time;
305 }
306
307 function updateData()
308 {
309 try {
310 // meetings have time
311 // 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
312 now = new Date();
313 var meetingListFiltering = {
314 Type:'CalendarEntry',
315 Filter:{
316 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0)),
317 EndRange: (new Date(now.getFullYear(), now.getMonth() + monthRange, now.getDate(), 0, 0, 0))
318 }
319 }
320 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
321 var meetingList = meetingResult.ReturnValue;
322
323 // todos don't, they start on 00:00 hrs., but should be visible anyway
324 // this will generate a list of passed todos. We have to check if they have been marked as "done" yet
325 if (includeTodos) {
326 var todayTodoListFiltering = {
327 Type:'CalendarEntry',
328 Filter:{
329 Type: 'ToDo',
330 StartRange: (new Date(now.getFullYear() - 1, now.getMonth(), now.getDate(), 0, 0, 0)),
331 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 1))
332 }
333 }
334 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
335 var todayTodoList = todayTodoResult.ReturnValue;
336 var entryLists = [todayTodoList, meetingList];
337 } else {
338 var entryLists = [meetingList];
339 }
340 } catch(e) {
341 error('loading Calendar items list:' + e + ', line ' + e.line);
342 return;
343 }
344
345 try {
346 var entry;
347 var counter = 0;
348 var entryDate = '';
349 var dateArr = [];
350 var entriesHtml = '<table>';
351 var eventIds = [];
352 var max = ((panelNum == 0) ? eventsPerWidget : 2 * eventsPerWidget);
353
354 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
355 for (var i=0; counter < max && i < entryLists.length; i++) {
356 while (counter < max && (entry = entryLists[i].getNext()) != undefined) {
357 counter++;
358
359 // output event info for debugging
360 console.info(
361 'event: Id=' + entry.id +
362 ',Type=' + entry.Type +
363 ',Summary=' + entry.Summary +
364 ',Location=' + entry.Location +
365 ',Status=' + entry.Status +
366 ',StartTime=' + entry.StartTime +
367 ',EndTime=' + entry.EndTime +
368 ',InstanceStartTime=' + entry.InstanceStartTime +
369 ',InstanceEndTime=' + entry.InstanceEndTime
370 );
371
372 // we don't want ToDos when includeTodos == false or when they are completed
373 if (entry.Type == 'ToDo' && (entry.Status == "TodoCompleted" || !includeTodos)) {
374 console.info('skipping ' + entry.id );
375 counter--;
376 continue;
377 }
378
379 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
380 if (eventIds[entry.id] == 1) {
381 console.info('skipped (already included) ' + entry.id);
382 counter--;
383 continue;
384 } else
385 eventIds[entry.id] = 1;
386
387 // summary can be undefined!
388 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
389 if (entry.Type == 'Meeting' && entry.Location != '' && showLocation)
390 Summary += ', ' + entry.Location;
391
392 // fix by yves: determine start and end dates/times
393 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
394 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
395
396 // there can be ToDos that have no date at all!
397 if (entry.Type == 'ToDo' && entry.EndTime == null)
398 entryDate = ""; // this will cause parseDate(entryDate) to return null;
399 else
400 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
401
402 // Convert date/time string to Date object
403 var date = parseDate(entryDate);
404 console.info('date: ' + date);
405 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
406 console.info('endDate: ' + endDate);
407
408 // check if meeting event has already passed
409 if (entry.Type == 'Meeting') {
410 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
411 if (now.getTime() > compareTime) {
412 console.info('skipping Meeting (already passed) ' + entry.id);
413 counter--;
414 eventIds[entry.id] = 0;
415 continue;
416 }
417 }
418
419 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
420 if (entry.Type == 'Anniversary') {
421 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0,0,0);
422 if (date.getTime() < tmp.getTime()) {
423 console.info('skipping Anniversary (already passed) ' + entry.id);
424 counter--;
425 eventIds[entry.id] = 0;
426 continue;
427 }
428 }
429
430 // fix DayEvents end time. End times are off by 1 Second. It's possible that the event has already passed
431 if (entry.Type == 'DayEvent' && endDate != null) {
432 endDate.setMinutes(endDate.getMinutes() - 1);
433 console.info('fixing DayEvent endDate: ' + endDate);
434 if (now.getTime() > endDate.getTime()) {
435 console.info('event already passed ' + entry.id);
436 counter--;
437 eventIds[entry.id] = 0;
438 continue;
439 }
440 }
441
442 // check if the event is currently taking place
443 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
444 // check if we are between start and endtime
445 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
446 date = now; // change appointment date/time to now
447 console.info('event is currently taking place: ' + date);
448 }
449 }
450
451 // skip events for the first panel in case this is the second one
452 if (panelNum == 1 && counter < eventsPerWidget + 1) {
453 console.info('skipping (already in first widget) ' + entry.id);
454 continue;
455 }
456
457 // generate html output
458 entriesHtml += '<tr><td><img class="icon" src="' + entry.Type + '.png" /></td>';
459 if(date == null) {
460 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
461 entriesHtml += '<td colspan="4"><span class="date">' + entryDate + '</span> ';
462 } else {
463 var weekDay = date.toLocaleDateString().substr(0,weekDayLength);
464 var time = formatTime(date);
465 var dateStr = formatDate(date, entryDate);
466 if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
467 // decide if we want to leave off the weekday
468 if (dateStr.search(/Today/) != -1)
469 entriesHtml += '<td colspan="4"><span class="date">' + dateStr + '</span> ';
470 else
471 entriesHtml += '<td><span class="weekDay">' + weekDay + '</span></td><td><span class="date">' + dateStr + '</span></td><td colspan="2">';
472 } else if (entry.Type == 'Meeting') {
473 if (showCombinedDateTime) {
474 if (now.getDate() == date.getDate() && now.getMonth() == date.getMonth())
475 entriesHtml += '<td colspan="4"><span class="today">' + time + '</span> ';
476 else {
477 // decide if we want to leave off the weekday
478 if (dateStr.search(/Today/) != -1)
479 entriesHtml += '<td colspan="4"><span class="date">' + dateStr + '</span> ';
480 else
481 entriesHtml += '<td><span class="weekDay">' + weekDay + '</span></td><td><span class="date">' + dateStr + '</span></td><td colspan="2">';
482 }
483 } else {
484 // decide if we want to leave off the weekday
485 if (dateStr.search(/Today/) != -1)
486 entriesHtml += '<td colspan="4"><span class="date">' + dateStr + '</span> <span class="time">' + time + '</span> ';
487 else
488 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>';
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>