]> code.delx.au - comingnext/blob - comingNext/index.html
updated credits
[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 /* The following classes can be modified by widget settings */
10 .background { }
11 .backgroundFullscreen { }
12 .weekDay { }
13 .date { }
14 .today { }
15 .tomorrow { }
16 .time { }
17 .now { }
18 .description { }
19 .icon { }
20 .overdue {}
21 </style>
22
23 <script type="text/javascript" src="localizedTextStrings.js" charset="utf-8" />
24
25 <script>
26 // valid types for the config object are 'Int', 'Bool', 'String', 'Enum', 'UID'
27 var config = {
28 monthRange: { Type: 'Int', Default: 2, Value: 2,},
29 includeTodos: { Type: 'Bool', Default: true, Value: true,},
30 useBackgroundImage: { Type: 'Bool', Default: true, Value: true,},
31 backgroundImageLocation: { Type: 'Enum', Default: 'internal', Value: 'internal', ValidValues: ['internal', 'external']},
32 showCombinedDateTime: { Type: 'Bool', Default: false, Value: false,},
33 showLocation: { Type: 'Bool', Default: true, Value: true,},
34 showTodayAsText: { Type: 'Bool', Default: true, Value: true,},
35 todayText: { Type: 'String', Default: getLocalizedText('settings.default.todayText'), Value: getLocalizedText('settings.default.todayText'),},
36 tomorrowText: { Type: 'String', Default: getLocalizedText('settings.default.tomorrowText'), Value: getLocalizedText('settings.default.tomorrowText'),},
37 showNowAsText: { Type: 'Bool', Default: true, Value: true,},
38 nowText: { Type: 'String', Default: getLocalizedText('settings.default.nowText'), Value: getLocalizedText('settings.default.nowText'),},
39 markOverdueTodos: { Type: 'Bool', Default: true, Value: true,},
40 overdueText: {Type: 'String', Default: getLocalizedText('settings.default.overdueText'), Value: getLocalizedText('settings.default.overdueText'),},
41 dateSeparator: { Type: 'String', Default: getLocalizedText('settings.default.dateSeparator'), Value: getLocalizedText('settings.default.dateSeparator'),},
42 dateFormat: { Type: 'Enum', Default: 'auto', Value: 'auto', ValidValues: ['auto', 'DDMM', 'MMDD'],},
43 weekDayLength: { Type: 'Int', Default: 2, Value: 2,},
44 updateDataInterval: { Type: 'Int', Default: 5, Value: 5,},
45 calendarApp: { Type: 'UID', Default: 0x10005901, Value: 0x10005901,},
46 eventsPerWidget: { Type: 'Int', Default: 4, Value: 4,},
47 showNothingText: { Type: 'Bool', Default: true, Value: true,},
48 nothingText: { Type: 'String', Default: getLocalizedText('settings.default.nothingText'), Value: getLocalizedText('settings.default.nothingText'),},
49 enableDaylightSaving: { Type: 'Bool', Default: true, Value: true,},
50 hideWidgetOnCalendarOpen: { Type: 'Bool', Default: false, Value: false,},
51 cssStyle_background: { Type: 'String', Default: 'color:#ffffff; background-color:#000000', Value: 'color:#ffffff; background-color:#000000',},
52 cssStyle_backgroundFullscreen: { Type: 'String', Default: 'color:#ffffff; background-color:#000000', Value: 'color:#ffffff; background-color:#000000',},
53 cssStyle_weekDay: { Type: 'String', Default: '', Value: '',},
54 cssStyle_date: { Type: 'String', Default: '', Value: '',},
55 cssStyle_today: { Type: 'String', Default: 'color:#ff0000', Value: 'color:#ff0000',},
56 cssStyle_tomorrow: { Type: 'String', Default: 'color:#0000ff', Value: 'color:#0000ff',},
57 cssStyle_time: { Type: 'String', Default: '', Value: '',},
58 cssStyle_now: { Type: 'String', Default: 'color:#ff00ff', Value: 'color:#ff00ff',},
59 cssStyle_description: { Type: 'String', Default: '', Value: '',},
60 cssStyle_icon: { Type: 'String', Default: 'width:15px; height:15px', Value: 'width:15px; height:15px',},
61 cssStyle_overdue: { Type: 'String', Default: 'color:#ffff00', Value: 'color:#ffff00',},
62 }
63
64
65
66 //-------------------------------------------------------
67 // Nothing of interest from here on...
68 //-------------------------------------------------------
69 var panelNum = 0; // use 1 for second panel
70 var version = "1.28";
71 var versionURL = "http://comingnext.sourceforge.net/version.xml";
72 var calendarService = null;
73 var cacheEntriesHtml = [];
74 var months_translated = [];
75 var orientation = '';
76 var now = new Date();
77 var mode = 0; // 0 = homescreen, 1 = fullscreen, 2 = settings, 3 = about, 4 = check for update
78 var reqV = null;
79 var settingsCalEntryId = null;
80 var settingsCache = null;
81 var notificationRequest1;
82 var notificationRequest2;
83
84 // vars for daylight saving time
85 var daylightsavingWinter = 0;
86 var daylightsavingSummer = 0;
87 var summertime = false;
88
89 window.onload = init;
90 window.onresize = updateScreen;
91 window.onshow = updateScreen;
92
93 function isLeapYear( year ) {
94 if (( year % 4 == 0 && year % 100 != 0 ) || year % 400 == 0 )
95 return true;
96 else
97 return false;
98 }
99
100 function calcLeapYear(year, days)
101 {
102 if (isLeapYear(year))
103 return ++days;
104 else
105 return days;
106 }
107
108 function subToSunday(myDate, year, days, prevMonthDays)
109 {
110 for (i = myDate.getDay(); i > 0 ;i--)
111 days--;
112 days -= prevMonthDays;
113 days = isLeapYear(year) ? --days : days;
114 return days;
115 }
116
117 function calcDaylightSaving()
118 {
119 var thisYearS = new Date(now.getFullYear(), 3, 0, 0, 0, 0 );
120 var thisYearW = new Date(now.getFullYear(), 10, 0, 0, 0, 0 );
121 var nextYearS = new Date(now.getFullYear() + 1, 3, 0, 0, 0, 0 );
122 var nextYearW = new Date(now.getFullYear() + 1, 10, 0, 0, 0, 0 );
123 var summer = false;
124 var winter = false;
125
126 thisYearSDays = nextYearSDays = 90;
127 thisYearWDays = nextYearWDays = 304;
128
129 thisYearSDays = calcLeapYear(now.getFullYear(), thisYearSDays);
130 thisYearWDays = calcLeapYear(now.getFullYear(), thisYearWDays);
131 nextYearSDays = calcLeapYear(now.getFullYear() + 1, nextYearSDays);
132 nextYearWDays = calcLeapYear(now.getFullYear() + 1, nextYearWDays);
133
134 thisYearSDays = subToSunday(thisYearS, now.getFullYear(), thisYearSDays, 59);
135 thisYearWDays = subToSunday(thisYearW, now.getFullYear(), thisYearWDays, 273);
136 nextYearSDays = subToSunday(nextYearS, now.getFullYear() + 1, nextYearSDays, 59);
137 nextYearWDays = subToSunday(nextYearW, now.getFullYear() + 1, nextYearWDays, 273);
138
139 daylightsavingSummer = new Date (now.getFullYear(), 03-1, thisYearSDays, 2, 0, 0);
140 daylightsavingWinter = new Date (now.getFullYear(), 10-1, thisYearWDays, 2, 0, 0);
141 if (daylightsavingSummer < now) {
142 daylightsavingSummer = new Date (now.getFullYear()+1, 03-1, nextYearSDays, 2, 0, 0);
143 var summer = true;
144 }
145 if (daylightsavingWinter < now) {
146 daylightsavingWinter = new Date (now.getFullYear()+1, 10-1, nextYearWDays, 2, 0, 0);
147 var winter = true;
148 }
149 if (summer && !winter)
150 summertime = true;
151 else
152 summertime = false;
153 }
154
155 function error(message)
156 {
157 console.info('Error: ' + message);
158 document.getElementById("calendarList").innerHTML = 'Error: ' + message;
159 }
160
161 function areDatesEqual(date1, date2)
162 {
163 return (date1.getFullYear() == date2.getFullYear() &&
164 date1.getMonth() == date2.getMonth() &&
165 date1.getDate() == date2.getDate());
166 }
167
168 function isTomorrow(date)
169 {
170 // tommorow = now + 1 day
171 // ToDo: some days can be shorter as 24 hours(daylight saving change day)
172 return areDatesEqual(date, new Date (now.getTime() + 24*60*60*1000));
173 }
174
175 function isToday(date)
176 {
177 return areDatesEqual(date, now);
178 }
179
180 function collectLocales()
181 {
182 var tmpyear = 2000 + panelNum;
183 var month = 0;
184
185 if (months_translated.length > 0)
186 return;
187 for (month = 0; month < 12; month++) {
188 var startDate = new Date(tmpyear, month, 15);
189
190 var item = new Object();
191 item.Type = "DayEvent";
192 item.StartTime = startDate;
193 item.Summary = "__temp" + month;
194
195 var criteria = new Object();
196 criteria.Type = "CalendarEntry";
197 criteria.Item = item;
198
199 try {
200 var result = calendarService.IDataSource.Add(criteria);
201 if (result.ErrorCode)
202 error(result.ErrorMessage);
203 } catch (e) {
204 error("collectLocales: " + e + ', line ' + e.line);
205 }
206 }
207 try {
208 var startTime = new Date(tmpyear,0,1);
209 var endTime = new Date(tmpyear,11,31);
210 var listFiltering = {
211 Type:'CalendarEntry',
212 Filter:{
213 StartRange: startTime,
214 EndRange: endTime,
215 SearchText: '__temp',
216 Type: 'DayEvent'
217 }
218 }
219 var result = calendarService.IDataSource.GetList(listFiltering);
220 if (result.ErrorCode) {
221 error(result.ErrorMessage);
222 return;
223 }
224 var list = result.ReturnValue;
225 } catch(e) {
226 error(e + ', line ' + e.line);
227 return;
228 }
229 var ids = new Array();
230 try {
231 var entry;
232 var counter = 0;
233 var dateArr = [];
234
235 while (list && (entry = list.getNext()) != undefined) {
236 dateArr = entry.StartTime.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
237 var day = dateArr[1];
238 var month = dateArr[2];
239 var year = dateArr[3];
240
241 // make sure month is set properly
242 if (isNaN(parseInt(day))) {
243 var tmp = day;
244 day = month;
245 month = tmp;
246 } else if (isNaN(parseInt(year))) {
247 var tmp = year;
248 year = month;
249 month = tmp;
250 }
251
252 console.info(entry.StartTime + ' -> ' + month + ' ' + counter);
253 ids[counter] = entry.id;
254 months_translated[month] = counter + 1;
255 counter++;
256 }
257 } catch(e) {
258 error(e + ', line ' + e.line);
259 return;
260 }
261 console.info(ids);
262 try {
263 var criteria = new Object();
264 criteria.Type = "CalendarEntry";
265 criteria.Data = {
266 IdList: ids
267 }
268
269 var result = calendarService.IDataSource.Delete(criteria);
270 if (result.ErrorCode)
271 error(result.ErrorMessage);
272 } catch(e) {
273 error('deleting temp calendar entries:' + e + ', line ' + e.line);
274 return;
275 }
276 }
277
278 function requestNotification()
279 {
280 var criteria = new Object();
281 criteria.Type = "CalendarEntry";
282
283 try {
284 notificationRequest1 = calendarService.IDataSource.RequestNotification(criteria, callback);
285 if (notificationRequest1.ErrorCode)
286 error('requestNotification failed with error code ' + notificationRequest1.ErrorCode);
287 } catch (e) {
288 error("requestNotification: " + e + ', line ' + e.line);
289 }
290
291 var criteria2 = new Object();
292 criteria2.Type = "CalendarEntry";
293 criteria2.Filter = new Object();
294 criteria2.Filter.LocalIdList = new Array();
295 criteria2.Filter.LocalIdList[0] = settingsCalEntryId;
296
297 try {
298 notificationRequest2 = calendarService.IDataSource.RequestNotification(criteria2, settingsCallback);
299 if (notificationRequest2.ErrorCode)
300 error('requestNotification failed with error code ' + notificationRequest2.ErrorCode);
301 } catch (e) {
302 error("requestNotification: " + e + ', line ' + e.line);
303 }
304 }
305
306 function callback(transId, eventCode, result)
307 {
308 console.info("callback(): panelNum: %d transId: %d eventCode: %d result.ErrorCode: %d", panelNum, transId, eventCode, result.ErrorCode);
309 updateData();
310 }
311
312 function settingsCallback(transId, eventCode, result)
313 {
314 console.info("settingsCallback(): panelNum: %d transId: %d eventCode: %d result.ErrorCode: %d", panelNum, transId, eventCode, result.ErrorCode);
315 loadSettings();
316 }
317
318 function parseDate(dateString)
319 {
320 /*
321 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:
322 Wednesday, 26 August, 2009 24:00:00
323 Wednesday, 26 August, 2009 12:00:00 am
324 Wednesday, August 26, 2009 12:00:00 am
325 Wednesday, 2009 August, 26 12:00:00 am
326 Wednesday, 2009 August, 28 8.00.00 pm
327 Wednesday, 2009 August, 28 08:00:00 PM
328 */
329
330 if (dateString == "" || dateString == null)
331 return null;
332 var dateArr = dateString.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
333 if (dateArr.length != 5 && dateArr.length != 6)
334 return null;
335
336 // parse date
337 var weekDay = dateArr[0];
338 var day = dateArr[1];
339 var month = dateArr[2];
340 var year = dateArr[3];
341 // make sure month is set properly
342 if (isNaN(parseInt(day))) {
343 var tmp = day;
344 day = month;
345 month = tmp;
346 } else if (isNaN(parseInt(year))) {
347 var tmp = year;
348 year = month;
349 month = tmp;
350 }
351 // make sure day and year are set properly
352 if (Number(day) > Number(year)) {
353 var tmp = year;
354 year = day;
355 day = tmp;
356 }
357 month = months_translated[month];
358
359 // parse time
360 var timeArr = dateArr[4].split(':');
361 if (timeArr.length != 3)
362 return null;
363 var hours = Number(timeArr[0]);
364 var minutes = Number(timeArr[1]);
365 var seconds = Number(timeArr[2]);
366 if (dateArr.length == 6 && dateArr[5].toLowerCase() == 'pm' && hours < 12)
367 hours += 12;
368 if (dateArr.length == 6 && dateArr[5].toLowerCase() == 'am' && hours == 12)
369 hours = 0;
370
371 console.info('year=' + year + ' month=' + month + ' day=' + day + ' hours=' + hours + ' minutes=' + minutes+ ' seconds=' + seconds);
372
373 // take care of daylight saving time
374 if (config['enableDaylightSaving'].Value) {
375 var date = new Date(year, month - 1, day, hours, minutes, seconds);
376 if (summertime && date > daylightsavingWinter && date < daylightsavingSummer)
377 hours -= 1;
378 else if (!summertime && date > daylightsavingSummer && date < daylightsavingWinter)
379 hours += 1;
380 }
381
382 return new Date(year, month - 1, day, hours, minutes, seconds);
383 }
384
385 // 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"
386 function formatDate(date, format)
387 {
388 var day = date.getDate().toString();
389 var month = (date.getMonth() + 1).toString();
390 while (day.length < 2) { day = '0' + day; }
391 while (month.length < 2) { month = '0' + month; }
392
393 if (config['showTodayAsText'].Value && isToday(date))
394 return '<span class="today">' + config['todayText'].Value + '</span>';
395 if (config['showTodayAsText'].Value && isTomorrow(date))
396 return '<span class="tomorrow">' + config['tomorrowText'].Value + '</span>';
397
398 var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');
399 if (dateArr.length != 5 && dateArr.length != 6) {
400 // we don't know how to format this
401 if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')
402 return day + config['dateSeparator'].Value + month;
403 else
404 return month + config['dateSeparator'].Value + day;
405 }
406
407 var dayFirst = true;
408 if (config['dateFormat'].Value == 'MMDD')
409 dayFirst = false;
410 else if (config['dateFormat'].Value == 'DDMM')
411 dayFirst = true;
412 else {
413 // config['dateFormat'].Value == 'auto', try to detect system setting
414 // parse date
415 var day_ = dateArr[1];
416 var month_ = dateArr[2];
417 var year_ = dateArr[3];
418 // make sure month is set properly
419 if (isNaN(parseInt(day_))) {
420 var tmp = day_;
421 day_ = month_;
422 month_ = tmp;
423 dayFirst = false;
424 } else if (isNaN(parseInt(year_))) {
425 var tmp = year_;
426 year_ = month_;
427 month_ = tmp;
428 dayFirst = true;
429 }
430 // make sure day and year are set properly
431 if (Number(day_) > Number(year_))
432 dayFirst = false;
433 }
434
435 if (dayFirst)
436 return day + config['dateSeparator'].Value + month;
437 else
438 return month + config['dateSeparator'].Value + day;
439 }
440
441 function formatTime(date)
442 {
443 // date is a Date() object
444 date.setSeconds(0); // we don't care about seconds
445 var time = date.toLocaleTimeString().replace(/[\.:]00/, ''); // remove seconds from string
446 if (time.replace(/\./, ':').split(':')[0].length < 2)
447 time = '0' + time;
448 if (config['showNowAsText'].Value && date.getTime() == now.getTime())
449 time = '<span class="now">' + config['nowText'].Value + '</span>';
450 return time;
451 }
452
453 function updateData()
454 {
455 console.info('updateData()');
456 calcDaylightSaving();
457 try {
458 // meetings have time
459 // 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
460 now = new Date();
461 var meetingListFiltering = {
462 Type:'CalendarEntry',
463 Filter:{
464 StartRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0)),
465 EndRange: (new Date(now.getFullYear(), now.getMonth() + config['monthRange'].Value, now.getDate(), 0, 0, 0))
466 }
467 }
468 var meetingResult = calendarService.IDataSource.GetList(meetingListFiltering);
469 if (meetingResult.ErrorCode != 0)
470 throw("Error fetching calendar data: " + meetingResult.ErrorCode + ': ' + meetingResult.ErrorMessage);
471 var meetingList = meetingResult.ReturnValue;
472
473 // todos don't, they start on 00:00 hrs., but should be visible anyway
474 // this will generate a list of passed todos. We have to check if they have been marked as "done" yet
475 if (config['includeTodos'].Value) {
476 var todayTodoListFiltering = {
477 Type:'CalendarEntry',
478 Filter:{
479 Type: 'ToDo',
480 StartRange: (new Date(now.getFullYear() - 1, now.getMonth(), now.getDate(), 0, 0, 0)),
481 EndRange: (new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 1))
482 }
483 }
484 var todayTodoResult = calendarService.IDataSource.GetList(todayTodoListFiltering);
485 var todayTodoList = todayTodoResult.ReturnValue;
486 var entryLists = [todayTodoList, meetingList];
487 } else {
488 var entryLists = [meetingList];
489 }
490 } catch(e) {
491 error('loading Calendar items list:' + e + ', line ' + e.line);
492 return;
493 }
494
495 try {
496 var entry;
497 var counter = 0;
498 var entryDate = '';
499 var dateArr = [];
500 var fontsize = 'normal';
501 if (mode == 0) {
502 if (config['eventsPerWidget'].Value == 3) {
503 fontsize = '17pt';
504 changeCssClass('.icon', 'width:20px; height:20px');
505 }
506 else if (config['eventsPerWidget'].Value == 5) {
507 fontsize = '10pt';
508 changeCssClass('.icon', 'width:10px; height:10px');
509 }
510 else if (config['eventsPerWidget'].Value == 6) {
511 fontsize = '8pt';
512 changeCssClass('.icon', 'width:8px; height:8px');
513 }
514 }
515 else
516 changeCssClass('.icon', config['cssStyle_icon'].Value);
517 var entriesHtml = '<table style="font-size:' + fontsize + ';">';
518 var eventIds = [];
519 var max;
520 if (mode == 0)
521 max = (panelNum + 1) * config['eventsPerWidget'].Value;
522 else
523 max = 30; // we can display a lot more events in fullscreen mode
524
525 // the first outer loop iteration is for passed ToDos, the second loop is for all upcomming events (may also include ToDos)
526 for (var i=0; counter < max && i < entryLists.length; i++) {
527 while (counter < max && (entry = entryLists[i].getNext()) != undefined) {
528 counter++;
529
530 // output event info for debugging
531 console.info(
532 'event: Id=' + entry.id +
533 ',Type=' + entry.Type +
534 ',Summary=' + entry.Summary +
535 ',Location=' + entry.Location +
536 ',Status=' + entry.Status +
537 ',StartTime=' + entry.StartTime +
538 ',EndTime=' + entry.EndTime +
539 ',InstanceStartTime=' + entry.InstanceStartTime +
540 ',InstanceEndTime=' + entry.InstanceEndTime
541 );
542
543 // we don't want ToDos when includeTodos == false or when they are completed
544 if (entry.Type == 'ToDo' && (entry.Status == "TodoCompleted" || !config['includeTodos'].Value)) {
545 console.info('skipping ' + entry.id );
546 counter--;
547 continue;
548 }
549
550 // make sure that we don't include an event twice (useful for ToDos that might come up twice)
551 if (eventIds[entry.id] == 1 && entry.Type == 'ToDo') {
552 console.info('skipped (already included) ' + entry.id);
553 counter--;
554 continue;
555 } else
556 eventIds[entry.id] = 1;
557
558 // summary can be undefined!
559 var Summary = ((entry.Summary == null) ? '' : entry.Summary);
560 if (entry.Type == 'Meeting' && entry.Location != '' && config['showLocation'].Value)
561 Summary += ', ' + entry.Location;
562
563 // fix by yves: determine start and end dates/times
564 entryStartTime = ((entry.InstanceStartTime == null) ? entry.StartTime : entry.InstanceStartTime);
565 entryEndTime = ((entry.InstanceEndTime == null) ? entry.EndTime : entry.InstanceEndTime);
566
567 // there can be ToDos that have no date at all!
568 if (entry.Type == 'ToDo' && entry.EndTime == null)
569 entryDate = ""; // this will cause parseDate(entryDate) to return null;
570 else
571 entryDate = ((entry.Type == 'ToDo') ? entryEndTime : entryStartTime); // ToDo's use their EndTime, the rest use StartTime
572
573 // Convert date/time string to Date object
574 var date = parseDate(entryDate);
575 console.info('date: ' + date);
576 var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));
577 console.info('endDate: ' + endDate);
578
579 // check if meeting event has already passed
580 if (entry.Type == 'Meeting') {
581 var compareTime = ((endDate == null) ? date.getTime() : endDate.getTime());
582 if (now.getTime() > compareTime) {
583 console.info('skipping Meeting (already passed) ' + entry.id);
584 counter--;
585 eventIds[entry.id] = 0;
586 continue;
587 }
588 }
589
590 // check if anniversary passed (not sure why they are in the list, the query was only for today - nokia?)
591 if (entry.Type == 'Anniversary') {
592 var tmp = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0,0,0);
593 if (date.getTime() < tmp.getTime()) {
594 console.info('skipping Anniversary (already passed) ' + entry.id);
595 counter--;
596 eventIds[entry.id] = 0;
597 continue;
598 }
599 }
600
601 // fix DayEvents end time. End times are off by 1 Second. It's possible that the event has already passed
602 if (entry.Type == 'DayEvent' && endDate != null) {
603 endDate.setMinutes(endDate.getMinutes() - 1);
604 console.info('fixing DayEvent endDate: ' + endDate);
605 if (now.getTime() > endDate.getTime()) {
606 console.info('event already passed ' + entry.id);
607 counter--;
608 eventIds[entry.id] = 0;
609 continue;
610 }
611 }
612
613 // check if the event is currently taking place
614 if (entryStartTime != null && entryEndTime != null && date != null && endDate != null) {
615 // check if we are between start and endtime
616 if ((date.getTime() < now.getTime()) && (now.getTime() < endDate.getTime())) {
617 date = now; // change appointment date/time to now
618 console.info('event is currently taking place: ' + date);
619 }
620 }
621
622 // skip events for the first panel in case this is the second one and we're not in fullscreen mode
623 if (mode == 0 && panelNum > 0 && counter < panelNum * config['eventsPerWidget'].Value + 1) {
624 console.info('skipping (already in first widget) ' + entry.id);
625 continue;
626 }
627
628 // mark overdue todos
629 var overdue = false;
630 if (entry.Type == 'ToDo' && date != null) {
631 var tmp1 = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0,0,0);
632 var tmp2 = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0,0,0);
633 if (tmp1.getTime() < tmp2.getTime()) {
634 overdue = true;
635 }
636 }
637
638 // generate html output
639 entriesHtml += '<tr><td><img class="icon" src="' + entry.Type + '.png" /></td>';
640 if(date == null) {
641 // some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.
642 entriesHtml += '<td colspan="4"><span class="date">' + entryDate + '</span> ';
643 } else {
644 var weekDay = date.toLocaleDateString().substr(0,config['weekDayLength'].Value);
645 var time = formatTime(date);
646 var dateStr = formatDate(date, entryDate);
647 if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {
648 dateStr = '<span class="overdue">' + config['overdueText'].Value + '</span>';
649 entriesHtml += '<td colspan="4" width="1px"><span class="date">' + dateStr + '</span> ';
650 } else if (entry.Type == 'ToDo' || entry.Type == 'Anniversary' || entry.Type == 'DayEvent' || entry.Type == 'Reminder') {
651 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value) // show weekday if the date string is not text. looks odd otherwise
652 entriesHtml += '<td colspan="4" width="1px"><span class="date">' + dateStr + '</span> ';
653 else
654 entriesHtml += '<td class="weekDay" width="1px">' + weekDay + '</td><td width="1px" class="date">' + dateStr + '</td><td colspan="2">';
655 } else if (entry.Type == 'Meeting') {
656 if (config['showCombinedDateTime'].Value) {
657 if (isToday(date))
658 entriesHtml += '<td width="1px" colspan="4"><span class="today">' + time + '</span> ';
659 else if (isTomorrow(date))
660 entriesHtml += '<td width="1px" colspan="4"><span class="tomorrow">' + dateStr + '</span> <span class="time">' + time + '</span> ';
661 else
662 entriesHtml += '<td width="1px" class="weekDay">' + weekDay + '</td><td width="1px" class="date">' + dateStr + '</td><td colspan="2">';
663 } else {
664 if ((isToday(date) || isTomorrow(date)) && config['showTodayAsText'].Value)
665 entriesHtml += '<td colspan="4" width="1px"><span class="today">' + dateStr + '</span> <span class="time">' + time + '</span> ';
666 else
667 entriesHtml += '<td width="1px" class="weekDay">' + weekDay + '</td><td width="1px" class="date">' + dateStr + '</td><td width="1px" class="time">' + time + '</td><td>';
668 }
669 }
670 }
671 entriesHtml += '<span class="description">' + Summary + '</span></td></tr>';
672 }
673 }
674 entriesHtml += '</table>';
675 if (config['showNothingText'].Value && entriesHtml == '<table></table>') {
676 var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);
677 entriesHtml = '<div style="width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '</div>';
678 }
679 if (cacheEntriesHtml != entriesHtml) {
680 if (mode == 0)
681 document.getElementById('calendarList').innerHTML = entriesHtml;
682 else
683 document.getElementById('fullscreenCalendarList').innerHTML = entriesHtml;
684 cacheEntriesHtml = entriesHtml;
685 }
686 } catch(e) {
687 error('displaying list:' + e + ', line ' + e.line);
688 return;
689 }
690 }
691
692 function updateScreen()
693 {
694 // check if opening fullscreen
695 if( window.innerHeight > 91 && mode == 0) {
696 mode = 1;
697 cacheEntriesHtml = '';
698 document.getElementById('body').style.backgroundImage = "";
699 showFullscreen();
700 }
701 else if (window.innerHeight <= 91 && mode != 0) {
702 mode = 0;
703 cacheEntriesHtml = '';
704 showHomescreen();
705 }
706
707 if (mode == 0)
708 updateHomescreen();
709 else if (mode == 1)
710 updateFullscreen();
711 }
712
713 function launchCalendar()
714 {
715 try {
716 widget.openApplication(config['calendarApp'].Value, "");
717 if (config['hideWidgetOnCalendarOpen'].Value)
718 window.close();
719 } catch(e) {
720 error('starting Calendar App');
721 return;
722 }
723 }
724
725 function init()
726 {
727 console.info('New widget instance starting up...');
728
729 try {
730 // call calendar service
731 if (device != "undefined")
732 calendarService = device.getServiceObject("Service.Calendar", "IDataSource");
733 else
734 throw('device object does not exist');
735 } catch(e) {
736 error('loading Calendar service: ' + e + ', line ' + e.line);
737 return;
738 }
739
740 loadSettings();
741 collectLocales();
742 //updateData();
743 requestNotification();
744 window.setInterval('updateData()', 1000 * 60 * config['updateDataInterval'].Value);
745 document.getElementById("settingsTitle").innerHTML = getLocalizedText('menu.settings');
746
747 mode = 0;
748 showHomescreen();
749 updateScreen();
750 if (config['useBackgroundImage'].Value)
751 // check for screen rotation every 1 secs
752 window.setInterval('updateScreen()', 1000 * 1);
753 }
754
755 function createMenu()
756 {
757 window.menu.setLeftSoftkeyLabel("",null);
758 window.menu.setRightSoftkeyLabel("",null);
759 var id = 0;
760 var menuSettings = new MenuItem(getLocalizedText('menu.settings'), id++);
761 var menuCallApp = new MenuItem(getLocalizedText('menu.openCalendarApp'), id++);
762 var menuUpdate = new MenuItem(getLocalizedText('menu.update'), id++);
763 var menuAbout = new MenuItem(getLocalizedText('menu.about'), id++);
764 menuSettings.onSelect = showSettings;
765 menuAbout.onSelect = showAbout;
766 menuCallApp.onSelect = launchCalendar;
767 menuUpdate.onSelect = showUpdate;
768 window.menu.clear();
769 window.menu.append(menuCallApp);
770 window.menu.append(menuSettings);
771 window.menu.append(menuUpdate);
772 window.menu.append(menuAbout);
773 }
774
775 function showSettings()
776 {
777 mode = 2;
778 hideViews();
779 document.getElementById("settingsView").style.display = "block";
780 document.onclick = null;
781
782 window.menu.setLeftSoftkeyLabel(getLocalizedText('settings.save'), function()
783 {
784 for (var key in config) {
785 if (config[key].Type == 'String')
786 config[key].Value = document.forms[0].elements["settings." + key].value;
787 else if (config[key].Type == 'Int') {
788 config[key].Value = parseInt(document.forms[0].elements["settings." + key].value);
789 if (config[key].Value < 0)
790 config[key].Value = config[key].Default;
791 }
792 else if (config[key].Type == 'Bool')
793 config[key].Value = document.forms[0].elements["settings." + key].checked;
794 else if (config[key].Type == 'UID')
795 config[key].Value = parseInt(document.forms[0].elements["settings." + key].value);
796 else if (config[key].Type == 'Enum') {
797 config[key].Value = document.forms[0].elements["settings." + key].value;
798 if (config[key].ValidValues.indexOf(config[key].Value) == -1)
799 config[key].Value = config[key].Default;
800 }
801 }
802
803 updateCssClasses();
804
805 saveSettings();
806
807 mode = 1;
808 showFullscreen();
809 });
810 window.menu.setRightSoftkeyLabel(getLocalizedText('settings.cancel'), function()
811 {
812 mode = 1;
813 showFullscreen();
814 });
815
816 var settingsHtml = '<form>';
817 for (var key in config) {
818 if (config[key].Type == 'String') {
819 var prefix = "";
820 if (key.substring(0,9) == "cssStyle_")
821 prefix = getLocalizedText('settings.cssStyle_prefix');
822 settingsHtml += '<table><tr><td>' + prefix + getLocalizedText('settings.name.' + key) + '<br /><input class="textInput" name="settings.' + key + '" type="text" value="' + config[key].Value + '" /></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '<hr />';
823 }
824 else if (config[key].Type == 'Int')
825 settingsHtml += '<table><tr><td>' + getLocalizedText('settings.name.' + key) + '<br /><input class="textInput" name="settings.' + key + '" type="text" value="' + config[key].Value + '" /></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '<hr />';
826 else if (config[key].Type == 'Bool')
827 settingsHtml += '<table><tr><td>' + getLocalizedText('settings.name.' + key) + '<br /><input name="settings.' + key + '" type="checkbox" value="true" ' + (config[key].Value ? 'checked="checked"' : '') + '/></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '<hr />';
828 else if (config[key].Type == 'UID')
829 settingsHtml += '<table><tr><td>' + getLocalizedText('settings.name.' + key) + '<br /><input class="textInput" name="settings.' + key + '" type="text" value="0x' + config[key].Value.toString(16) + '" /></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '<hr />';
830 else if (config[key].Type == 'Enum') {
831 settingsHtml += '<table><tr><td>' + getLocalizedText('settings.name.' + key) + '<br /><select name="settings.' + key + '" size="1">';
832 for(var i = 0; i < config[key].ValidValues.length; i++)
833 settingsHtml += '<option value="' + config[key].ValidValues[i] + '"' + (config[key].Value == config[key].ValidValues[i] ? ' selected="selected"' : '') + '>' + getLocalizedText('settings.validValues.' + key + '.' + config[key].ValidValues[i]) + '</option>';
834 settingsHtml += '</select></div></td>' + printHintBox(getLocalizedText('settings.info.' + key)) + '<hr />';
835 }
836 }
837 settingsHtml += '<input name="reset" type="button" value="' + getLocalizedText('settings.restoreDefaults') + '" onclick="javascript:restoreDefaultSettings();showSettings();" />';
838 settingsHtml += '</form>';
839 document.getElementById("settingsList").innerHTML = settingsHtml;
840 }
841
842 function changeCssClass(classname, properties)
843 {
844 for(var i = 0; i < document.styleSheets[0]['cssRules'].length; i++)
845 {
846 if (document.styleSheets[0]['cssRules'][i].selectorText == classname) {
847 document.styleSheets[0].deleteRule(i);
848 document.styleSheets[0].insertRule(classname + ' { ' + properties + ' }', document.styleSheets[0]['cssRules'].length);
849 break;
850 }
851 }
852 }
853
854 function updateCssClasses()
855 {
856 for(var key in config) {
857 changeCssClass(getLocalizedText('settings.name.' + key), config[key].Value);
858 }
859 }
860
861 function getSettingsCalEntryId()
862 {
863 if (settingsCalEntryId == null) {
864 // check if entry already exists
865 var listFiltering = {
866 Type:'CalendarEntry',
867 Filter:{
868 StartRange: new Date(2000, 0, 1),
869 EndRange: new Date(2000, 0, 1),
870 SearchText: 'ComingNext Settings|',
871 Type: 'DayEvent'
872 }
873 }
874 var result = calendarService.IDataSource.GetList(listFiltering);
875 if (result.ErrorCode) {
876 error(result.ErrorMessage);
877 return;
878 }
879 var list = result.ReturnValue;
880 var entry = list.getNext();
881 if (entry != undefined) {
882 settingsCalEntryId = entry.LocalId;
883 console.info("settingsCalEntryId=" + settingsCalEntryId);
884 }
885 else { // create settings item
886 var item = new Object();
887 item.Type = "DayEvent";
888 item.StartTime = new Date(2000, 0, 1);
889 item.Summary = "ComingNext Settings|";
890
891 var criteria = new Object();
892 criteria.Type = "CalendarEntry";
893 criteria.Item = item;
894
895 try {
896 var result = calendarService.IDataSource.Add(criteria);
897 if (result.ErrorCode)
898 error(result.ErrorMessage);
899 } catch (e) {
900 error("getSettingsCalEntryId: " + e + ', line ' + e.line);
901 }
902
903 getSettingsCalEntryId();
904 }
905 }
906 }
907
908 function restoreDefaultSettings()
909 {
910 for (var key in config)
911 config[key].Value = config[key].Default;
912 }
913
914 function loadSettings()
915 {
916 getSettingsCalEntryId();
917 var listFiltering = {
918 Type:'CalendarEntry',
919 Filter:{
920 LocalId: settingsCalEntryId
921 }
922 }
923 var result = calendarService.IDataSource.GetList(listFiltering);
924 if (result.ErrorCode) {
925 error(result.ErrorMessage);
926 return;
927 }
928 var entry = result.ReturnValue.getNext();
929 if (entry != undefined) {
930 // only reload settings if they chanced since the last reload
931 if (settingsCache != entry.Summary)
932 {
933 restoreDefaultSettings();
934 var stringlist = entry.Summary.split("|");
935 // skip the first two entries, those contain header and version info
936 for(var i = 2; i < stringlist.length - 1; i++) {
937 var pair = stringlist[i].split('=');
938 var key = pair[0];
939 var value = pair[1];
940 console.info('stringlist: ' + key + '=\'' + value + '\'');
941 if (config[key].Type == 'Int')
942 config[key].Value = Number(value);
943 else if (config[key].Type == 'String')
944 config[key].Value = value;
945 else if (config[key].Type == 'Bool')
946 config[key].Value = (value == 'true')
947 else if (config[key].Type == 'Enum')
948 config[key].Value = value;
949 else if (config[key].Type == 'UID')
950 config[key].Value = Number(value);
951 }
952 settingsCache = entry.Summary;
953 updateCssClasses();
954 }
955 }
956 else {
957 error("Failed to load settings, calendar entry could not be found");
958 }
959 }
960
961 function saveSettings()
962 {
963 getSettingsCalEntryId();
964 var item = new Object();
965 item.Type = "DayEvent";
966 item.StartTime = new Date(2000, 0, 1);
967 item.LocalId = settingsCalEntryId;
968 item.Summary = "ComingNext Settings|" + version + "|";
969
970 for (var key in config) {
971 if (config[key].Type == 'Int')
972 item.Summary += key + "=" + config[key].Value.toString() + "|";
973 else if (config[key].Type == 'String')
974 item.Summary += key + "=" + config[key].Value + "|";
975 else if (config[key].Type == 'Bool')
976 item.Summary += key + "=" + (config[key].Value ? 'true' : 'false') + "|";
977 else if (config[key].Type == 'Enum')
978 item.Summary += key + "=" + config[key].Value + "|";
979 else if (config[key].Type == 'UID')
980 item.Summary += key + "=" + config[key].Value.toString() + "|";
981 }
982 settingsCache = item.Summary;
983
984 var criteria = new Object();
985 criteria.Type = "CalendarEntry";
986 criteria.Item = item;
987
988 console.info("Saving settings to calendar entry: " + item.Summary);
989 try {
990 var result = calendarService.IDataSource.Add(criteria);
991 if (result.ErrorCode)
992 error(result.ErrorMessage);
993 } catch (e) {
994 error("saveSettings: " + e + ', line ' + e.line);
995 }
996 }
997
998 function toggleVisibility(elementId)
999 {
1000 if (document.getElementById(elementId).style.display == "none")
1001 document.getElementById(elementId).style.display = "block";
1002 else
1003 document.getElementById(elementId).style.display = "none";
1004 }
1005
1006 var uniqueId = 0;
1007 function printHintBox(text)
1008 {
1009 uniqueId++;
1010 return '<td width="1%" align="right" onclick="javascript:toggleVisibility(\'info' + uniqueId + '\')">' + getLocalizedText('settings.help') + '</td></tr></table>'+
1011 '<div class="settingsInfo" id="info' + uniqueId + '">' + text + '</div>';
1012 }
1013
1014 function showAbout()
1015 {
1016 mode = 3;
1017 hideViews();
1018 document.getElementById("aboutView").style.display = "block";
1019 document.onclick = null;
1020
1021 window.menu.setLeftSoftkeyLabel(" ", function(){});
1022 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1023 {
1024 mode = 1;
1025 showFullscreen();
1026 });
1027
1028 //document.getElementById("aboutView").innerHTML = 'aboutView';
1029 document.getElementById("name").innerHTML = "Coming Next " + version;
1030 }
1031
1032 function updateFullscreen()
1033 {
1034 }
1035
1036 function showFullscreen()
1037 {
1038 hideViews();
1039 document.getElementById("fullscreenView").style.display = "block";
1040 document.getElementById('body').className = "backgroundFullscreen";
1041 document.onclick = launchCalendar;
1042 createMenu();
1043 updateData();
1044 }
1045
1046 function getBackgroundImage()
1047 {
1048 var bgImage;
1049 if (config['backgroundImageLocation'].Value == config['backgroundImageLocation'].ValidValues[0]) // internal
1050 bgImage = 'background_' + orientation + '.png';
1051 else
1052 bgImage = 'C:/Data/background_' + panelNum + '_' + orientation + '.png';
1053 return bgImage;
1054 }
1055
1056 function updateHomescreen()
1057 {
1058 if (config['useBackgroundImage'].Value) {
1059 // check for screen rotation
1060 if (orientation != 'portrait' && screen.width == 360 && screen.height == 640) {
1061 window.widget.prepareForTransition("fade");
1062 orientation = 'portrait';
1063 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1064 document.getElementById('body').style.backgroundColor = 'none';
1065 window.widget.performTransition();
1066 } else if (orientation != 'landscape' && screen.width == 640 && screen.height == 360) {
1067 window.widget.prepareForTransition("fade");
1068 orientation = 'landscape';
1069 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1070 document.getElementById('body').style.backgroundColor = 'none';
1071 window.widget.performTransition();
1072 }
1073 else if (document.getElementById('body').style.backgroundImage == "")
1074 {
1075 document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';
1076 }
1077 }
1078 }
1079
1080 function showHomescreen()
1081 {
1082 hideViews();
1083 document.getElementById("homescreenView").style.display = "block";
1084 document.getElementById('body').className = "background";
1085 document.onclick = null;
1086 updateData();
1087 }
1088
1089 function getLocalizedText(p_Txt)
1090 {
1091 if (localizedText[p_Txt])
1092 return localizedText[p_Txt];
1093 else
1094 return 'ERROR: missing translation for ' + p_Txt;
1095 }
1096
1097 function showUpdate()
1098 {
1099 mode = 4;
1100 hideViews();
1101 document.getElementById("updateView").style.display = "block";
1102 document.onclick = null;
1103
1104 window.menu.setLeftSoftkeyLabel(getLocalizedText('update.checknow'), function(){
1105 checkForUpdate();
1106 });
1107 window.menu.setRightSoftkeyLabel(getLocalizedText('softkey.back'), function()
1108 {
1109 mode = 1;
1110 showFullscreen();
1111 });
1112
1113 document.getElementById("currentVersion").innerHTML = getLocalizedText("update.current") + version;
1114 checkForUpdate();
1115 }
1116
1117 function checkForUpdate()
1118 {
1119 // asynch XHR to server url
1120 reqV = new XMLHttpRequest();
1121 reqV.onreadystatechange = checkForUpdateCallback;
1122 document.getElementById("updateDiv").innerHTML = getLocalizedText("update.checking");
1123 reqV.open("GET", versionURL, true);
1124 reqV.setRequestHeader( "If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT" ); // disable caching
1125 reqV.send(null);
1126 }
1127
1128 function checkForUpdateCallback()
1129 {
1130 if (reqV.readyState == 4) {
1131 if (reqV.status == 200) {
1132 var resultXml = reqV.responseText;
1133 if (resultXml) {
1134 var div = document.getElementById("tmp");
1135 div.innerHTML = resultXml;
1136 var newVersion = div.getElementsByTagName('version')[0].innerHTML;
1137 var newVersionURL = div.getElementsByTagName('url')[0].innerHTML;
1138 div.innerHTML = "";
1139 if (version != newVersion) {
1140 document.getElementById("updateDiv").innerHTML = getLocalizedText("update.download").replace(/%1/, newVersion).replace(/%2/, newVersionURL);
1141 }
1142 else {
1143 document.getElementById("updateDiv").innerHTML = getLocalizedText("update.nonewversion");
1144 }
1145 }
1146 }
1147 else {
1148 document.getElementById("updateDiv").innerHTML = getLocalizedText("update.error") + reqV.status + " " + reqV.responseText;
1149 }
1150 }
1151 }
1152
1153 function hideViews()
1154 {
1155 document.getElementById("homescreenView").style.display = "none";
1156 document.getElementById("fullscreenView").style.display = "none";
1157 document.getElementById("aboutView").style.display = "none";
1158 document.getElementById("settingsView").style.display = "none";
1159 document.getElementById("updateView").style.display = "none";
1160 }
1161 </script>
1162
1163 <style type="text/css">
1164 table { margin:0px; padding:0px; border-spacing:0px; }
1165 td { padding:0px 5px 0px 0px; white-space:nowrap; overflow:hidden; }
1166 hr { color:#ffffff; background-color:#ffffff; height:1px; text-align:left; border-style:none; }
1167 .settingsInfo { display:none; font-style:italic; }
1168 .title { font-weight:bold; font-size:14pt; }
1169 .textInput { width:90%; }
1170 .credits { margin-left:40px; text-indent: -20px; margin-bottom:0px; }
1171 #homescreenView { width: 315px; height:91px; overflow:hidden; }
1172 #calendarList { position:absolute; left:10px; top:4px; width:295px; height:75px; overflow:hidden; }
1173 #name { text-align:center; }
1174 #appicon { display: block; margin-left: auto; margin-right: auto; margin-top: 10px; }
1175 #smallappicon { width:22px; height:22px; margin-right:10px; float:left; }
1176 </style>
1177
1178 </head>
1179
1180 <body id="body" class="background">
1181 <div id="homescreenView">
1182 <div id="calendarList"></div>
1183 </div>
1184 <div id="fullscreenView" style="display:none;">
1185 <img src="Icon.png" id="smallappicon">
1186 <h1 class="title">Coming Next</h1>
1187 <hr />
1188 <div id="fullscreenCalendarList">loading...</div>
1189 </div>
1190 <div id="settingsView" style="display:none">
1191 <img src="Icon.png" id="smallappicon">
1192 <h1 id="settingsTitle" class="title">Settings</h1>
1193 <hr />
1194 <div id="settingsList"></div>
1195 </div>
1196 <div id="aboutView" style="display:none">
1197 <img src="Icon.png" id="appicon">
1198 <h1 id="name">Coming Next</h1>
1199 <hr />
1200 <p>Created by Dr. Cochambre and Michael Prager.</p>
1201 <p>Contributions:</p>
1202 <p class="credits">Paul Moore (bug fixes, new features and code cleanup)</p>
1203 <p class="credits">Manfred Hanselmann (DST support)</p>
1204 <p class="credits">Christophe Milsent (translation support & french translation)</p>
1205 <p class="credits">Flavio Nathan (portuguese-brazilian translation)</p>
1206 <p class="credits">Tokeda (russian translation)</p>
1207 <p>This software is open source and licensed under the GPLv3.</p>
1208 <p>Visit sourceforge.net/projects/comingnext for free updates.</p>
1209 <hr />
1210 </div>
1211 <div id="updateView" style="display:none">
1212 <img src="Icon.png" id="smallappicon">
1213 <h1 class="title">Check for update</h1>
1214 <hr />
1215 <div id="currentVersion">Coming Next ??</div>
1216 <div id="updateDiv"></div>
1217 <div id="tmp" style="display:none;"></div>
1218 </div>
1219 </body>
1220
1221 </html>