// Nothing of interest from here on...\r
//-------------------------------------------------------\r
var panelNum = 0; // use 1 for second panel\r
-var version = "1.32";\r
+var version = "1.34";\r
var versionURL = "http://comingnext.sourceforge.net/version.xml";\r
var calendarService = null;\r
var cacheEntriesHtml = [];\r
var months_translated = [];\r
+var weekdays_translated = [];\r
var orientation = '';\r
var now = new Date();\r
var mode = 0; // 0 = homescreen, 1 = fullscreen, 2 = settings, 3 = about, 4 = check for update\r
var reloadInterval = 6 * 60 * 60 * 1000; // = 6 hours; time interval for reloading calendar data\r
var errorOccured = false;\r
var entryLists = null; // stores all fetched calendar entries until data is refreshed\r
+var statupSuccessful = false; // indicates if everything started up wihtout errors. If we detect an error after that, it might just be a temporary problem e.g. by a backup process.\r
+var use12hoursTimeFormat = false; // defines how time should be formated: 19:00 or 07:00 pm\r
+var timeFormatSeparator = ":"; // format time 19:00 or 19.00 depending on system setting\r
\r
// vars for daylight saving time\r
var summertime = false; // true, if current date is in summer, false if in winter\r
try {\r
var result = calendarService.IDataSource.Add(criteria);\r
if (result.ErrorCode)\r
- error(result.ErrorMessage);\r
+ throw(result.ErrorMessage);\r
+ } catch (e) {\r
+ error("collectLocales: " + e + ', line ' + e.line);\r
+ }\r
+ }\r
+ for (weekday = 0; weekday < 7; weekday++) {\r
+ var startDate = new Date(2000, 0, 2 + weekday); // date that we know for sure is a sunday\r
+\r
+ var item = new Object();\r
+ item.Type = "DayEvent";\r
+ item.StartTime = startDate;\r
+ item.Summary = "__weekday_temp" + weekday;\r
+\r
+ var criteria = new Object();\r
+ criteria.Type = "CalendarEntry";\r
+ criteria.Item = item;\r
+\r
+ try {\r
+ var result = calendarService.IDataSource.Add(criteria);\r
+ if (result.ErrorCode)\r
+ throw(result.ErrorMessage);\r
} catch (e) {\r
error("collectLocales: " + e + ', line ' + e.line);\r
}\r
}\r
}\r
var result = calendarService.IDataSource.GetList(listFiltering);\r
- if (result.ErrorCode) {\r
- error(result.ErrorMessage);\r
- return;\r
- }\r
+ if (result.ErrorCode)\r
+ throw(result.ErrorMessage);\r
var list = result.ReturnValue;\r
} catch(e) {\r
- error(e + ', line ' + e.line);\r
+ error("collectLocales: " + e + ', line ' + e.line);\r
return;\r
}\r
var ids = new Array();\r
var dateArr = [];\r
\r
while (list && (entry = list.getNext()) != undefined) {\r
- dateArr = entry.StartTime.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');\r
+ dateArr = (entry.StartTime + '').replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');\r
var day = dateArr[1];\r
var month = dateArr[2];\r
var year = dateArr[3];\r
counter++;\r
}\r
} catch(e) {\r
- error(e + ', line ' + e.line);\r
+ error("collectLocales: " + e + ', line ' + e.line);\r
+ return;\r
+ }\r
+ try {\r
+ var startTime = new Date(2000,0,2);\r
+ var endTime = new Date(2000,0,9);\r
+ var listFiltering = {\r
+ Type:'CalendarEntry', \r
+ Filter:{\r
+ StartRange: startTime,\r
+ EndRange: endTime,\r
+ SearchText: '__weekday_temp',\r
+ Type: 'DayEvent'\r
+ }\r
+ }\r
+ var result = calendarService.IDataSource.GetList(listFiltering);\r
+ if (result.ErrorCode)\r
+ throw(result.ErrorMessage);\r
+ var weekdaylist = result.ReturnValue;\r
+ } catch(e) {\r
+ error("collectLocales: " + e + ', line ' + e.line);\r
+ return;\r
+ }\r
+ try {\r
+ var entry;\r
+ var counter2 = 0;\r
+ var curWeekday = "";\r
+\r
+ while (weekdaylist && (entry = weekdaylist.getNext()) != undefined) {\r
+ detectTimeFormat(entry.StartTime + '');\r
+ curWeekday = (entry.StartTime + '').split(',')[0];\r
+ log(entry.StartTime + ' -> ' + curWeekday + ' ' + counter2);\r
+ ids[counter + counter2] = entry.id;\r
+ weekdays_translated[counter2] = curWeekday;\r
+ counter2++;\r
+ }\r
+ } catch(e) {\r
+ error("collectLocales: " + e + ', line ' + e.line);\r
return;\r
}\r
log(ids);\r
\r
var result = calendarService.IDataSource.Delete(criteria);\r
if (result.ErrorCode)\r
- error(result.ErrorMessage);\r
+ throw(result.ErrorMessage);\r
} catch(e) {\r
error('deleting temp calendar entries:' + e + ', line ' + e.line);\r
return;\r
}\r
}\r
\r
+// detects the system's current time format by parsing a native calendar timestamp (this is the only reliable formating across all devices and firmwares)\r
+function detectTimeFormat(localeTimeString)\r
+{\r
+ localeTimeString = localeTimeString.toLowerCase();\r
+ use12hoursTimeFormat = localeTimeString.indexOf("am") != -1 || localeTimeString.indexOf("pm") != -1 ? true : false;\r
+ timeFormatSeparator = localeTimeString.indexOf(":") != -1 ? ":" : ".";\r
+}\r
+\r
function requestNotification()\r
{\r
var criteria = new Object();\r
Wednesday, 2009 August, 28 8.00.00 pm\r
Wednesday, 2009 August, 28 08:00:00 PM\r
*/\r
+ var result = null;\r
\r
- if (dateString == "" || dateString == null)\r
- return null;\r
- var dateArr = dateString.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');\r
- if (dateArr.length != 5 && dateArr.length != 6)\r
- return null;\r
-\r
- // parse date\r
- var weekDay = dateArr[0];\r
- var day = dateArr[1];\r
- var month = dateArr[2];\r
- var year = dateArr[3];\r
- // make sure month is set properly\r
- if (isNaN(parseInt(day))) {\r
- var tmp = day;\r
- day = month;\r
- month = tmp;\r
- } else if (isNaN(parseInt(year))) {\r
- var tmp = year;\r
- year = month;\r
- month = tmp;\r
+ if (dateString == "" || dateString == null || dateString == undefined)\r
+ return result;\r
+ if (dateString instanceof Date) {\r
+ // we already have a date object, no need to parse string here\r
+ result = dateString;\r
}\r
- // make sure day and year are set properly\r
- if (Number(day) > Number(year)) {\r
- var tmp = year;\r
- year = day;\r
- day = tmp;\r
+ else {\r
+ var dateArr = (dateString + '').replace(/,/g, '').replace(/\./g, ':').replace(/ /g, ' ').split(' ');\r
+ if (dateArr.length != 5 && dateArr.length != 6) \r
+ return null;\r
+ \r
+ // parse date\r
+ var weekDay = dateArr[0];\r
+ var day = dateArr[1];\r
+ var month = dateArr[2];\r
+ var year = dateArr[3];\r
+ // make sure month is set properly\r
+ if (isNaN(parseInt(day))) {\r
+ var tmp = day;\r
+ day = month;\r
+ month = tmp;\r
+ }\r
+ else \r
+ if (isNaN(parseInt(year))) {\r
+ var tmp = year;\r
+ year = month;\r
+ month = tmp;\r
+ }\r
+ // make sure day and year are set properly\r
+ if (Number(day) > Number(year)) {\r
+ var tmp = year;\r
+ year = day;\r
+ day = tmp;\r
+ }\r
+ month = months_translated[month];\r
+ \r
+ // parse time\r
+ var timeArr = dateArr[4].split(':');\r
+ if (timeArr.length != 3) \r
+ return null;\r
+ var hours = Number(timeArr[0]);\r
+ var minutes = Number(timeArr[1]);\r
+ var seconds = Number(timeArr[2]);\r
+ if (dateArr.length == 6 && dateArr[5].toLowerCase() == 'pm' && hours < 12) \r
+ hours += 12;\r
+ if (dateArr.length == 6 && dateArr[5].toLowerCase() == 'am' && hours == 12) \r
+ hours = 0;\r
+ \r
+ result = new Date(year, month - 1, day, hours, minutes, seconds);\r
}\r
- month = months_translated[month];\r
-\r
- // parse time\r
- var timeArr = dateArr[4].split(':');\r
- if (timeArr.length != 3)\r
- return null;\r
- var hours = Number(timeArr[0]);\r
- var minutes = Number(timeArr[1]);\r
- var seconds = Number(timeArr[2]);\r
- if (dateArr.length == 6 && dateArr[5].toLowerCase() == 'pm' && hours < 12)\r
- hours += 12;\r
- if (dateArr.length == 6 && dateArr[5].toLowerCase() == 'am' && hours == 12)\r
- hours = 0;\r
-\r
- var result = new Date(year, month - 1, day, hours, minutes, seconds);\r
\r
// take care of daylight saving time\r
if (config['enableDaylightSaving'].Value) {\r
return result;\r
}\r
\r
+function getWeekdayLocalized(date) {\r
+ var localizedString = date.toLocaleDateString();\r
+ if (localizedString.indexOf(",") == -1) {\r
+ return weekdays_translated[date.getDay()];\r
+ } else\r
+ return localizedString.split(',')[0];\r
+}\r
+\r
// 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"\r
function formatDate(date, format)\r
{\r
if (config['showTodayAsText'].Value && isTomorrow(date))\r
return '<span class="tomorrow">' + config['tomorrowText'].Value + '</span>';\r
\r
+ if (format instanceof Date) {\r
+ // we don't know how to format this\r
+ if (config['dateFormat'].Value == 'auto' || config['dateFormat'].Value == 'DDMM')\r
+ return day + config['dateSeparator'].Value + month;\r
+ else\r
+ return month + config['dateSeparator'].Value + day;\r
+ }\r
var dateArr = format.replace(/,/g,'').replace(/\./g,':').replace(/ /g,' ').split(' ');\r
if (dateArr.length != 5 && dateArr.length != 6) {\r
// we don't know how to format this\r
function formatTime(date)\r
{\r
// date is a Date() object\r
- date.setSeconds(0); // we don't care about seconds\r
- var time = date.toLocaleTimeString().replace(/[\.:]00/, ''); // remove seconds from string\r
- if (time.replace(/\./, ':').split(':')[0].length < 2)\r
- time = '0' + time;\r
+ var hour = date.getHours();\r
+ var minute = date.getMinutes();\r
+ \r
+ // don't use Date().toLocaleTimeString() as it is utterly broken on newer firmwares\r
+ if (use12hoursTimeFormat) {\r
+ var ap = "AM";\r
+ if (hour > 11)\r
+ ap = "PM";\r
+ if (hour > 12)\r
+ hour = hour - 12;\r
+ if (hour == 0)\r
+ hour = 12;\r
+ if (hour < 10)\r
+ hour = "0" + hour;\r
+ if (minute < 10)\r
+ minute = "0" + minute;\r
+ time = hour + timeFormatSeparator + minute + " " + ap;\r
+ }\r
+ else {\r
+ if (hour < 10)\r
+ hour = "0" + hour;\r
+ if (minute < 10)\r
+ minute = "0" + minute;\r
+ time = hour + timeFormatSeparator + minute;\r
+ }\r
+ \r
if (config['showNowAsText'].Value && date.getTime() == now.getTime())\r
time = '<span class="now">' + config['nowText'].Value + '</span>';\r
+ log("formatTime(): " + time + ", use12hoursTimeFormat=" + use12hoursTimeFormat + ", timeFormatSeparator=" + timeFormatSeparator + ", date.toLocateTimeString(): " + date.toLocaleTimeString());\r
return time;\r
}\r
\r
\r
// check if we got additional or less calendars since our last update\r
var newCalendarList = listCalendars();\r
+ if (newCalendarList == null) {\r
+ // Something went wrong fetching the calendars list.\r
+ // This usually happens when a backup is being made.\r
+ // Retry the next time updateData() is called by \r
+ // resetting errorOccured\r
+ log('updateData(): listCalendars() failed, trying again later...');\r
+ cacheEntriesHtml = ''; // make sure we replace the currently shown error message on the next update\r
+ errorOccured = false;\r
+ return;\r
+ }\r
if (newCalendarList.length != calendarList.length) {\r
calendarList = newCalendarList;\r
updateCalendarColors();\r
var entryDate = '';\r
var dateArr = [];\r
var fontsize = 'normal';\r
+ var lineheight = 'normal';\r
if (mode == 0) {\r
+ fontsize = parseInt(72 / config['eventsPerWidget'].Value) + 'px';\r
+ lineheight = parseInt(82 / config['eventsPerWidget'].Value) + 'px';\r
+ \r
if (config['eventsPerWidget'].Value == 3) {\r
- fontsize = '17pt';\r
changeCssClass('.icon', 'width:20px; height:20px');\r
}\r
else if (config['eventsPerWidget'].Value == 5) {\r
- fontsize = '10pt';\r
changeCssClass('.icon', 'width:10px; height:10px');\r
}\r
else if (config['eventsPerWidget'].Value == 6) {\r
- fontsize = '8pt';\r
changeCssClass('.icon', 'width:8px; height:8px');\r
}\r
}\r
else\r
changeCssClass('.icon', config['cssStyle_icon'].Value);\r
- var entriesHtml = '<table style="font-size:' + fontsize + ';">';\r
+ var entriesHtml = '<table style="font-size:' + fontsize + '; line-height:' + lineheight + ';">';\r
+ if (mode == 0)\r
+ entriesHtml = '<table width="307" height="82"><tr><td>' + entriesHtml; // this is needed to center the actual content vertically\r
var eventIds = [];\r
var max;\r
if (mode == 0)\r
\r
// summary can be undefined!\r
var Summary = ((entry.Summary == null) ? '' : entry.Summary);\r
- if (entry.Type == 'Meeting' && entry.Location != '' && config['showLocation'].Value)\r
+ if (entry.Location != '' && entry.Location != undefined && config['showLocation'].Value)\r
Summary += ', ' + entry.Location;\r
\r
// fix by yves: determine start and end dates/times\r
log('date: ' + date);\r
var endDate = ((entryEndTime == null) ? null : parseDate(entryEndTime));\r
log('endDate: ' + endDate);\r
+ \r
+ // check if Meeting is actually a DayEvent. Bug introduced by "Anna" updates to various Symbian^3 devices.\r
+ // Note that this workaround is not 100% save! It might missinterpret some meetings as dayevents of starting and ending on 00:00\r
+ if (entry.Type == 'Meeting' && date.getHours() == 0 && date.getMinutes() == 0 && \r
+ endDate != null && endDate.getHours() == 0 && endDate.getMinutes() == 0) {\r
+ log('fixing event type: changed from "Meeting" to "DayEvent".');\r
+ entry.Type = 'DayEvent';\r
+ }\r
\r
// check if meeting event has already passed\r
if (entry.Type == 'Meeting') {\r
// some languages have very strange locale date formats, can't parse all those. Also some todos don't have dates at all.\r
entriesHtml += '<td colspan="4"><span class="date">' + entryDate + '</span> ';\r
} else {\r
- var weekDay = date.toLocaleDateString().substr(0,config['weekDayLength'].Value);\r
+ var weekDay = getWeekdayLocalized(date).substr(0,config['weekDayLength'].Value);\r
+ log('date.toLocaleDateString(): ' + date.toLocaleDateString());\r
+ log('weekDay: ' + weekDay);\r
var time = formatTime(date);\r
var dateStr = formatDate(date, entryDate);\r
if (entry.Type == 'ToDo' && overdue && config['markOverdueTodos'].Value) {\r
}\r
}\r
entriesHtml += '</table>';\r
+ if (mode == 0)\r
+ entriesHtml = entriesHtml + '</td></tr></table>';\r
if (config['showNothingText'].Value && entriesHtml == '<table></table>') {\r
var text = config['nothingText'].Value.replace(/%d/, config['monthRange'].Value);\r
entriesHtml = '<div style="width:295px; height:75px; text-align:center; line-height:75px; overflow:visible;">' + text + '</div>';\r
window.widget.onshow = handleOnShow;\r
\r
log("init(): finished...");\r
+ if (!errorOccured)\r
+ statupSuccessful = true;\r
}\r
\r
function checkOrientation()\r
var listFiltering = {\r
Type:'CalendarEntry', \r
Filter:{\r
- StartRange: new Date(2000, 0, 1),\r
- EndRange: new Date(2000, 0, 1),\r
+ StartRange: new Date(1999, 11, 30), // note: due to Nokia's buggy calendar API, the settings event can be on 01.01.2000 AND on 31.12.1999, depending on when the calendar entry was created (in summer or winter). It is not even possible to narrow the search down to these two days (probably because of DST offsets). So we're looking for an event between 30.12.1999 and 02.01.2000!\r
+ EndRange: new Date(2000, 0, 2),\r
SearchText: 'ComingNext Settings|',\r
Type: 'DayEvent'\r
}\r
}\r
- var result = calendarService.IDataSource.GetList(listFiltering);\r
- if (result.ErrorCode) {\r
- error(result.ErrorMessage);\r
+ var result = null;\r
+ try {\r
+ result = calendarService.IDataSource.GetList(listFiltering);\r
+ if (result.ErrorCode)\r
+ throw(result.ErrorMessage);\r
+ }\r
+ catch (e) {\r
+ error("getSettingsCalEntryId: GetList() failed: " + e + ', line ' + e.line);\r
return;\r
}\r
var list = result.ReturnValue;\r
try {\r
var result = calendarService.IDataSource.Add(criteria);\r
if (result.ErrorCode)\r
- error(result.ErrorMessage);\r
+ throw(result.ErrorMessage);\r
} catch (e) {\r
error("getSettingsCalEntryId: " + e + ', line ' + e.line);\r
}\r
LocalId: settingsCalEntryId\r
}\r
}\r
- var result = calendarService.IDataSource.GetList(listFiltering);\r
- if (result.ErrorCode) {\r
- error(result.ErrorMessage);\r
+ var result = null;\r
+ try {\r
+ result = calendarService.IDataSource.GetList(listFiltering);\r
+ if (result.ErrorCode)\r
+ throw(result.ErrorMessage);\r
+ }\r
+ catch (e) {\r
+ error("loadSettings: GetList() failed: " + e + ', line ' + e.line);\r
return;\r
}\r
var entry = result.ReturnValue.getNext();\r
var pair = stringlist[i].split('=');\r
var key = pair[0];\r
var value = pair[1];\r
+ if (key == null || value == null || config[key] == null) {\r
+ log('Warning: unknown or invalid setting: ' + stringlist[i]);\r
+ continue;\r
+ }\r
log('stringlist: ' + key + '=\'' + value + '\'');\r
if (config[key].Type == 'Int') {\r
config[key].Value = Number(value);\r
try {\r
var result = calendarService.IDataSource.Add(criteria);\r
if (result.ErrorCode)\r
- error(result.ErrorMessage);\r
+ throw(result.ErrorMessage);\r
} catch (e) {\r
error("saveSettings: " + e + ', line ' + e.line);\r
}\r
function updateHomescreen()\r
{\r
if (config['useBackgroundImage'].Value) {\r
+ // check if we have a completely unknown screen resolution\r
+ var screenHeight = screen.height;\r
+ var screenWidth = screen.width;\r
+ if (screenHeight != 640 && screenHeight != 480 && screenHeight != 360)\r
+ screenHeight = 360; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code\r
+ if (screenWidth != 640 && screenWidth != 480 && screenWidth != 360)\r
+ screenWidth = 640; // we can only assume we're in portrait mode, so we set the screen dims as needed for the following code\r
+ \r
// check for screen rotation\r
- if (orientation != 'portrait' && screen.width == 360 && screen.height == 640) {\r
+ if (orientation != 'portrait' && ((screenWidth == 360 && screenHeight == 640) || (screenWidth == 640 && screenHeight == 480))) {\r
window.widget.prepareForTransition("fade");\r
orientation = 'portrait';\r
document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';\r
document.getElementById('body').style.backgroundColor = 'none';\r
window.widget.performTransition();\r
- } else if (orientation != 'landscape' && screen.width == 640 && screen.height == 360) {\r
+ } else if (orientation != 'landscape' && ((screenWidth == 640 && screenHeight == 360) || (screenWidth == 480 && screenHeight == 640))) {\r
window.widget.prepareForTransition("fade");\r
orientation = 'landscape';\r
document.getElementById('body').style.backgroundImage = 'url(' + getBackgroundImage() + ')';\r
}\r
}\r
\r
-function log(message) {\r
+function log(message)\r
+{\r
if (config['enableLogging'].Value) {\r
console.info(message);\r
}\r
\r
<style type="text/css">\r
a { color:#aaccff }\r
-table { margin:0px; padding:0px; border-spacing:0px; }\r
-td { padding:0px 5px 0px 0px; white-space:nowrap; overflow:hidden; }\r
+table { margin:0px; padding:0px; border-spacing:0px; border-collapse: collapse; }\r
+td { padding:0px 5px 0px 0px; white-space:nowrap; overflow:hidden; margin:0px; }\r
hr { color:#ffffff; background-color:#ffffff; height:1px; text-align:left; border-style:none; }\r
.settingsInfo { display:none; font-style:italic; }\r
.title { font-weight:bold; font-size:14pt; }\r
.textInput { width:90%; }\r
.credits { margin-left:40px; text-indent: -20px; margin-bottom:0px; }\r
-#homescreenView { width: 315px; height:91px; overflow:hidden; }\r
-#calendarList { position:absolute; left:5px; top:4px; width:295px; height:75px; overflow:hidden; }\r
+#homescreenView { width: 312px; height:82px; overflow:hidden; }\r
+#calendarList { position:absolute; left:5px; top:0px; width:307px; height:82px; overflow:hidden; }\r
#name { text-align:center; }\r
#appicon { display: block; margin-left: auto; margin-right: auto; margin-top: 10px; }\r
#smallappicon { width:22px; height:22px; margin-right:10px; float:left; }\r