updates and additions
[webos-internals:modifications.git] / calendar / calendar-ubercalendar.patch
1 diff --git a/usr/palm/applications/com.palm.app.calendar/app/controllers/app-assistant.js b/usr/palm/applications/com.palm.app.calendar/app/controllers/app-assistant.js
2 index 5375929..5bbcb88 100644
3 --- a/usr/palm/applications/com.palm.app.calendar/app/controllers/app-assistant.js
4 +++ b/usr/palm/applications/com.palm.app.calendar/app/controllers/app-assistant.js
5 @@ -8,6 +8,27 @@ var AppAssistant = Class.create({
6                 this.appController = appController;
7                 this.openReminderAlert = null;
8                 
9 +               //get snooze cookie -- renamed because of bug in cookie names
10 +               this.snoozeCookie = new Mojo.Model.Cookie("snoozeCookie");      
11 +               if (this.snoozeCookie) {
12 +                       var snzcookie = this.snoozeCookie.get();
13 +                       if (snzcookie) {                        
14 +                               if(snzcookie.showReminderDashboard !== undefined) {
15 +                                       this.showReminderDashboard = snzcookie.showReminderDashboard;
16 +                               } else {
17 +                                       this.showReminderDashboard = false;
18 +                               }
19 +                               if(snzcookie.snoozethrob !== undefined) {
20 +                                       this.snoozeThrob = snzcookie.snoozethrob;
21 +                               } else {
22 +                                       this.snoozeThrob = false;
23 +                               }
24 +                       }
25 +               } else {
26 +                       this.snoozeThrob = false;
27 +                       this.showReminderDashboard = false;
28 +               }
29 +               
30                 // CURRENT DATE & TIME - Keeps track of the current day/month/time in view
31                 this.currentDateTime = new Date();
32                 this.currentDateTimeObservers = new Hash();
33 @@ -77,9 +98,9 @@ var AppAssistant = Class.create({
34                 // TEMP Ignore the first time we get called which is at boot time. We need this until framework
35                 // gives us a flag to let us now if this being called at boot.
36                 this.handlelaunchCount++;
37 -               if (this.handlelaunchCount <= 1)
38 +               if (this.handlelaunchCount <= 1) {
39                         return; 
40 -                       
41 +               }
42                 //if this failed during initialization, try again       
43                 if (!this.calendarsManager.accounts) {                  
44                         this.calendarsManager.getCalendarsByAccount();
45 @@ -116,7 +137,10 @@ var AppAssistant = Class.create({
46                 else if (launchParams.alarmclose){
47                         Mojo.Log.info("$$$$$$$$ AppAssistant handleLaunch : alarmclose");
48                         this.closeReminder(launchParams.alarmclose);
49 -               } 
50 +               }
51 +               else if (launchParams.playalarmsound){
52 +                       this.playAlarmSound();
53 +               }
54                 else if (launchParams.dayChange){
55                         this.dayChange();
56                 }
57 @@ -267,6 +291,20 @@ var AppAssistant = Class.create({
58                 Mojo.Log.info("$$$$$$$$ AppAssistant closeReminder:end");
59         },
60         
61 +       playAlarmSound: function() {
62 +               if (this.openReminderAlert) {
63 +                       this.openReminderAlert.playAlarmSound();
64 +                       this.openReminderAlert = null;
65 +               }
66 +       },
67 +
68 +       closeToDashboard: function() {
69 +               if(this.openReminderAlert) {
70 +                       this.openReminderAlert.closeToDashboard();
71 +                       this.openReminderAlert = null;
72 +               }
73 +       },
74 +       
75         scheduleNextReminder: function(eventId) {
76                 Mojo.Log.info("$$$$$$$$ AppAssistant scheduleNextReminder: for event:"+eventId);
77                 new Mojo.Service.Request('palm://com.palm.calendar', {
78 @@ -398,10 +436,15 @@ var AppAssistant = Class.create({
79                 var height;
80                 var reminder = getReminderManager().getReminder(eventId);
81                 reminder.userClosed = false;
82 -               if (reminder.attendees.length > 1 /*now we include the organizer in attendee list*/)
83 -                       height = 203;
84 -               else
85 -                       height = 149;
86 +               if(reminder.attendees) {
87 +                       if (reminder.attendees.length > 1 /*now we include the organizer in attendee list*/) {
88 +                               height = 205; //203 orig; 74 + a couple to get more choices
89 +                       } else {
90 +                       height = 160; //149 orig;
91 +                       }
92 +               } else {
93 +                       height = 160;
94 +               }
95                 
96                 var needThrobbing =(hasNewContent || !isSnoozedReminder) ? true:false;
97                 Mojo.Log.info("$$$$$$$$ AppAssistant doAlarm:createStageWithCallback for stage: "+this.createAlarmStageName(eventId)+", stage height is: "+height);
98 @@ -435,23 +478,25 @@ var AppAssistant = Class.create({
99                                 }, pushReminderScene.bind(this, eventId, needThrobbing), 'popupalert');
100                         }
101                 }
102 -               
103 -               Mojo.Log.info("$$$$$$$$ AppAssistant doAlarm:calling getStageController for calendar-dashboard");
104 -               var dashboardStageController = Mojo.Controller.getAppController().getStageController("calendar-dashboard");
105 -               if (!dashboardStageController) {
106 -                       Mojo.Log.info("$$$$$$$$ AppAssistant doAlarm:calling getStageProxy for calendar-dashboard");
107 -                       dashboardStageController = Mojo.Controller.getAppController().getStageProxy("calendar-dashboard");
108 -               }
109 -               if (!dashboardStageController) {
110 -                       var pushDashboardScene = function(stageController){
111 -                               stageController.pushScene('dashboard');
112 +               //Optionally disable reminder dashboard
113 +               if(this.showReminderDashboard || this.snoozeThrob) {
114 +                       Mojo.Log.info("$$$$$$$$ AppAssistant doAlarm:calling getStageController for calendar-dashboard");
115 +                       var dashboardStageController = Mojo.Controller.getAppController().getStageController("calendar-dashboard");
116 +                       if (!dashboardStageController) {
117 +                               Mojo.Log.info("$$$$$$$$ AppAssistant doAlarm:calling getStageProxy for calendar-dashboard");
118 +                               dashboardStageController = Mojo.Controller.getAppController().getStageProxy("calendar-dashboard");
119 +                       }
120 +                       if (!dashboardStageController) {
121 +                               var pushDashboardScene = function(stageController){
122 +                                       stageController.pushScene('dashboard');
123 +                               }
124 +                               Mojo.Log.info("$$$$$$$$ AppAssistant doAlarm:calling createStageWithCallback for calendar-dashboard");
125 +                               Mojo.Controller.getAppController().createStageWithCallback({
126 +                                       name: "calendar-dashboard",
127 +                                       lightweight: true,
128 +                                       applicationStylesheets: ["stylesheets/notification.css"],
129 +                               }, pushDashboardScene, "dashboard");
130                         }
131 -                       Mojo.Log.info("$$$$$$$$ AppAssistant doAlarm:calling createStageWithCallback for calendar-dashboard");
132 -                       Mojo.Controller.getAppController().createStageWithCallback({
133 -                               name: "calendar-dashboard",
134 -                               lightweight: true,
135 -                               applicationStylesheets: ["stylesheets/notification.css"],
136 -                       }, pushDashboardScene, "dashboard");
137                 }
138                 Mojo.Log.info("$$$$$$$$ AppAssistant doAlarm :end");
139         },
140 @@ -481,6 +526,83 @@ var AppAssistant = Class.create({
141                 }
142         },
143         
144 +       getUserUberCalGroups: function() {
145 +               // read cookie set variables for all views
146 +               var userCalGrpsCookie = new Mojo.Model.Cookie("ucGroupsCookie");
147 +               var userCalGrps = [];
148 +               if(userCalGrpsCookie) {
149 +                       var calGrps = userCalGrpsCookie.get();
150 +                       if(calGrps) {
151 +                               if(calGrps.usercalgroups && calGrps.usercalgroups.length > 0 ) {
152 +                                       userCalGrps = calGrps.usercalgroups;
153 +                                       if(userCalGrps && userCalGrps.length > 0 &&  userCalGrps[0] && userCalGrps[0].rId !== undefined) {
154 +                                               return userCalGrps;
155 +                                       } else {
156 +                                               userCalGrps = undefined;
157 +                                       }
158 +                               }
159 +                       }
160 +               }
161 +               return userCalGrps;
162 +       },
163 +       
164 +       getUberGroups: function() {
165 +               // read cookie set variables
166 +               var uberGrpsCookie = new Mojo.Model.Cookie("uberGrpsCookie");
167 +               var uberGrps = {};
168 +               if(uberGrpsCookie) {
169 +                       var uberGrps = uberGrpsCookie.get();
170 +                       if(uberGrps && uberGrps.inUse !== undefined ) {
171 +                               return uberGrps;
172 +                       } else { // bad cookie, erased cookie or no defined groups yet: build it.
173 +                               return {inUse: false, rId: ""};
174 +                       }
175 +               } else { //bad cookie, erased cookie or no defined groups yet: build it.
176 +                       return {inUse: false, rId: ""};
177 +               }
178 +       },
179 +       
180 +       setUberGroups: function(rID) {
181 +               //set cookie
182 +               if(rID){
183 +                       var uberGrpsCookie = new Mojo.Model.Cookie("uberGrpsCookie");
184 +                       if(uberGrpsCookie) {
185 +                               uberGrpsCookie.put({inUse: true, rId: rID});
186 +                       }
187 +               } else {
188 +                       var uberGrpsCookie = new Mojo.Model.Cookie("uberGrpsCookie");
189 +                       if(uberGrpsCookie) {
190 +                               uberGrpsCookie.put({inUse: false, rId: ""});
191 +                       }
192 +               }
193 +       },
194 +       
195 +       uberToggleGroupsCmd: function(usingUberGroups, name) {
196 +               // for toggleCmd on cal picker submenu
197 +               if(usingUberGroups === true && name) {
198 +                       return name;
199 +               } else {
200 +                       return getCurrentCal();
201 +               }
202 +       },
203 +       
204 +       getUberOrigExcludes: function() {
205 +               // read the orig excludes cookie
206 +               var uberOrigCookie = new Mojo.Model.Cookie("origExCookie");
207 +               var uberOrigEx = [];
208 +               if(uberOrigCookie) {
209 +                       var uberEx = uberOrigCookie.get();
210 +                       if(uberEx && uberEx.excludes && uberEx.excludes.length > 0) {
211 +                               uberOrigEx = uberEx.excludes;
212 +                               return uberOrigEx;
213 +                       } else { // bad cookie, erased cookie or no defined groups yet: build it.
214 +                               return undefined;
215 +                       }
216 +               } else { //bad cookie, erased cookie or no defined groups yet: build it.
217 +                       return undefined;
218 +               }
219 +       },
220 +
221         launchCalendarScene: function(stageController, showFirstUse) {
222                 // Clear the view stack (just in case the starting scene is up)
223                 stageController.popScenesTo();
224 @@ -488,8 +610,41 @@ var AppAssistant = Class.create({
225                         // If this is the first use of Calendar, show the first use scene
226                         this.firstUseManager = new FirstUseManager(stageController);
227                 } else {
228 +                       this.uberOpenInView = 'last';
229 +                       this.snoozeThrob = false;
230 +                       this.snoozeCookie = new Mojo.Model.Cookie("snoozeCookie");      
231 +                       if (this.snoozeCookie) {
232 +                               var snzcookie = this.snoozeCookie.get();
233 +                               if (snzcookie) {
234 +                                       if(snzcookie.uberopeninview !== undefined) {
235 +                                               this.uberOpenInView = snzcookie.uberopeninview;
236 +                                       } else {
237 +                                               this.uberOpenInView = 'last';
238 +                                       }
239 +                                       if(snzcookie.snoozethrob !== undefined) {
240 +                                               this.snoozeThrob = snzcookie.snoozethrob;
241 +                                       } else {
242 +                                               this.snoozeThrob = false;
243 +                                       }
244 +                               }
245 +                       }
246 +               
247                         // Otherwise show the Day View
248 -                       stageController.pushScene({name: "day", transition: Mojo.Transition.crossFade, disableSceneScroller: true});
249 +                       var view = "day";
250 +                       var cookie = new Mojo.Model.Cookie("BackGesture");
251 +                       try {
252 +                               var lview = cookie.get();
253 +                               if(lview && lview.lastview) {
254 +                                       view = lview.lastview;
255 +                               }
256 +                               if ((lview.lastview != "month") && (lview.lastview != "week")) {
257 +                                       view = "day";
258 +                               }
259 +                       } catch (e) {}
260 +                       if(this.uberOpenInView !== 'last' && this.uberOpenInView !== undefined) {
261 +                               view = this.uberOpenInView;
262 +                       }
263 +                       stageController.pushScene({name: view, transition: Mojo.Transition.crossFade, disableSceneScroller: true});
264                 }
265         },
266         
267 @@ -764,6 +919,29 @@ function getDOWCount(value) {
268         return num;
269  }
270  
271 +function getIsLastProps(value) {
272 +       var monthDays= [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
273 +       var dt = new Date(value);
274 +       var daydt = dt.getDate();
275 +       var yr = dt.getFullYear();
276 +       var mn = dt.getMonth();
277 +       if(isLeapYear(yr)) {
278 +               monthDays[1] = 29;
279 +       } else {
280 +               monthDays[1] = 28;
281 +       }
282 +       var lastdayIdx = (daydt - monthDays[mn] -1).toString();
283 +       if(monthDays[mn] - daydt < 7) {
284 +               if(monthDays[mn] - daydt === 0) {
285 +                       return {lastweek: true, lastday: lastdayIdx, islastday: true };
286 +               } else {
287 +                       return {lastweek: true, lastday: lastdayIdx, islastday: false};
288 +               }
289 +       } else {
290 +               return {lastweek: false, lastday: lastdayIdx, islastday: false};
291 +       }
292 +}
293 +
294  function getAppAssistant() {
295         return Mojo.Controller.getAppController().assistant;
296  }
297 @@ -819,6 +997,30 @@ function buildCalendarsMenu(includeAll, includeReadOnly, includeExcludedFromAll)
298         return getCalendarsManager().buildCalendarsMenu(includeAll, includeReadOnly, includeExcludedFromAll);
299  }
300  
301 +function buildUberExcludes(includes) {
302 +       getCalendarsManager().buildUberExcludes(includes);
303 +}
304 +
305 +function getUserUberCalGroups() {
306 +       return getAppAssistant().getUserUberCalGroups();
307 +}
308 +
309 +function getUberGroups() {
310 +       return getAppAssistant().getUberGroups();
311 +}
312 +
313 +function getUberOrigExcludes() {
314 +       return getAppAssistant().getUberOrigExcludes();
315 +}
316 +
317 +function setUberGroups(rID) {
318 +       getAppAssistant().setUberGroups(rID);
319 +}
320 +
321 +function uberToggleGroupsCmd(usingUberGroups, name) {
322 +       return getAppAssistant().uberToggleGroupsCmd(usingUberGroups, name);
323 +}
324 +
325  // ** CALENDAR PREFS
326  function getPrefsManager() {
327         return getAppAssistant().prefsManager;
328 @@ -863,7 +1065,15 @@ function notifyTimeFormatObservers() {
329  }
330  
331  function getTimeFormat() {
332 -       return getAppAssistant().timeFormat;
333 +       //if getAppAssistant is not valid yet return the default setting of this.timeFormat.
334 +       if(getAppAssistant() != undefined)
335 +       {
336 +               return getAppAssistant().timeFormat;
337 +       }
338 +       else
339 +       {
340 +               return this.timeFormat;
341 +       }
342  }
343  // **System  Time Change
344  function observeTimeChange(sceneName, controller){
345 diff --git a/usr/palm/applications/com.palm.app.calendar/app/controllers/dashboard-assistant.js b/usr/palm/applications/com.palm.app.calendar/app/controllers/dashboard-assistant.js
346 index a667ac9..81ac2a6 100644
347 --- a/usr/palm/applications/com.palm.app.calendar/app/controllers/dashboard-assistant.js
348 +++ b/usr/palm/applications/com.palm.app.calendar/app/controllers/dashboard-assistant.js
349 @@ -14,6 +14,21 @@ var DashboardAssistant = Class.create({
350                 
351                 this.service = getCalendarService();
352                 
353 +               this.snoozeThrob = false;
354 +               
355 +               //get default snooze duration from cookie
356 +               this.snoozeCookie = new Mojo.Model.Cookie("snoozeCookie");
357 +
358 +               if (this.snoozeCookie) {
359 +                       var snzcookie = this.snoozeCookie.get();
360 +                       if (snzcookie) {
361 +                               if(snzcookie.snoozethrob)       {
362 +                                       this.snoozeThrob = snzcookie.snoozethrob;
363 +                               } else {
364 +                                       this.snoozeThrob = false;
365 +                               }
366 +                       }
367 +               }
368                 this.controller.get('calendar-dashboard').addEventListener(Mojo.Event.tap, this.tapHandler.bindAsEventListener(this));
369                 this.controller.get('dashboard-icon').addEventListener(Mojo.Event.tap, this.reminderList.bindAsEventListener(this));
370                 this.controller.get('dashboard-count').addEventListener(Mojo.Event.tap, this.reminderList.bindAsEventListener(this));
371 @@ -24,7 +39,10 @@ var DashboardAssistant = Class.create({
372         cleanup: function() {
373                 Mojo.Log.info("$$$$$$$$ Dashboard-assistant cleanup: start ");
374                 this.reminders.stopObservingReminders('dashboard');
375 -               this.reminders.removeAllReminders();
376 +//Do not remove the scheduled reminders
377 +//This is so that if the dashboard event is swiped away the reminder is not removed
378 +//to support reminders that are far in the future but may not want the icon in the dashboard.
379 +//             this.reminders.removeAllReminders();
380                 Mojo.Log.info("$$$$$$$$ Dashboard-assistant cleanup: end ");
381         },
382         
383 @@ -35,6 +53,7 @@ var DashboardAssistant = Class.create({
384                         Mojo.Log.info("$$$$$$$$ Dashboard-assistant updateMostRecentReminder: recent Reminder is "+this.reminder.id);
385                         this.updateHTML(this.controller.get('dashboard-subject'), (this.reminder.subject != null) ? this.reminder.subject : '');
386                         this.updateHTML(this.controller.get('dashboard-timeloc'), (this.reminder.subtitle != null) ? this.reminder.subtitle : '');
387 +                       if(this.snoozeThrob) {this.controller.stageController.indicateNewContent(true);}
388                 }
389                 else
390                 {
391 diff --git a/usr/palm/applications/com.palm.app.calendar/app/controllers/datetime-assistant.js b/usr/palm/applications/com.palm.app.calendar/app/controllers/datetime-assistant.js
392 index 1bc0374..156342c 100644
393 --- a/usr/palm/applications/com.palm.app.calendar/app/controllers/datetime-assistant.js
394 +++ b/usr/palm/applications/com.palm.app.calendar/app/controllers/datetime-assistant.js
395 @@ -140,10 +140,669 @@ var DatetimeAssistant = Class.create({
396                  break;
397          }
398      },
399 -    
400 +       
401 +       // From monthview (Feb is fixed up by hand as necessary)
402 +       // We try to avoid the DateJS stuff because it's indescribably slow.
403 +       _monthDays: [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ],
404 +       
405 +       rdayNames: function() {
406 +               var stday = 0;
407 +               if(this.startOfWeek==null || this.startOfWeek == 'undefined')
408 +                       this.startOfWeek = 1;
409 +               stday = this.startOfWeek - 1;
410 +               var tday = new Date();
411 +               tday.moveToDayOfWeek(stday);
412 +               for (var i = 0; i < 7; i++) {
413 +                       this._rdNames[i] = Mojo.Format.formatDate(tday, "E");
414 +                       tday.addDays(1);
415 +               }
416 +       },
417 +       
418 +       radvanceWk: function(wk, month, year, maxwkn) {
419 +               var wkn = parseInt(wk, 10);
420 +               if(this.weekModulusNum != undefined && this.weekModulusNum <= 52 && this.weekModulusNum != 1) {
421 +                       var maxwkn = this.weekModulusNum;
422 +               }
423 +               if((wkn > 8) && (wkn < maxwkn)) {
424 +                       return (wkn + 1);
425 +               } else if((wkn <= 8) && (wkn < maxwkn)) {
426 +                       wkn +=1;
427 +                       var zd = '0';
428 +                       return zd + wkn.toString();
429 +               } else if(wkn == maxwkn || wkn > maxwkn) {
430 +                       var zd = '01';
431 +                       return zd;
432 +               }
433 +       },
434 +       
435 +       // draw month function, expects numbers 0 based month
436 +       canvasRM: function(month, year, context) {
437 +               // date object
438 +               var rmon = new Date(year, month, 1);
439 +               
440 +               //setup number of days, 1st day(day of week), week number, number of weeks
441 +               var rd1dayOfMon = rmon.getDay();
442 +               var rwkNum = this.useISOweekNum === true ? rmon.getISO8601Week() : rmon.getWeekOfYear(this.prefStartDoW);
443 +               var maxwkn = this.useISOweekNum === true ? new Date((month != 0 ? year : year -1), 11, 28).getISO8601Week() : new Date((month != 0 ? year : year -1), 11, 28).getWeekOfYear(this.prefStartDoW);
444 +               maxwkn = maxwkn == 0 ? 53 : maxwkn;
445 +               rwkNum = rwkNum == 0 ? maxwkn : rwkNum;
446 +               if(this.weekNumOffset !== undefined && this.weekNumOffset !=0) {
447 +                       var wkNum = parseInt(rwkNum,10) + this.weekNumOffset;
448 +                       rwkNum = wkNum > maxwkn ? (wkNum - maxwkn) : wkNum;
449 +                       rwkNum = rwkNum < 10 ? '0' + rwkNum : rwkNum;
450 +               }
451 +               if(this.weekModulusNum != undefined && this.weekModulusNum <= 52 && this.weekModulusNum != 1) {
452 +                       rwkNum = (parseInt(rwkNum, 10) % this.weekModulusNum);
453 +                       rwkNum = rwkNum !== 0 ? rwkNum : this.weekModulusNum;
454 +                       rwkNum = rwkNum < 10 ? '0' + rwkNum : rwkNum;
455 +               }
456 +               var r1offset = rd1dayOfMon - (this.startOfWeek - 1);
457 +               if (r1offset < 0) {r1offset += 7;}  //num of days of prev mon
458 +               if(isLeapYear(year)) {
459 +                       this._monthDays[1] = 29;
460 +               } else {
461 +                       this._monthDays[1] = 28;
462 +               }
463 +               this.RM[context].maxdays = this._monthDays[month];              
464 +               //setup fonts and spacing
465 +               this.mthctx[context].fillStyle = "rgb(0, 0, 0)";
466 +               this.mthctx[context].font = "bold 14px Prelude";
467 +               this.mthctx[context].textAlign = "left";
468 +               this.mthctx[context].textBaseline = "top";
469 +               var top = 2;
470 +               var leftmargin = 2;
471 +               var left = 0 + leftmargin;
472 +               var txt = "";
473 +               this.colHW = 30;
474 +               var maxW = 30;
475 +               this.topCor = 42 + (this.colHW/2); //top margin + half-cell
476 +               this.leftCor = this.colHW;
477 +               this.RM[context].fstDayLidx = r1offset;
478 +               this.RM[context].fstDayTidx = 1;
479 +               // setup title and week header
480 +               var titleTxt = Mojo.Format.formatDate(rmon, $L("MMM yyyy"));
481 +               this.mthctx[context].strokeText(titleTxt, left + 90, top);
482 +               this.mthctx[context].textAlign = "center";
483 +               for (var i = 0; i < 7; i++) {
484 +                       txt = this._rdNames[i];
485 +                       left = (i * this.colHW) + this.leftCor + 13;//13 is for font &txt to ctr
486 +                       top = 22;
487 +                       this.mthctx[context].strokeText(txt, left, top);        
488 +               }
489 +               this.mthctx[context].fillStyle = "rgb(104, 104, 104)";
490 +               this.mthctx[context].font = "14px Prelude";
491 +               this.mthctx[context].textAlign = "left";
492 +               this.mthctx[context].textBaseline = "alphabetic";
493 +               for (var j = 0; j < 6; j++) {
494 +                       txt = rwkNum;
495 +                       left = leftmargin;
496 +                       top = (j * this.colHW) + this.topCor + 3; // 3 is for font correction
497 +                       this.mthctx[context].strokeText(txt, left, top);
498 +                       rwkNum = this.radvanceWk(rwkNum, month, year, maxwkn);
499 +               }
500 +               //iterate through the date rows
501 +               var num = 1;
502 +               this.mthctx[context].fillStyle = "rgb(0, 0, 0)";
503 +               this.mthctx[context].font = "bold 14px Prelude";
504 +               this.mthctx[context].textAlign = "center";
505 +               for (var j=0; j<6; j++) {
506 +                       if (num > this.RM[context].maxdays) {
507 +                               break; }
508 +                       top = (j * this.colHW) + this.topCor + 3;
509 +                       for (var i=0; i<7; i++) {
510 +                               if (j==0 && i ==0) {i = r1offset;}
511 +                               txt = num;
512 +                               left =  (i * this.colHW) + this.leftCor + 13;
513 +                               this.mthctx[context].strokeText(txt, left, top);
514 +                               num +=1;
515 +                               if (num > this.RM[context].maxdays) {
516 +                                       break; }
517 +                       }
518 +               }
519 +       },
520 +       
521 +       RMnextM: function(index) {
522 +               this.RM[index].month = this.RM[index - 1].month;
523 +               this.RM[index].year = this.RM[index - 1].year;
524 +               if(this.RM[index].month == 11) {
525 +                       this.RM[index].month = 0;
526 +                       this.RM[index].year += 1;
527 +               } else {
528 +                       this.RM[index].month += 1;
529 +               }
530 +       },
531 +       
532 +       RMprevM: function(index) {
533 +               this.RM[index].month = this.RM[index + 1].month;
534 +               this.RM[index].year = this.RM[index + 1].year;
535 +               if(this.RM[index].month == 0) {
536 +                       this.RM[index].month = 11;
537 +                       this.RM[index].year -= 1;
538 +               } else {
539 +                       this.RM[index].month -= 1;
540 +               }
541 +       },
542 +       
543 +       // determin calendar order for the canvas's
544 +       orderRM: function( stDate, eDate, isAllDay) {
545 +               //check first
546 +               if(stDate.getTime() > eDate.getTime) {
547 +                       Mojo.Log.error ("start after end");
548 +                       return;
549 +               }
550 +               for(var i=0; i<6; i++) {
551 +                       this.RM[i] = {};
552 +                       this.RM[i].month = "";
553 +                       this.RM[i].year = "";
554 +                       this.RM[i].fstDayLidx = 1;
555 +                       this.RM[i].fstDayTidx = 1;
556 +                       this.RM[i].maxdays = 1;
557 +               }
558 +               // date objects
559 +               var curD = new Date();
560 +               var curMY = {month: curD.getMonth(), year: curD.getFullYear() };
561 +               var stMY = {month: stDate.getMonth(), year: stDate.getFullYear() };
562 +               var eMY = {month: eDate.getMonth(), year: eDate.getFullYear() };
563 +               this.RMlast.duration = getTimePeriodParts(stDate, eDate, isAllDay);
564 +               var rwhen = {};
565 +               rwhen = getTimePeriodParts(curD, stDate, isAllDay);
566 +               var dura = this.RMlast.duration;
567 +               // determine duration case
568 +               if ( (dura.years == 0) && (((dura.months == 5) && (dura.days == 0)) || (dura.months < 5)) ) {
569 +                       if ( (dura.months <=1) && ((rwhen.months <= 3) && (rwhen.years <=0)) ){
570 +                               // we can fit in 6 months try to get today in the 6 months
571 +                               if(curD.getTime() < stDate.getTime()) {
572 +                                       //close future start with curDate 
573 +                                       this.redlineSplit.setStyle({borderRight: '1px solid black'});
574 +                                       this.RM[0].month = curMY.month;
575 +                                       this.RM[0].year = curMY.year;
576 +                                       for (var i = 1; i < 6; i++) {
577 +                                               this.RMnextM(i);
578 +                                       }
579 +                               } else {
580 +                                       // in close past start with stDate
581 +                                       this.redlineSplit.setStyle({borderRight: '1px solid black'});
582 +                                       this.RM[0].month = stMY.month;
583 +                                       this.RM[0].year = stMY.year;
584 +                                       for (var i = 1; i < 6; i++) {
585 +                                               this.RMnextM(i);
586 +                                       }
587 +                               }
588 +                       } else {
589 +                               if((curD.getTime() < stDate.getTime()) && (((dura.months == 4) && (dura.days == 0) && (dura.years ==0)) || ((dura.months <4) && (dura.years==0)))){
590 +                                       // in 6 months, too far away for today, in future do prev 
591 +                                       this.redlineSplit.setStyle({borderRight: '1px solid black'});
592 +                                       this.RM[1].month = stMY.month;
593 +                                       this.RM[1].year = stMY.year;
594 +                                       this.RMprevM(0);
595 +                                       this.RMnextM(2);
596 +                                       this.RMnextM(3);
597 +                                       this.RMnextM(4);
598 +                                       this.RMnextM(5);
599 +                               } else {
600 +                                       // in past or could be 6 cal months do start + 5
601 +                                       this.redlineSplit.setStyle({borderRight: '1px solid black'});
602 +                                       this.RM[0].month = stMY.month;
603 +                                       this.RM[0].year = stMY.year;
604 +                                       for (var i = 1; i < 6; i++) {
605 +                                               this.RMnextM(i);
606 +                                       }
607 +                               }
608 +                       }
609 +               } else { //duration won't fit in 6 months
610 +                       if( ((stMY.year == curMY.year) && (stMY.month == curMY.month)) ||
611 +                         ((stMY.year < curMY.year) ||  ((stMY.year == curMY.year) && (stMY.month < curMY.month))) ){
612 +                       //past or present month - do start + next + next redline split then -- prev + end + next
613 +                               this.redlineSplit.setStyle({borderRight: '2px solid red'});
614 +                               this.RM[0].month = stMY.month;
615 +                               this.RM[0].year = stMY.year;
616 +                               this.RMnextM(1);
617 +                               this.RMnextM(2);
618 +                               this.RM[4].month = eMY.month;
619 +                               this.RM[4].year = eMY.year;
620 +                               this.RMprevM(3);
621 +                               this.RMnextM(5);
622 +                       } else if((stMY.year > curMY.year) ||  ((stMY.year == curMY.year) && (stMY.month > curMY.month))) {
623 +                       // future - do prev + start + next redline split prev + end + next
624 +                               this.redlineSplit.setStyle({borderRight: '2px solid red'});
625 +                               this.RM[1].month = stMY.month;
626 +                               this.RM[1].year = stMY.year;
627 +                               this.RMprevM(0);
628 +                               this.RMnextM(2);
629 +                               this.RM[4].month = eMY.month;
630 +                               this.RM[4].year = eMY.year;
631 +                               this.RMprevM(3);
632 +                               this.RMnextM(5);
633 +                       }
634 +               }       
635 +               // call canvasRM
636 +               for(var k=0; k<6; k++){
637 +                       this.canvasRM(this.RM[k].month, this.RM[k].year, k);
638 +               }
639 +
640 +               // record for next time comparisons
641 +               this.RMlast.stMY = stMY;
642 +               this.RMlast.eMY = eMY;
643 +               this.RMlast.curMY = curMY;
644 +       },
645 +       
646 +       risRendered: function( year, month) {
647 +               for(var i=0; i<6; i++) {
648 +                       if((this.RM[i].month == month) && (this.RM[i].year == year)) {
649 +                               return i;
650 +                       }
651 +               }
652 +               return -1;
653 +       },
654 +       
655 +       //mark days in calendar
656 +       markDay: function(rdate, imgsrc, color, rx, ry, rwt, rht) {
657 +               // determine which month, year, date
658 +               if (rdate instanceof Date == true) { 
659 +                       var whatMn = rdate.getMonth();
660 +                       var whatYr = rdate.getFullYear();
661 +                       var whatDt = rdate.getDate();
662 +               } else if(rdate !== undefined) {
663 +                       this.rtdate = new Date(rdate);
664 +                       var whatMn = this.rtdate.getMonth();
665 +                       var whatYr = this.rtdate.getFullYear();
666 +                       var whatDt = this.rtdate.getDate();
667 +               }
668 +               var rmimgsrc = imgsrc;
669 +               var idx = this.risRendered(whatYr, whatMn);
670 +               if(idx == -1) { return; }
671 +               var fstDayLidx = this.RM[idx].fstDayLidx;
672 +               var fstDayTidx = this.RM[idx].fstDayTidx;
673 +               var rRow = Math.floor((whatDt + fstDayLidx -1) / 7);
674 +               var col = (whatDt + fstDayLidx - 1) % 7;
675 +               var itop = (rRow * this.colHW) + 40;
676 +               var ileft = (col * this.colHW) + this.colHW;
677 +               itop = (ry !== undefined) ? itop + ry : itop;
678 +               ileft = (rx !== undefined) ? ileft + rx : ileft;
679 +               if (rmimgsrc !== undefined) {
680 +                       this.mthctx[idx].drawImage(rmimgsrc, ileft, itop, (rwt !== undefined)? rwt : this.colHW,(rht !== undefined)? rht : this.colHW);
681 +               } else if(color !== undefined) {
682 +                       this.mthctx[idx].fillStyle = color;
683 +                       this.mthctx[idx].fillRect(ileft, itop, this.colHW-2, this.colHW-2);
684 +               } else {
685 +                       this.mthctx[idx].fillStyle = "rgba(232,227,124,0.5)";
686 +                       this.mthctx[idx].fillRect(ileft, itop, this.colHW-2, this.colHW-2);
687 +               }
688 +       },
689 +       
690 +       rmMarkD: function() {
691 +               if(this.RMlast.duration.months > 7) {
692 +                       return;
693 +               }
694 +               if((this.RMlast.stMY.month == this.RMlast.eMY.month) && (this.RMlast.stD.getDate() == this.RMlast.eD.getDate())) {
695 +                       this.RMlast.HMDB = 1;
696 +                       return;
697 +               }
698 +               var stTS = new Date(this.RMlast.stMY.year, this.RMlast.stMY.month, this.RMlast.stD.getDate(), 12).getTime();
699 +               var daylen = 3600000*24;
700 +               var end = howManyDaysBetween(this.RMlast.stD, this.RMlast.eD) +1;
701 +               this.RMlast.HMDB = end;
702 +               this.RMlast.stTS = stTS;
703 +               for (var z = 0; z < end; z++) {
704 +                       this.markDay(stTS + (z*daylen),
705 +                                                       this.dImg, 
706 +                                                       null/*color*/,
707 +                                                       null/*x adjust*/,
708 +                                                       this.colHW-2/*y adjust*/ ,
709 +                                                       this.colHW/*wd adjust*/,
710 +                                                       2 /*ht adjust*/)
711 +               }
712 +       },
713 +       
714 +       rmRecur: function() {
715 +               // this function is after it is a known recurrent model
716 +               // time of when -- occuring each
717 +               var rcfrequency = this.targetEvent.rruleModel.frequency;
718 +               var rccount = this.targetEvent.rruleModel.count;
719 +               // this is week day names array
720 +               var rcbyday =  this.targetEvent.rruleModel.byday;
721 +               // this is the date of the month
722 +               var rcbymonthday = this.targetEvent.rruleModel.bymonthday;
723 +               // end day
724 +               var rcuntil = this.targetEvent.rruleModel.until;
725 +               // howmany times between
726 +               var rcint = this.targetEvent.rruleModel.interval;
727 +               // take stTS and duradays to create the base event from the curent event
728 +               var rcduraD = this.RMlast.HMDB;
729 +               var rcstTS = this.targetEvent.startTimestamp;
730 +               var rcstDy = new Date(rcstTS);
731 +               var rcstD = new Date(Date.UTC(rcstDy.getFullYear(), rcstDy.getMonth(), rcstDy.getDate(), 12));
732 +               rcstTS = rcstD.getTime();
733 +               var stDoW = rcstD.getDay();
734 +               var dlen = 3600000*24;
735 +               var rcdaysofwk = [];
736 +               this.recTS = []; // array of timestamps of the recurring evt
737 +               switch (rcfrequency) {
738 +                               case 'DAILY':
739 +                                       var recfreqTS = dlen;
740 +                                       break;
741 +                               case 'WEEKLY':
742 +                                       var recfreqTS = dlen * 7;
743 +                                       break;
744 +                               case 'MONTHLY':
745 +                                       var recfreqTS = -1;
746 +                                       break;
747 +                               case 'YEARLY':
748 +                                       var recfreqTS = -1;
749 +                                       break;
750 +               }
751 +
752 +               if(rcuntil !== "" && rcuntil !== undefined) {
753 +                       // until is in UTC jan = 1, need local for cal
754 +                       var rcyear = rcuntil.substring(0,4);
755 +                       var rcmon = parseInt(rcuntil.substring(4,6), 10) -1;
756 +                       var rcday = parseInt(rcuntil.substring(6,8), 10);
757 +                       var rchour = parseInt(rcuntil.substring(9,11), 10);
758 +                       var rcmin = parseInt(rcuntil.substring(11, 13), 10);
759 +                       this.RMlast.recD = new Date(Date.UTC(rcyear, rcmon, rcday, rchour, rcmin));
760 +               } else if(this.targetEvent.isRecurringForever) {
761 +                       if(rcfrequency == "DAILY" || recfreqTS == -1) {
762 +                       // go out 6 months
763 +                               this.RMlast.recD = new Date(this.RMlast.eMY.month + 6 > 11 ? this.RMlast.eMY.year + 1 : this.RMlast.eMY.year, this.RMlast.eMY.month + 6 > 11 ? this.RMlast.eMY.month - 6 : this.RMlast.eMY.month + 6, this.RMlast.eD.getDate());
764 +                       } else {        // go out 1 year from the end date
765 +                               this.RMlast.recD = new Date(this.RMlast.eMY.year + 1, this.RMlast.eMY.month, this.RMlast.eD.getDate());
766 +                       }
767 +               } else if((rccount !== -1) && (recfreqTS !== -1)) { //until set outside of webos excludes yearly & monthly
768 +                       this.RMlast.recD = new Date(rcstTS + (recfreqTS*rcint*rccount));
769 +               }
770 +               this.RMlast.recD.setUTCHours(12); // set end to noon UTC to match start, UTC get's the right day
771 +               var recHMDB = howManyDaysBetween(rcstD, this.RMlast.recD) +1;
772 +               // detect recurr model
773 +               switch (rcfrequency) {
774 +                       case 'DAILY' : // Do Not Localize
775 +                               // get how many intervals
776 +                               var rcdays = 1 + Math.floor((recHMDB*dlen) / (recfreqTS*rcint));
777 +                               for(var k=0; k < rcdays; k++) { // cycle through intervals
778 +                                       this.recTS.push((dlen*k*rcint) + rcstTS);       
779 +                               }
780 +                               while(this.recTS[this.recTS.length -1] > this.RMlast.recD.getTime()){
781 +                                       this.recTS.pop();
782 +                               }
783 +                               break;
784 +                               
785 +            case 'WEEKLY': // Do NOT Localize
786 +                               // find the day numbers from their names
787 +                               var rci = this.targetEvent.rruleModel.byday.length;
788 +                               var rcSundayTS = rcstTS - (stDoW*dlen); 
789 +                               for(var i=0; i < rci; i++) {
790 +                                       rcdaysofwk[i] = this.recurrenceRule.dayMap.indexOf(rcbyday[i]);
791 +                               }
792 +                               if(rci > 1) {
793 +                               // get start day dow because it has to be in rcdaysofwk
794 +                                       var rcpos = rcdaysofwk.indexOf(stDoW);
795 +                                       //need to get to the last of the array before start of next week
796 +                                       if(rcpos !== rci - 1){
797 +                                               for(var i = rcpos; i <= rci; i++) {
798 +                                                       for(var j = 0; j < rcduraD; j++) {
799 +                                                       // array's TS = duration days *milliseconds in a day + (sundays TS + day of week adjustment) 
800 +                                                       this.recTS.push((dlen*j) + (rcSundayTS + dlen*rcdaysofwk[i]));  
801 +                                                       }
802 +                                               }
803 +                                       }
804 +                               }
805 +                               //should be at the first day of the week after start day's week
806 +                               // need to get how many intervals until GetHowManyDays / 7*interval
807 +                               var rcwks = 1 + Math.floor((recHMDB*dlen) / (recfreqTS*rcint)); 
808 +                               for(var k=1; k <= rcwks; k++) { // cycle through intervals
809 +                                       var rcwkSunTS = rcSundayTS + (rcint * recfreqTS * k);
810 +                                       for(var i = 0; i < rci; i++) { // cycle through days of week
811 +                                               for(var j = 0; j < rcduraD; j++) { //cycle duration
812 +                                               this.recTS.push((dlen*j) + (rcwkSunTS + dlen*rcdaysofwk[i]));   
813 +                                               }
814 +                                       }
815 +                               }
816 +                               while(this.recTS[this.recTS.length -1] > this.RMlast.recD.getTime()){
817 +                                       this.recTS.pop();
818 +                               }
819 +               break;
820 +                
821 +            case 'MONTHLY': // Do NOT Localize
822 +                //Monthly by date
823 +                               var rcmonths = 1 + Math.floor(howManyMonthsBetween(rcstD ,this.RMlast.recD)/rcint);
824 +                if (this.targetEvent.rruleModel.bymonthday.length > 0) {
825 +                                       var rcmonthday = parseInt(this.targetEvent.rruleModel.bymonthday[0], 10);
826 +                                       if(rcmonthday > 0) {
827 +                                               var rcstmon = rcstD.getMonth();
828 +                                               var rcstyear = rcstD.getFullYear();
829 +                                               for(var i=0; i<rcmonths; i++) { //cycle through intervals
830 +                                                       var rcmon = (rcstmon + (i*rcint)) > 11 ? rcstmon + (i*rcint) - 12 : rcstmon + (i*rcint);
831 +                                                       var rcyear = (rcstmon + (i*rcint)) > 11 ? rcstyear + 1 : rcstyear; 
832 +                                                       var rcmonTS = Date.UTC(rcyear, rcmon, rcmonthday, 12);
833 +                                                       var rcmonChk = new Date(rcmonTS);
834 +                                                       if(rcmonChk.getMonth() === rcmon) { // test valid date in the month
835 +                                                               for(var j=0; j<rcduraD; j++) { // cycle through duration
836 +                                                                       this.recTS.push(rcmonTS + (j*dlen));
837 +                                                               }
838 +                                                       }
839 +                                               }
840 +                                       } else if(rcmonthday < 0) {
841 +                                               var rcstmon = rcstD.getMonth();
842 +                                               var rcstyear = rcstD.getFullYear();
843 +                                               for(var i=0; i<rcmonths; i++) { //cycle through intervals
844 +                                                       var rcmon = (rcstmon + (i*rcint)) > 11 ? rcstmon + (i*rcint) - 12 : rcstmon + (i*rcint);
845 +                                                       var rcmonLast = (rcstmon + 1 + (i*rcint)) > 11 ? rcstmon +1 + (i*rcint) - 12 : rcstmon + 1 +(i*rcint);
846 +                                                       var rcyear = (rcstmon + 1 + (i*rcint)) > 11 ? rcstyear + 1 : rcstyear; 
847 +                                                       var rcmonTS = Date.UTC(rcyear, rcmonLast, 1, 12) + rcmonthday*dlen;
848 +                                                       var rcmonChk = new Date(rcmonTS);
849 +                                                       if(rcmonChk.getMonth() === rcmon) { // test valid date in the month
850 +                                                               for(var j=0; j<rcduraD; j++) { // cycle through duration
851 +                                                                       this.recTS.push(rcmonTS + (j*dlen));
852 +                                                               }
853 +                                                       }
854 +                                               }
855 +                                       }
856 +                               } else {
857 +                                       // check for multiple by days and last week type set
858 +                                       var byDayLen = this.targetEvent.rruleModel.byday.length;
859 +                                       var byDayDefault = true;
860 +                                       if(byDayLen && byDayLen > 1) {
861 +                                               var byDayArray = [];
862 +                                               var ford = parseInt(this.targetEvent.rruleModel.byday[0], 10);
863 +                                               for(var i=0; i<byDayLen; i++) {
864 +                                                       var ord = parseInt(this.targetEvent.rruleModel.byday[i], 10);
865 +                                                       if(ord && ord !== ford) {//we only care about matching bysetpos type repeat
866 +                                                               byDayDefault = true; //default to just using first byday
867 +                                                               break; //cal doesn't support multiple pos days in monthly repeat 
868 +                                                       } else if(ord && ord === ford) {
869 +                                                               var DoW = this.recurrenceRule.dayMap.indexOf(this.targetEvent.rruleModel.byday[i].substring((ford<0?2:1)));
870 +                                                               if(byDayArray.indexOf(DoW) === -1) {//not in previously
871 +                                                                       byDayArray.push(DoW);
872 +                                                               }
873 +                                                               byDayDefault = false;
874 +                                                       }
875 +                                               } //should have an array with the last days wanted
876 +                                               if(!byDayDefault && byDayArray.length > 1) {
877 +                                                       if(ford<0){
878 +                                                               var rcmonthday = -1;
879 +                                                       } else if(ford>0) {
880 +                                                               var rcmonthday = 1;
881 +                                                       }
882 +                                                       var rcstmon = rcstD.getMonth();
883 +                                                       var rcstyear = rcstD.getFullYear();
884 +                                                       for(var i=0; i<rcmonths; i++) { //cycle through intervals
885 +                                                               var rcmon = (rcstmon + (i*rcint)) > 11 ? rcstmon + (i*rcint) - 12 : rcstmon + (i*rcint);
886 +                                                               if(ford<0){
887 +                                                                       var rcmonLast = (rcstmon + 1 + (i*rcint)) > 11 ? rcstmon +1 + (i*rcint) - 12 : rcstmon + 1 +(i*rcint);
888 +                                                                       var rcyear = (rcstmon + 1 + (i*rcint)) > 11 ? rcstyear + 1 : rcstyear; 
889 +                                                                       var rcmonTS = new Date(rcyear, rcmonLast, 1, 12).getTime() + rcmonthday*dlen;
890 +                                                               } else if(ford>0){
891 +                                                                       var rcmonLast = (rcstmon + (i*rcint)) > 11 ? rcstmon + (i*rcint) - 12 : rcstmon +(i*rcint);
892 +                                                                       var rcyear = (rcstmon + (i*rcint)) > 11 ? rcstyear + 1 : rcstyear; 
893 +                                                                       var rcmonTS = new Date(rcyear, rcmonLast, 1, 12).getTime();
894 +                                                               }
895 +                                                               var rcDoW = new Date(rcmonTS).getDay();
896 +                                                               for(var k=0; k< Math.abs(ford); k++) {
897 +                                                                       while(byDayArray.indexOf(rcDoW) === -1) {
898 +                                                                               rcmonTS = rcmonTS + rcmonthday*dlen;
899 +                                                                               rcDoW = new Date(rcmonTS).getDay();
900 +                                                                       }
901 +                                                                       if(k !== Math.abs(ford) - 1){
902 +                                                                               rcmonTS = rcmonTS + rcmonthday*dlen;
903 +                                                                               var rcDoW = new Date(rcmonTS).getDay();
904 +                                                                       }
905 +                                                               }
906 +                                                               var rcmonChk = new Date(rcmonTS);
907 +                                                               if(rcmonChk.getMonth() === rcmon) { // test valid date in the month
908 +                                                                       for(var j=0; j<rcduraD; j++) { // cycle through duration
909 +                                                                               this.recTS.push(rcmonTS + (j*dlen));
910 +                                                                       }
911 +                                                               }
912 +                                                       }
913 +                                               } else {
914 +                                                       byDayDefault = true; // just one byday
915 +                                               }
916 +                                       } else if(byDayLen === 1 || byDayDefault) {
917 +                                               var ucoldByDay = parseInt(this.targetEvent.rruleModel.byday[0], 10);
918 +                                               if(ucoldByDay && ucoldByDay > 0) {
919 +                                                       var nth = getDOWCount(this.targetEvent.startTimestamp);
920 +                                                       var rcmonths = 1 + Math.floor(howManyMonthsBetween(rcstD ,this.RMlast.recD)/rcint);
921 +                                                       var rcstmon = rcstD.getMonth();
922 +                                                       var rcstyear = rcstD.getFullYear();
923 +                                                       var rcwantday = rcstD.getDay();
924 +                                                       for(var i=0; i<rcmonths; i++) { // cycle through intervals
925 +                                                               var rcmon = (rcstmon + (i*rcint)) > 11 ? rcstmon + (i*rcint) - 12 : rcstmon + (i*rcint);
926 +                                                               var rcyear = (rcstmon + (i*rcint)) > 11 ? rcstyear + 1 : rcstyear;
927 +                                                               var rcmonD = new Date(Date.UTC(rcyear, rcmon, 1, 12));
928 +                                                               var rcfstday = rcmonD.getDay();
929 +                                                               var rcaddTS = ((rcwantday - rcfstday) < 0) ? ((rcwantday - rcfstday) + 7)*dlen : (rcwantday - rcfstday)*dlen;
930 +                                                               var rcmonTS = rcmonD.getTime() + rcaddTS + 7*dlen*(nth-1);
931 +                                                               var rcmonChk = new Date(rcmonTS);
932 +                                                               if(rcmonChk.getMonth() === rcmon) { // test valid date in the month
933 +                                                                       for(var j=0; j<rcduraD; j++) { // cycle through duration
934 +                                                                               this.recTS.push(rcmonTS + (j*dlen));
935 +                                                                       }
936 +                                                               }
937 +                                                       }
938 +                                               } else if(ucoldByDay && ucoldByDay <0) {
939 +                                                       var nth = ucoldByDay;
940 +                                                       var rcmonths = 1 + Math.floor(howManyMonthsBetween(rcstD ,this.RMlast.recD)/rcint);
941 +                                                       var rcstmon = rcstD.getMonth();
942 +                                                       var rcstyear = rcstD.getFullYear();
943 +                                                       var rcwantday = rcstD.getDay();
944 +                                                       for(var i=0; i<rcmonths; i++) { // cycle through intervals
945 +                                                               var rcmon = (rcstmon + (i*rcint)) > 11 ? rcstmon + (i*rcint) - 12 : rcstmon + (i*rcint);
946 +                                                               var rcmonLast = (rcstmon + 1 + (i*rcint)) > 11 ? rcstmon +1 + (i*rcint) - 12 : rcstmon + 1 +(i*rcint);
947 +                                                               var rcyear = (rcstmon + 1 + (i*rcint)) > 11 ? rcstyear + 1 : rcstyear; 
948 +                                                               var rcmonD = new Date(Date.UTC(rcyear, rcmonLast, 1, 12) - dlen);
949 +                                                               var rcLstday = rcmonD.getDay();
950 +                                                               var rcaddTS = ((rcwantday - rcLstday) > 0) ? ((rcwantday - rcLstday) - 7)*dlen : (rcwantday - rcLstday)*dlen;
951 +                                                               var rcmonTS = rcmonD.getTime() + rcaddTS + 7*dlen*(nth+1);
952 +                                                               var rcmonChk = new Date(rcmonTS);
953 +                                                               if(rcmonChk.getMonth() === rcmon) { // test valid date in the month
954 +                                                                       for(var j=0; j<rcduraD; j++) { // cycle through duration
955 +                                                                               this.recTS.push(rcmonTS + (j*dlen));
956 +                                                                       }
957 +                                                               }
958 +                                                       }
959 +                                               }
960 +                                       }
961 +                               }
962 +                               while(this.recTS[this.recTS.length -1] > this.RMlast.recD.getTime()){
963 +                                       this.recTS.pop();
964 +                               }
965 +                               break;
966 +                               
967 +                       default:                
968 +                               break;
969 +               }
970 +               // pull out the exceptions
971 +               if(this.targetEvent.exdates !== undefined) {
972 +                       if(this.targetEvent.exdates !== "") {
973 +                               var rcexTS = [];
974 +                               var rcexstr = this.targetEvent.exdates.split("\r\n");
975 +                               for(var i=0; i<rcexstr.length; i++){
976 +                                       var idx = rcexstr[i].indexOf(":");
977 +                                       if(idx !== -1) {
978 +                                               rcexstr[i] = rcexstr[i].substring(idx +1);
979 +                                       }
980 +                               }
981 +                               for(var j=0; j<rcexstr.length; j++) {
982 +                                       var rcyear = rcexstr[j].substring(0,4);
983 +                                       var rcmon = parseInt(rcexstr[j].substring(4,6), 10) -1;
984 +                                       var rcday = parseInt(rcexstr[j].substring(6,8), 10);
985 +                                       rcexTS[j] = Date.UTC(rcyear, rcmon, rcday, 12);
986 +                               }
987 +                               // pull exdates out of array
988 +                               for(var k=0; k<rcexTS.length; k++) {
989 +                                       var idx = this.recTS.indexOf(rcexTS[k]);
990 +                                       if(idx !== -1) {
991 +                                               this.recTS.splice(idx,1);
992 +                                       }
993 +                               }
994 +                       }
995 +               }
996 +               // mark the recurrence days
997 +               var rcstop = this.recTS.length;
998 +               for(var k=0; k<rcstop; k++){
999 +                       this.markDay(this.recTS[k],
1000 +                                                       this.rImg, 
1001 +                                                       null/*color*/,
1002 +                                                       null/*x adjust*/,
1003 +                                                       this.colHW-2/*y adjust*/ ,
1004 +                                                       this.colHW/*wd adjust*/,
1005 +                                                       2 /*ht adjust*/)
1006 +               }
1007 +               
1008 +       },
1009 +       
1010 +       rmEval: function() {
1011 +               if(this.targetModifiedTime) {                   
1012 +                       this.RMlast.stD = new Date(this.targetModifiedTime.start);
1013 +                       this.RMlast.eD = new Date(this.targetModifiedTime.end);
1014 +               } else {
1015 +                       this.RMlast.stD = new Date(this.targetEvent.startTimestamp);
1016 +                       this.RMlast.eD = new Date(this.targetEvent.endTimestamp);
1017 +               }
1018 +               if(this.targetEvent.rruleModel) {
1019 +                       
1020 +                       this.rmdoRec = true;
1021 +                       return;
1022 +               }
1023 +       },
1024 +       
1025      setup: function(){
1026          //Mojo.Log.info("datetime-assistant:setup");
1027 -        
1028 +        this.weekModulusNum = 1;
1029 +               this.weekNumOffset = 0;
1030 +               this.useISOweekNum = false;
1031 +               this.uberMinuteInterval = 5;
1032 +               this.prefStartDoW = 0;
1033 +               this.weekCookie = new Mojo.Model.Cookie('WeekViewEnhanced');
1034 +               if (this.weekCookie) {
1035 +                       var weekcookie = this.weekCookie.get();
1036 +                       if(weekcookie) {
1037 +                               if(weekcookie.weeknumoffset !== undefined) {
1038 +                                               this.weekNumOffset = parseInt(weekcookie.weeknumoffset, 10);
1039 +                               } else {
1040 +                                               this.weekNumOffset = 0;
1041 +                               }
1042 +                               if(weekcookie.weekmodulusnum !== undefined) {
1043 +                                               this.weekModulusNum = parseInt(weekcookie.weekmodulusnum, 10);
1044 +                               } else {
1045 +                                               this.weekModulusNum = 1;
1046 +                               }
1047 +                               if (weekcookie.useisoweeknum !== undefined) {
1048 +                                       this.useISOweekNum = weekcookie.useisoweeknum;
1049 +                               } else {
1050 +                                       this.useISOweekNum = false;
1051 +                               }
1052 +                               if (weekcookie.prefsstartofweek !== undefined) {
1053 +                                       this.prefStartDoW = parseInt(weekcookie.prefsstartofweek, 10) -1;
1054 +                               } else {
1055 +                                       this.prefStartDoW = 0;
1056 +                               }
1057 +                               if (weekcookie.uberminuteinterval !== undefined) {
1058 +                                       this.uberMinuteInterval = parseInt(weekcookie.uberminuteinterval, 10);
1059 +                               } else {
1060 +                                       this.uberMinuteInterval = 5;
1061 +                               }
1062 +                       }
1063 +               }
1064                 this.appMenuModel= { visible:true, 
1065              label: $L('Calendar'),
1066                                                         items: [ Mojo.Menu.editItem,
1067 @@ -168,26 +827,59 @@ var DatetimeAssistant = Class.create({
1068          this.startDateModel = {
1069              date: new Date(this.targetModifiedTime.start)
1070          };
1071 +         var startDiv = this.controller.get("edit_startDate").parentNode.parentNode;
1072 +        startDiv.style.paddingTop = "0px";
1073 +        //startDiv.style.marginTop = "-20px";
1074 +        startDiv.removeChild(startDiv.firstChild);
1075 +        startDiv.innerHTML = '<table width="100%"><tr><td width="10%"><div x-mojo-element="Button" id="popCanvasBtn2" class="popCanvas"></div></td><td width="90%"><div class="title datetime-picker"><div id="edit_startDate" x-mojo-element="DatePicker"></div></div></td></tr></table>';
1076 +
1077 +        var endDiv = this.controller.get("edit_endDate").parentNode.parentNode;
1078 +        endDiv.style.paddingTop = "0px";
1079 +        //endDiv.style.marginTop = "-20px";
1080 +        endDiv.removeChild(endDiv.firstChild);
1081 +        endDiv.innerHTML = '<table width="100%"><tr><td width="10%"><div x-mojo-element="Button" id="popCanvasBtn" class="popCanvas"></div></td><td width="90%"><div class="title datetime-picker"><div id="edit_endDate" x-mojo-element="DatePicker"></div></div></td></tr></table>';
1082 +               var startdatePalmListDiv = this.controller.get("start_date_row").parentNode;
1083 +        var parentDiv = this.controller.get("datetime_view");
1084 +        var newDiv = this.controller.document.createElement("div");
1085 +        newDiv.setAttribute("id", "lDrawer");
1086 +        newDiv.setAttribute("x-mojo-element", "Drawer");
1087 +        newDiv.setAttribute("class", "drawerClass");
1088 +        newDiv.setAttribute("name", "DPmonth_view");
1089 +        newDiv.innerHTML = '<div id="DPscrol" x-mojo-element="Scroller"><div id="DPscrolct">' +
1090 +                               '<div id="DPmonth_0" class="DPmv">' +
1091 +                               '<canvas id="left0" width="240" height="220" left="0"></canvas>' +
1092 +                               '</div><div id="DPmonth_1" class="DPmv">' +
1093 +                               '<canvas id="left1" width="240" height="220"></canvas>' +
1094 +                               '</div><div id="DPmonth_2" class="DPmv">' +
1095 +                               '<canvas id="left2" width="240" height="220"></canvas>' +
1096 +                               '</div><div id="DPmonth_3" class="DPmv">' +
1097 +                               '<canvas id="right0" width="240" height="220"></canvas>' +
1098 +                               '</div><div id="DPmonth_4" class="DPmv">' +
1099 +                               '<canvas id="right1" width="240" height="220"></canvas>' +
1100 +                               '</div><div id="DPmonth_5" class="DPmv">' +
1101 +                               '<canvas id="right2" width="280" height="220"></canvas></div></div></div>';
1102 +        parentDiv.insertBefore(newDiv, startdatePalmListDiv.nextSibling);
1103          
1104 -       this.controller.setupWidget('edit_startDate',{label: $L('Date'),modelProperty:'date'}, this.startDateModel);
1105 +               
1106 +       this.controller.setupWidget('edit_startDate',{label: ' ',modelProperty:'date'}, this.startDateModel);
1107          this.controller.listen('edit_startDate', Mojo.Event.propertyChange, this.startDateCallback.bindAsEventListener(this));
1108          
1109          this.endDateModel = {
1110              date: new Date(this.targetModifiedTime.end)
1111          };
1112 -    this.controller.setupWidget('edit_endDate', {label: $L('Date'),modelProperty:'date'}, this.endDateModel);
1113 +    this.controller.setupWidget('edit_endDate', {label: ' ',modelProperty:'date'}, this.endDateModel);
1114          this.controller.listen('edit_endDate', Mojo.Event.propertyChange, this.endDateCallback.bindAsEventListener(this));
1115          
1116          this.startTimeModel = {
1117              time: new Date(this.targetModifiedTime.start)
1118          };
1119 -    this.controller.setupWidget('edit_startTime', {label: $L('Time'),modelProperty:'time'}, this.startTimeModel);
1120 +    this.controller.setupWidget('edit_startTime', {label: $L('Time'),modelProperty:'time', minuteInterval:this.uberMinuteInterval}, this.startTimeModel);
1121          this.controller.listen('edit_startTime', Mojo.Event.propertyChange, this.startTimeCallback.bindAsEventListener(this));
1122          
1123          this.endTimeModel = {
1124              time: new Date(this.targetModifiedTime.end)
1125          };
1126 -    this.controller.setupWidget('edit_endTime', {label: $L('Time'), modelProperty:'time'}, this.endTimeModel);
1127 +    this.controller.setupWidget('edit_endTime', {label: $L('Time'), modelProperty:'time', minuteInterval:this.uberMinuteInterval}, this.endTimeModel);
1128          this.controller.listen('edit_endTime', Mojo.Event.propertyChange, this.endTimeCallback.bindAsEventListener(this));
1129          
1130          
1131 @@ -204,10 +896,133 @@ var DatetimeAssistant = Class.create({
1132          this.controller.setupWidget('dtl_allday_cb', this.allDayCheckboxAttribute, this.allDayCheckboxModel);
1133          
1134          this.updateTimedAllDay(false);
1135 -        
1136 -        
1137 -    },
1138 +               // button setup
1139 +               this.controller.setupWidget("popCanvasBtn",
1140 +                       {},
1141 +                       {
1142 +                               label : "",
1143 +                               disabled: false
1144 +                       }
1145 +               );
1146 +               this.popCanvasBtn = this.controller.get('popCanvasBtn');
1147 +               this.controller.setupWidget("popCanvasBtn2",
1148 +                       {},
1149 +                       {
1150 +                               label : "",
1151 +                               disabled: false
1152 +                       }
1153 +               );
1154 +               this.canvasBtnHandler = this.DPtoggleDrawer.bind(this);
1155 +               this.popCanvasBtn2 = this.controller.get('popCanvasBtn2');
1156 +               Mojo.Event.listen(this.popCanvasBtn, Mojo.Event.tap, this.canvasBtnHandler);
1157 +               Mojo.Event.listen(this.popCanvasBtn2, Mojo.Event.tap, this.canvasBtnHandler);
1158 +               // drawer setup
1159 +               this.controller.setupWidget("DPscrol",{mode: 'horizontal-snap'}, {snapElements: {x:[this.controller.get("DPmonth_0"), this.controller.get("DPmonth_1"), this.controller.get("DPmonth_2"), this.controller.get("DPmonth_3"), this.controller.get("DPmonth_4"), this.controller.get("DPmonth_5")]}});\r
1160 +               this.dModel = {open:false};
1161 +               this.controller.setupWidget('lDrawer', {property:'open', drawerBottomOffset: 50}, this.dModel);
1162 +               this.ldrawer = this.controller.get('lDrawer');          
1163 +               // setup month canvas context
1164 +               this.redlineSplit = this.controller.get("DPmonth_2");
1165 +               this.mthctx = [];
1166 +               this.left0 = this.controller.get("left0");
1167 +               this.mthctx[0] = this.left0.getContext('2d');
1168 +               this.left1 = this.controller.get("left1");
1169 +               this.mthctx[1] = this.left1.getContext('2d');
1170 +               this.left2 = this.controller.get("left2");
1171 +               this.mthctx[2] = this.left2.getContext('2d');
1172 +               this.right0 = this.controller.get("right0");
1173 +               this.mthctx[3] = this.right0.getContext('2d');
1174 +               this.right1 = this.controller.get("right1");
1175 +               this.mthctx[4] = this.right1.getContext('2d');
1176 +               this.right2 = this.controller.get("right2");
1177 +               this.mthctx[5] = this.right2.getContext('2d');
1178 +               // setup vars
1179 +               this.startOfWeek = getPrefs().startOfWeek;
1180 +               this._rdNames = [];
1181 +               this.RMlast = {};
1182 +               this.RMlast.duration = {years: 0, months: 0, days: 0, hours: 0, minutes: 0};
1183 +               this.RM = [];
1184 +               this.topCor = "";
1185 +               this.leftCor = "";
1186 +               this.rtdayimg = new Image();
1187 +               this.rtdayimg.src = "./images/week-current-day.png";
1188 +               this.rmdoRec = false;
1189 +               this.rdayNames();
1190 +               this.rmEval();
1191 +               this.orderRM(this.RMlast.stD, this.RMlast.eD, this.targetEvent.allDay);
1192 +               this.stImg = new Image();
1193 +               this.stImg.src = "./images/day-allday-event-green-center.png";
1194 +               this.eImg = new Image();
1195 +               this.eImg.src = "./images/day-allday-event-red-center.png";
1196 +               this.dImg = new Image();
1197 +               this.dImg.src = "./images/day-event-green.png";
1198 +               this.rImg = new Image();
1199 +               this.rImg.src = "./images/day-event-yellow.png";
1200 +               this.rmScroller = this.controller.get('DPscrol');
1201 +               //this.rmScrollP = {x : 0, y : 0};
1202 +               this.rmlastBtn = null;
1203 +               this.rtDate = new Date();
1204 +               this.rmcalHold = false;
1205 +       },
1206      
1207 +       
1208 +       // toggle drawer function:
1209 +       DPtoggleDrawer: function(e) {
1210 +               var curBtn = e.currentTarget.id;
1211 +               if(curBtn == "popCanvasBtn2") {
1212 +                       this.rmScrollTo(this.RMlast.stD);
1213 +               } else {
1214 +                       this.rmScrollTo(this.RMlast.eD);
1215 +               }
1216 +               if (curBtn == this.rmlastBtn)  {
1217 +                       this.ldrawer.mojo.setOpenState(false);
1218 +                       this.rmlastBtn = null;
1219 +                       if(!this.targetEvent.allDay) {
1220 +                               this.slideDown(this.controller.get('start_time_row'), 0.4);             
1221 +                               this.slideDown(this.controller.get('end_time_row'), 0.4);
1222 +                       }
1223 +               } else {
1224 +                       this.rmlastBtn = curBtn;
1225 +                       var state = this.ldrawer.mojo.getOpenState();
1226 +                       if(!state) {
1227 +                       
1228 +                               this.ldrawer.mojo.setOpenState(true);
1229 +                               if(!this.targetEvent.allDay) {
1230 +                                       this.slideUp(this.controller.get('start_time_row'), 0.4);
1231 +                                       this.slideUp(this.controller.get('end_time_row'), 0.4);
1232 +                               }
1233 +                       }
1234 +               }
1235 +       },      
1236 +       
1237 +       rmScrollTo: function(x) {
1238 +               if (x instanceof Date == true) { 
1239 +                       var whatMn = x.getMonth();
1240 +                       var whatYr = x.getFullYear();
1241 +                       var idx = this.risRendered(whatYr, whatMn);
1242 +               } else if(x >= 0 && x <= 6) {
1243 +                       var idx = x;
1244 +               }
1245 +               //idx = idx * 241;
1246 +               //idx = -idx;
1247 +               this.controller.get('DPscrol').mojo.setSnapIndex(idx, true);
1248 +       },
1249 +       
1250 +       rmHandleUpdate: function() {
1251 +               // date picker model changed do redraw
1252 +               for(var i = 0;i<6; i++) {
1253 +                       this.mthctx[i].clearRect(0, 0, 240,220);
1254 +               }
1255 +               this.rmEval();
1256 +               this.orderRM(this.RMlast.stD, this.RMlast.eD, this.targetEvent.allDay);
1257 +               this.markDay(new Date(), this.rtdayimg);
1258 +               this.markDay(this.RMlast.stD, this.stImg , null/*color*/, 1/*x adjust*/,null/*y adjust*/ ,2 /*wd adjust*/,this.colHW /*ht adjust*/);
1259 +               this.markDay(this.RMlast.eD, this.eImg , null/*color*/, this.colHW-2/*x adjust*/,null/*y adjust*/ ,2 /*wd adjust*/,this.colHW /*ht adjust*/);
1260 +               this.rmMarkD();
1261 +               if(this.rmdoRec) {this.rmRecur(); }
1262 +               this.rmScrollTo(this.RMlast.stD);
1263 +       },
1264 +       
1265      checktargetEventDirty: function(){
1266          //construct rrule
1267                 if(this.targetEvent.rruleModel)
1268 @@ -413,10 +1228,70 @@ var DatetimeAssistant = Class.create({
1269                  this.callBackAfterUpdate(this.targetId);
1270              this.controller.stageController.popScene("datetime");
1271          }
1272 -        
1273 -        
1274 -        
1275      },
1276 +       
1277 +       saveThisAndFuture: function() {
1278 +               // change end date, add  new event
1279 +               this.newEvent = Object.clone(this.targetEvent);
1280 +               if(this.targetEvent.startTimestamp === this.originalstartTimestamp) {
1281 +                       //first event same as series
1282 +                       this.saveEvent(undefined);
1283 +                       return;
1284 +               }
1285 +               var endtimestamp = new Date(this.targetEvent.endTimestamp);
1286 +               var time = new Date(this.targetModifiedTime.end);
1287 +               time.setHours(endtimestamp.getHours());
1288 +               time.setMinutes(endtimestamp.getMinutes());
1289 +               time.setSeconds(endtimestamp.getSeconds());
1290 +               this.targetEvent.endValidity= time.addDays(-1).getTime();
1291 +               this.recurrenceRule = getRecurrenceRule();
1292 +               this.targetEvent.isRecurringForever = false;
1293 +               if(this.targetEvent.rruleModel.count) {this.targetEvent.rruleModel.count = 0;}
1294 +               this.targetEvent.rruleModel.until= this.recurrenceRule.calculateRecurTime(this.targetEvent.endValidity);
1295 +               this.recurrenceRule.constructRRuleFromModel(this.targetEvent);
1296 +               
1297 +               this.requests.push(this.service.setEvent(this.targetEvent, this.ThisAndFutureCB.bind(this), this.editSceneController));
1298 +       },
1299 +       
1300 +       ThisAndFutureCB: function () {
1301 +               this.newEvent.id = 0;
1302 +               this.newEvent.parentId = undefined;
1303 +               if(this.newEvent.backupID) {this.newEvent.backupID = undefined;}
1304 +               this.targetId = 0;
1305 +               if(!this.newEvent.isRecurringForever) {
1306 +                       var time = new Date(this.newEvent.endValidity);
1307 +                       var endtimestamp = new Date(this.targetModifiedTime.end);
1308 +                       time.setHours(endtimestamp.getHours());
1309 +                       time.setMinutes(endtimestamp.getMinutes());
1310 +                       time.setSeconds(endtimestamp.getSeconds());
1311 +                       this.newEvent.endValidity = time.getTime();
1312 +                       this.newEvent.rruleModel.until= this.recurrenceRule.calculateRecurTime(this.newEvent.endValidity);
1313 +               }else if(this.newEvent.isRecurringForever){
1314 +                       this.newEvent.endValidity = "Long.MAX_VALUE";
1315 +                       if(this.newEvent.rruleModel.until) {delete this.newEvent.rruleModel.until;}
1316 +               }
1317 +               this.newEvent.startTimestamp = this.targetModifiedTime.start;
1318 +               this.newEvent.start = this.targetModifiedTime.start;
1319 +               this.newEvent.endTimestamp = this.targetModifiedTime.end;
1320 +               this.newEvent.end = this.targetModifiedTime.end;
1321 +               
1322 +               this.recurrenceRule.constructRRuleFromModel(this.newEvent);
1323 +               if(this.newEvent.originalstartTimestamp) {this.newEvent.originalstartTimestamp = undefined;}
1324 +               this.requests.push(this.service.setEvent(this.newEvent, this.createdEvent.bind(this), this.editSceneController));
1325 +       },
1326 +       
1327 +       createdEvent: function(response) {
1328 +               if(response.id) {
1329 +                       this.newEvent.id = response.id + "";
1330 +                       this.newEvent.dirty = false;
1331 +               }
1332 +               if(this.callBackAfterUpdate != undefined) {
1333 +                       this.callBackAfterUpdate(this.newEvent.id);
1334 +               }
1335 +               this.targetCallBack(this.newEvent, Object.clone(this.newEvent));
1336 +               this.controller.stageController.popScene("datetime");
1337 +       },
1338 +       
1339      renderSetEvent: function(response){
1340          //this callback is called only in the case
1341          //when we are in the scene and went into cardmode
1342 @@ -431,12 +1306,47 @@ var DatetimeAssistant = Class.create({
1343      },
1344      
1345      activate: function(){
1346 -    },
1347 +               this.markDay(new Date(), this.rtdayimg);
1348 +               this.markDay(this.RMlast.stD, this.stImg , null/*color*/,0/*x adjust*/,null/*y adjust*/ ,2 /*wd adjust*/,this.colHW /*ht adjust*/);
1349 +               this.markDay(this.RMlast.eD, this.eImg , null/*color*/, this.colHW-2/*x adjust*/,null/*y adjust*/ ,2 /*wd adjust*/,this.colHW /*ht adjust*/);
1350 +               this.rmMarkD();
1351 +               if(this.rmdoRec) {this.rmRecur(); }
1352 +               this.rmScrollTo(this.RMlast.stD);
1353 +               //tap handlers
1354 +               this.calTapHandler = this.handleCalTap.bind(this);
1355 +               this.calHoldHandler = this.handleCalHold.bind(this);
1356 +               Mojo.Event.listen(this.left0, Mojo.Event.tap, this.calTapHandler);
1357 +               Mojo.Event.listen(this.left1, Mojo.Event.tap, this.calTapHandler);
1358 +               Mojo.Event.listen(this.left2, Mojo.Event.tap, this.calTapHandler);
1359 +               Mojo.Event.listen(this.right0, Mojo.Event.tap, this.calTapHandler);
1360 +               Mojo.Event.listen(this.right1, Mojo.Event.tap, this.calTapHandler);
1361 +               Mojo.Event.listen(this.right2, Mojo.Event.tap, this.calTapHandler);
1362 +               Mojo.Event.listen(this.left0, Mojo.Event.hold, this.calHoldHandler);
1363 +               Mojo.Event.listen(this.left1, Mojo.Event.hold, this.calHoldHandler);
1364 +               Mojo.Event.listen(this.left2, Mojo.Event.hold, this.calHoldHandler);
1365 +               Mojo.Event.listen(this.right0, Mojo.Event.hold, this.calHoldHandler);
1366 +               Mojo.Event.listen(this.right1, Mojo.Event.hold, this.calHoldHandler);
1367 +               Mojo.Event.listen(this.right2, Mojo.Event.hold, this.calHoldHandler);
1368 +               },
1369      
1370      deactivate: function(){
1371 -        //Mojo.Log.info("datetime-assistant:deactivate");      
1372 -        this.controller.stopListening(this.controller.document, Mojo.Event.deactivate, this.blurStage);
1373 -    },
1374 +               Mojo.Event.stopListening(this.popCanvasBtn, Mojo.Event.tap, this.canvasBtnHandler);
1375 +               Mojo.Event.stopListening(this.popCanvasBtn, Mojo.Event.tap, this.canvasBtnHandler);
1376 +               //Mojo.Log.info("datetime-assistant:deactivate");       
1377 +               this.controller.stopListening(this.controller.document, Mojo.Event.deactivate, this.blurStage);
1378 +               Mojo.Event.stopListening(this.left0, Mojo.Event.tap, this.calTapHandler);
1379 +               Mojo.Event.stopListening(this.left1, Mojo.Event.tap, this.calTapHandler);
1380 +               Mojo.Event.stopListening(this.left2, Mojo.Event.tap, this.calTapHandler);
1381 +               Mojo.Event.stopListening(this.right0, Mojo.Event.tap, this.calTapHandler);
1382 +               Mojo.Event.stopListening(this.right1, Mojo.Event.tap, this.calTapHandler);
1383 +               Mojo.Event.stopListening(this.right2, Mojo.Event.tap, this.calTapHandler);
1384 +               Mojo.Event.stopListening(this.left0, Mojo.Event.hold, this.calHoldHandler);
1385 +               Mojo.Event.stopListening(this.left1, Mojo.Event.hold, this.calHoldHandler);
1386 +               Mojo.Event.stopListening(this.left2, Mojo.Event.hold, this.calHoldHandler);
1387 +               Mojo.Event.stopListening(this.right0, Mojo.Event.hold, this.calHoldHandler);
1388 +               Mojo.Event.stopListening(this.right1, Mojo.Event.hold, this.calHoldHandler);
1389 +               Mojo.Event.stopListening(this.right2, Mojo.Event.hold, this.calHoldHandler);
1390 +       },
1391         
1392         //When the start date of the event is changed, WEEKLY:single day, WEEKLY:custom, MONTHLY repeating events 
1393         //must update their rruleModel. DAILY, YEARLY, and WEEKLY:weekdays repeating events do not need to be changed.
1394 @@ -493,15 +1403,32 @@ var DatetimeAssistant = Class.create({
1395                  
1396              case 'MONTHLY': // Do NOT Localize
1397                  //Monthly by date
1398 +                               if(oldDate.getDate() === newDate.getDate() && oldDate.getMonth() === newDate.getMonth() && oldDate.getFullYear() === newDate.getFullYear()) {
1399 +                                       return; // no reason to change - just changed time
1400 +                               }
1401 +                               var ucLastDay = getIsLastProps(newDate.getTime());
1402                  if (this.targetEvent.rruleModel.bymonthday.length > 0) {
1403 -                    this.targetEvent.rruleModel.bymonthday = [];
1404 -                    this.targetEvent.rruleModel.bymonthday.push(newDate.toString("d"));
1405 -                }
1406 -                else {
1407 -                    var nth = getDOWCount(this.targetEvent.startTimestamp);
1408 -                    this.targetEvent.rruleModel.byday = [];
1409 -                    var byday = this.recurrenceRule.dayMap[newDate.getDay()];
1410 -                    this.targetEvent.rruleModel.byday.push(nth + byday);
1411 +                                       var ord = parseInt(this.targetEvent.rruleModel.bymonthday[0], 10);
1412 +                    if(ord >0 || (ord < 0 && ucLastDay.lastweek === false) ) {
1413 +                                               this.targetEvent.rruleModel.bymonthday = [];
1414 +                                               this.targetEvent.rruleModel.bymonthday.push(newDate.toString("d"));
1415 +                                       } else if(ord < 0 && ucLastDay.lastweek) { //was a last day of month type
1416 +                                               this.targetEvent.rruleModel.bymonthday = [];
1417 +                                               this.targetEvent.rruleModel.bymonthday.push(ucLastDay.lastday);
1418 +                                       }
1419 +                } else {
1420 +                                       var ord = this.targetEvent.rruleModel.byday.length > 0 ? parseInt(this.targetEvent.rruleModel.byday[0], 10) : -1;
1421 +                                       if(ord >0 || (ord < 0 && ucLastDay.lastweek === false) ) {
1422 +                                               var nth = getDOWCount(this.targetEvent.startTimestamp);
1423 +                                               this.targetEvent.rruleModel.byday = [];
1424 +                                               var byday = this.recurrenceRule.dayMap[newDate.getDay()];
1425 +                                               this.targetEvent.rruleModel.byday.push(nth + byday);
1426 +                                       } else if(ord < 0 && ucLastDay.lastweek) { //was a last day, week, weekend type
1427 +                                               var nth = -1;
1428 +                                               this.targetEvent.rruleModel.byday = [];
1429 +                                               var byday = this.recurrenceRule.dayMap[newDate.getDay()];
1430 +                                               this.targetEvent.rruleModel.byday.push(nth + byday);
1431 +                                       }
1432                  }
1433                                 changed = true;
1434                  break;
1435 @@ -553,6 +1480,7 @@ var DatetimeAssistant = Class.create({
1436              this.targetEvent.alldayReservedStartTimestamp = this.targetModifiedTime.start;
1437              this.targetEvent.alldayReservedEndTimestamp = this.targetModifiedTime.end;
1438          }
1439 +               this.rmHandleUpdate();
1440      },
1441      
1442      endDateSet: function(isOnBack){
1443 @@ -642,8 +1570,10 @@ var DatetimeAssistant = Class.create({
1444                                 }
1445              }
1446              
1447 -            if (isOnBack == false) 
1448 +            if (isOnBack == false) {
1449                  this.calcDuration();
1450 +                               this.rmHandleUpdate();
1451 +                       }
1452              this.targetModifiedTime.changed = true;
1453              if (this.datetimeoutID) {
1454                  this.controller.window.clearTimeout(this.datetimeoutID);
1455 @@ -751,6 +1681,7 @@ var DatetimeAssistant = Class.create({
1456          this.controller.modelChanged(this.startTimeModel);
1457          this.controller.modelChanged(this.endTimeModel);
1458          this.targetModifiedTime.changed = false;
1459 +               this.rmHandleUpdate();
1460          //Mojo.Log.info("Old event all day %o, new Event all day %o",this.oldEvent.allDay,this.allDayCheckboxModel);
1461          if (this.oldEvent.allDay != this.allDayCheckboxModel.value) {
1462          
1463 @@ -761,6 +1692,85 @@ var DatetimeAssistant = Class.create({
1464          this.targetCallBack(this.targetEvent, null);
1465          
1466      },
1467 -
1468 +       
1469 +       //Calendar Tap Handlers
1470 +       handleCalHold: function(event) {
1471 +               // set the hold var, send to tap handler
1472 +               this.rmcalHold = true;
1473 +               this.handleCalTap(event);
1474 +       },
1475 +       
1476 +       handleCalTap: function(event) {
1477 +               Event.stop(event);
1478 +               var x = event.down.offsetX;
1479 +               var y = event.down.offsetY;
1480 +               //get rid of tap areas not in calendar day area
1481 +               if(x <= 30 || y <= 40 || x>= 241) {
1482 +                       this.rmcalHold = false;
1483 +                       return;
1484 +               }
1485 +               var rmcan = event.target.id;
1486 +               switch (rmcan) {
1487 +                       case 'left0':
1488 +                               var rmindex = 0;
1489 +                               break;
1490 +                       case 'left1':
1491 +                               var rmindex = 1;
1492 +                               break;
1493 +                       case 'left2':
1494 +                               var rmindex = 2;
1495 +                               break;
1496 +                       case 'right0':
1497 +                               var rmindex = 3;
1498 +                               break;
1499 +                       case 'right1':
1500 +                               var rmindex = 4;
1501 +                               break;
1502 +                       case 'right2':
1503 +                               var rmindex = 5;
1504 +                               break;
1505 +               }
1506 +               // get first day index month year
1507 +               if (x && y && (rmindex !== undefined)) {
1508 +                       var calx = x - 30;
1509 +                       var caly = y - 40;
1510 +                       var cald1idx = this.RM[rmindex].fstDayLidx;
1511 +                       var calcol = Math.floor(calx/this.colHW);
1512 +                       var calrow = Math.floor(caly/this.colHW);
1513 +                       var caldate = ((calrow * 7) + calcol +1) - cald1idx;
1514 +                       if((caldate > this.RM[rmindex].maxdays) || (caldate <= 0)) {
1515 +                               // tapped an area with invalid date
1516 +                               this.rmcalHold = false;
1517 +                               return;
1518 +                       }
1519 +                       var calmon = this.RM[rmindex].month;
1520 +                       var calyear = this.RM[rmindex].year;
1521 +                       if((calyear !== undefined) && (calmon !== undefined) && (caldate !== undefined)) {
1522 +                               if(this.rmlastBtn != null && this.rmlastBtn == "popCanvasBtn2") {
1523 +                                       // start date
1524 +                                       this.startDateModel.date = new Date(calyear, calmon, caldate);
1525 +                                       this.controller.modelChanged(this.startDateModel);
1526 +                                       Mojo.Event.send(this.controller.get('edit_startDate'), 'mojo-property-change', {value: this.startDateModel.date} )
1527 +                               } else if(this.rmlastBtn !== null && this.rmlastBtn == "popCanvasBtn") {
1528 +                                       // end date
1529 +                                       this.endDateModel.date = new Date(calyear, calmon, caldate);
1530 +                                       this.controller.modelChanged(this.endDateModel);
1531 +                                       Mojo.Event.send(this.controller.get('edit_endDate'), 'mojo-property-change', {value: this.endDateModel.date} )
1532 +                               }
1533 +                               // check whether drawer should close
1534 +                               if(this.rmcalHold == false) {
1535 +                                       this.ldrawer.mojo.setOpenState(false);
1536 +                                       this.rmlastBtn = null;
1537 +                                       if(!this.targetEvent.allDay) {
1538 +                                               this.slideDown(this.controller.get('start_time_row'), 0.4);             
1539 +                                               this.slideDown(this.controller.get('end_time_row'), 0.4);
1540 +                                       }
1541 +                               } else {
1542 +                                       this.rmcalHold = false;
1543 +                                       return;
1544 +                               }
1545 +                       }
1546 +               }
1547 +       },
1548  
1549  });
1550 diff --git a/usr/palm/applications/com.palm.app.calendar/app/controllers/day-assistant.js b/usr/palm/applications/com.palm.app.calendar/app/controllers/day-assistant.js
1551 index 84263c0..a13e140 100644
1552 --- a/usr/palm/applications/com.palm.app.calendar/app/controllers/day-assistant.js
1553 +++ b/usr/palm/applications/com.palm.app.calendar/app/controllers/day-assistant.js
1554 @@ -11,17 +11,113 @@ var DayAssistant = Class.create({
1555                 this.appMenuModel = { visible:true, 
1556                                                                         label:$L('Calendar'), 
1557                                                                         items: [ Mojo.Menu.editItem,
1558 -                                                                                       {label:$L('New'), items: [{label:$L('Event'), command:'newtimed', disabled:false},
1559 -                                                                                                                               {label:$L('All day event'), command:'newallday', disabled:false}] 
1560 +                                                                                       {label:$L('New'), items: [{label:$L('Event'), shortcut:'n', command:'newtimed', disabled:false},
1561 +                                                                                                                               {label:$L('All day event'), shortcut:'d', command:'newallday', disabled:false}] 
1562                                                                                                                                                                 
1563                                                                                         },                                                                                      
1564                                                                                         {label:$L('Sync Now'), command:'sync', id: 2},
1565                                                                                         {label:$L('Show today'), command:'today', id: 3},
1566 -                                                                                       {label:$L('Jump to...'), command:'jumpto', id: 4},
1567 +                                                                                       {label:$L('Jump to...')+ '/' + $L("Templates"), command:'jumpto', id: 4},
1568                                                                                         {label:$L('Missed reminders...'), command:'reminders', id: 5},
1569                                                                                         {label:$L('Preferences & Accounts'), command:Mojo.Menu.prefsCmd, disabled: false},
1570 +                                                                                       //this.compressedMenuItem = {label:$L('Compressed View'), command:'compressed', chosen: true},
1571                                                                                         {label:$L('Help'), command:Mojo.Menu.helpCmd, disabled:false}]
1572                                                                 };
1573 +               
1574 +               this.uberCategories = [
1575 +                               {'name': 'birthday'}, // Do NOT Localize these
1576 +                               {'name': 'car'},
1577 +                               {'name': 'doctor'},
1578 +                               {'name': 'holiday'},
1579 +                               {'name': 'kids'},
1580 +                               {'name': 'party'},
1581 +                               {'name': 'plane'},
1582 +                               {'name': 'vacation'},
1583 +                       ];
1584 +               
1585 +               this.compressedView = false;
1586 +               this.enhancedView = false;
1587 +               this.dayViewShrink = "none";
1588 +               this.dayViewIcons = true;
1589 +               this.uberBackGesture = 'last';
1590 +               this.weekNumOffset = 0;
1591 +               this.useISOweekNum = false;
1592 +               this.prefStartDoW = 0;
1593 +               this.weekModulusNum = 1;
1594 +               this.weekNumberTitle = true;
1595 +               this.dayCookie = new Mojo.Model.Cookie('DayEnhanced');
1596 +               if (this.dayCookie !== undefined) {
1597 +                       var daycookie = this.dayCookie.get();
1598 +                       if(daycookie !== undefined) {
1599 +                               if(daycookie.dayviewcompressed !== undefined) {
1600 +                                       this.compressedView = daycookie.dayviewcompressed;
1601 +                               } else {
1602 +                                       this.compressedView = false;
1603 +                               }
1604 +                               if(daycookie.dayviewenhanced !== undefined) {
1605 +                                       this.enhancedView = daycookie.dayviewenhanced;
1606 +                               } else {
1607 +                                       this.enhancedView = false;
1608 +                               }
1609 +                               if(daycookie.dayviewshrink !== undefined) {
1610 +                                       this.dayViewShrink = daycookie.dayviewshrink;
1611 +                               } else {
1612 +                                       this.dayViewShrink = "none";
1613 +                               }
1614 +                               if(daycookie.dayviewicons !== undefined) {
1615 +                                       this.dayViewIcons = daycookie.dayviewicons;
1616 +                               } else {
1617 +                                       this.dayViewIcons = true;
1618 +                               }
1619 +                               if(daycookie.weeknumoffset !== undefined) {
1620 +                                       this.weekNumOffset = parseInt(daycookie.weeknumoffset,10);
1621 +                               } else {
1622 +                                       this.weekNumOffset = 0;
1623 +                               }
1624 +                               if(daycookie.weekmodulusnum !== undefined) {
1625 +                                       this.weekModulusNum = parseInt(daycookie.weekmodulusnum, 10);
1626 +                               } else {
1627 +                                       this.weekModulusNum = 1;
1628 +                               }
1629 +                               if(daycookie.weeknumbertitle !== undefined) {
1630 +                                               this.weekNumberTitle = daycookie.weeknumbertitle;
1631 +                               } else {
1632 +                                               this.weekNumberTitle = true;
1633 +                               }
1634 +                               if(daycookie.uberbackgesture !== undefined) {
1635 +                                               this.uberBackGesture = daycookie.uberbackgesture;
1636 +                               } else {
1637 +                                               this.uberBackGesture = 'last';
1638 +                               }
1639 +                               if (daycookie.useisoweeknum !== undefined) {
1640 +                                       this.useISOweekNum = daycookie.useisoweeknum;
1641 +                               } else {
1642 +                                       this.useISOweekNum = false;
1643 +                               }
1644 +                               if (daycookie.prefsstartofweek !== undefined) {
1645 +                                       this.prefStartDoW = parseInt(daycookie.prefsstartofweek, 10) -1;
1646 +                               } else {
1647 +                                       this.prefStartDoW = 0;
1648 +                               }
1649 +                       }
1650 +               }
1651 +               this.userUberCats = [];
1652 +               this.catCookie = new Mojo.Model.Cookie("userUberCats");
1653 +               if(this.catCookie) {
1654 +                       var catcookie = this.catCookie.get();
1655 +                       if(catcookie) {
1656 +                               if(catcookie.userubercats && catcookie.userubercats.length > 0){
1657 +                                       this.userUberCats = catcookie.userubercats;
1658 +                               } else {
1659 +                                       this.userUberCats = this.uberCategories;
1660 +                               }
1661 +                       } else {
1662 +                               this.userUberCats = this.uberCategories;
1663 +                       }
1664 +               } else {
1665 +                               this.userUberCats = this.uberCategories;
1666 +               }
1667 +
1668                 this.colors = {
1669                                 'cal-color-blue':       {background: 'rgb(145, 211, 234)', border: 'rgb(99, 165, 188)', text: 'rgb(5, 32, 41)'},
1670                                 'cal-color-green':      {background: 'rgb(140, 240, 140)', border: 'rgb(77, 206, 77)',  text: 'rgb(1, 52, 1)'},
1671 @@ -31,7 +127,7 @@ var DayAssistant = Class.create({
1672                                 'cal-color-pink':       {background: 'rgb(245, 156, 188)', border: 'rgb(209, 104, 147)',text: 'rgb(40, 0, 0)'},
1673                                 'cal-color-red':        {background: 'rgb(255, 151, 151)', border: 'rgb(224, 98, 98)',  text: 'rgb(45, 8, 21)'},
1674                                 'cal-color-purple': {background: 'rgb(217, 183, 255)', border: 'rgb(177, 128, 232)',text: 'rgb(38, 22, 56)'},
1675 -                               'cal-color-teal':       {background: 'rgb(114, 223, 210)', border: 'rgb(68, 177, 164)', text: 'rgb(0, 42, 36)'},
1676 +                               'cal-color-teal':       {background: 'rgb(114, 223, 210)', border: 'rgb(68, 177, 164)', text: 'rgb(0, 42, 36)'}
1677                         };
1678                         
1679                 this.PREV_DAY = 1;
1680 @@ -42,11 +138,23 @@ var DayAssistant = Class.create({
1681                 this.pendingCalendarSettingsUpdate = false;
1682                 //this.pendingOpenScratchEventInDetails = false;
1683                 this.snapEffectCount = 0;
1684 -
1685 -               
1686 -               this.hourHeight = 48;
1687 -               this.halfHourHeight = 24;
1688 -               this.fifteenMinuteHeight = 12;
1689 +               this.imgAlarm = new Image();
1690 +               this.imgAlarm.src = "/media/internal/.scrims/ubercalendar/alarm-icon.png";
1691 +               this.imgIcons = new Object();
1692 +               
1693 +               if(this.enhancedView && this.dayViewShrink == "strong") {
1694 +                       this.hourHeight = 16;
1695 +                       this.halfHourHeight = Math.round(this.hourHeight / 2);
1696 +                       this.fifteenMinuteHeight = Math.round(this.hourHeight / 4);
1697 +               } else if(this.enhancedView && this.dayViewShrink == "medium") {
1698 +                       this.hourHeight = 24;
1699 +                       this.halfHourHeight = Math.round(this.hourHeight / 2);
1700 +                       this.fifteenMinuteHeight = Math.round(this.hourHeight / 4);
1701 +               } else {
1702 +                       this.hourHeight = 48;
1703 +                       this.halfHourHeight = 24;
1704 +                       this.fifteenMinuteHeight = 12;
1705 +               }
1706                 
1707                 this.totalWidth = 320;
1708                 this.totalHeight = this.hourHeight * 24;
1709 @@ -170,6 +278,28 @@ var DayAssistant = Class.create({
1710                 this.hideFastScrollView();
1711         },
1712         
1713 +       getUCGroupsProps: function() {
1714 +               // check for UC groups
1715 +               if(this.uberGroups && this.uberGroups.inUse === true && this.userUberCalGroups && this.userUberCalGroups.length > 0 && this.userUberCalGroups[0].rId !== undefined) {
1716 +                       var rID = this.uberGroups.rId;
1717 +                       if(rID) {
1718 +                               var len = this.userUberCalGroups.length;
1719 +                               var idx;
1720 +                               for(var i=0; i < len; i++){
1721 +                                       if(rID === this.userUberCalGroups[i].rId) {
1722 +                                               var idx = i;
1723 +                                               break;
1724 +                                       }
1725 +                               }
1726 +                               if(idx !== undefined && this.userUberCalGroups[idx].includes && this.userUberCalGroups[idx].includes.length >0) {
1727 +                                       this.ucGroupIdx = idx;
1728 +                               }
1729 +                       }
1730 +               } else {
1731 +                       this.ucGroupIdx = undefined;
1732 +               }
1733 +       },
1734 +       
1735         isDayDisplayed: function(day) {
1736                 if (this.listeningToScroller)
1737                         return 0;
1738 @@ -211,18 +341,46 @@ var DayAssistant = Class.create({
1739                 
1740         buildDayTitle: function(doScrim) {
1741                 var today = Date.today().clearTime();
1742 +               var year = new Date(this.dayDate).getFullYear();
1743 +               var month = new Date(this.dayDate).getMonth();
1744 +               var maxwkn = this.useISOweekNum === true ? new Date((month != 0 ? year : year -1), 11, 28).getISO8601Week() : new Date((month != 0 ? year : year -1), 11, 28).getWeekOfYear(this.prefStartDoW);
1745                 var dayDateNoTime = new Date(this.dayDate).clearTime();
1746 +               var weekNumber = this.useISOweekNum === true ? new Date(this.dayDate).getISO8601Week() : new Date(this.dayDate).getWeekOfYear(this.prefStartDoW);
1747 +               maxwkn = maxwkn == 0 ? 53 : maxwkn;
1748 +               weekNumber = weekNumber == 0 ? maxwkn : weekNumber;
1749 +               if(this.weekNumOffset !== undefined && this.weekNumOffset !=0) {
1750 +                       var wkNum = parseInt(weekNumber,10) + this.weekNumOffset;
1751 +                       weekNumber = wkNum > maxwkn ? (wkNum - maxwkn) : wkNum;
1752 +                       weekNumber = weekNumber < 10 ? '0' + weekNumber : weekNumber;
1753 +               }
1754 +               if(this.weekModulusNum != undefined && this.weekModulusNum <= 52 && this.weekModulusNum != 1) {
1755 +                       modNumber = (parseInt(weekNumber, 10) % this.weekModulusNum);
1756 +                       modNumber = modNumber !== 0 ? modNumber : this.weekModulusNum;
1757 +                       weekNumber = weekNumber + ' (' + modNumber +')';
1758 +               }
1759                 
1760                 if (dayDateNoTime.compareTo(today) == 0) {
1761 -                       var template = new Template($L("#{todayStr}, #{dateStr}"));
1762 -                       var todayStr= Mojo.Format.formatRelativeDate(today, {date: "short"}).capitalize();
1763 -                       
1764                         var templateModel = {};
1765 +                       if(this.weekNumberTitle) {
1766 +                               var template = new Template($L("#{todayStr}, #{dateStr}") + ", " + $L("W#{weekStr}"));
1767 +                               templateModel.weekStr = weekNumber;
1768 +                       } else {
1769 +                               var template = new Template($L("#{todayStr}, #{dateStr}"));
1770 +                       }
1771 +                       var todayStr= Mojo.Format.formatRelativeDate(today, {date: "short"}).capitalize();
1772                         templateModel.todayStr = todayStr;
1773                         templateModel.dateStr = Mojo.Format.formatDate(this.dayDate, $L("EEE MMM d"));
1774                         this.controller.get('dv_title').update(template.evaluate(templateModel)); // Localize this date format string
1775                 } else {
1776 -                       this.controller.get('dv_title').update(Mojo.Format.formatDate(this.dayDate, $L("EEE MMM d, yyyy"))); // Localize this date format string
1777 +                       if(this.weekNumberTitle) {
1778 +                               var template = new Template($L("#{dateStr}") + ", " + $L("W#{weekStr}"));
1779 +                               var templateModel = {};
1780 +                               templateModel.weekStr = weekNumber;
1781 +                               templateModel.dateStr = Mojo.Format.formatDate(this.dayDate, $L("EEE MMM d, yyyy"));
1782 +                               this.controller.get('dv_title').update(template.evaluate(templateModel)); // Localize this date format string
1783 +                       } else {
1784 +                               this.controller.get('dv_title').update(Mojo.Format.formatDate(this.dayDate, $L("EEE MMM d, yyyy"))); // Localize this date format string
1785 +                       }
1786                 }
1787                 
1788                 if (doScrim) {
1789 @@ -344,8 +502,14 @@ var DayAssistant = Class.create({
1790         },
1791         getXIndexForTimeText:function(ctx,i,text)
1792         {               
1793 -                       
1794 -                       ctx.font = "bold 14px Prelude";
1795 +                       if(this.enhancedView && this.dayViewShrink == "strong") {
1796 +                               ctx.font = "bold 10px Prelude";
1797 +                       } else if(this.enhancedView && this.dayViewShrink == "medium") {
1798 +                               ctx.font = "bold 12px Prelude";
1799 +                       } else {
1800 +                               ctx.font = "bold 14px Prelude";
1801 +                       }
1802 +               
1803                         
1804  
1805                         var metrics = ctx.measureText(text);
1806 @@ -381,14 +545,37 @@ var DayAssistant = Class.create({
1807                                 }
1808                                 
1809                                 if (i < 24) {
1810 -                                       var text = String(i);
1811 -                                       if (this.currentTimeFormat == "HH12") {
1812 -                                               if (i == 0) 
1813 -                                                       text = '12';
1814 -                                               if (i > 12) 
1815 -                                                       text = String(i - 12);
1816 +                                       if(this.enhancedView && this.dayViewShrink != "none") {
1817 +                                               // replace the time labels on the left with just three labels
1818 +                                               var text = "";
1819 +                                               if ( i == 12 ) {
1820 +                                                       text = (this.currentTimeFormat == "HH12") ? $L("noon") : "12";
1821 +                                                       ctx.strokeText(text, this.getXIndexForTimeText(ctx, i, text), top + (this.dayViewShrink == "strong" ? 7 : 11));
1822 +                                               } else if ( i == 6  || i == 18 ) {
1823 +                                                       text = "";
1824 +                                                       if (this.currentTimeFormat == "HH12") {
1825 +                                                               if ( i > 12 ) {
1826 +                                                                       text = String(i - 12) + "pm";
1827 +                                                               }
1828 +                                                               else {
1829 +                                                                       text = i + "am";
1830 +                                                               }
1831 +                                                       } else {
1832 +                                                               i = i<10 ? '0' + i : i;
1833 +                                                               text = String(i);
1834 +                                                       }
1835 +                                               }
1836 +                                               ctx.strokeText(text, this.getXIndexForTimeText(ctx, i, text), top + (this.dayViewShrink == "strong" ? 7 : 11));
1837 +                                       } else {
1838 +                                               var text = String(i);
1839 +                                               if (this.currentTimeFormat == "HH12") {
1840 +                                                       if (i == 0) 
1841 +                                                               text = '12';
1842 +                                                       if (i > 12) 
1843 +                                                               text = String(i - 12);
1844 +                                               }
1845 +                                               ctx.strokeText(text, this.getXIndexForTimeText(ctx, i, text), top + 15);
1846                                         }
1847 -                                       ctx.strokeText(text, this.getXIndexForTimeText(ctx, i, text), top + 15);
1848                                 }
1849                         }
1850                 }
1851 @@ -504,7 +691,7 @@ var DayAssistant = Class.create({
1852                 return {left: left, top: top, width: width, height: height};
1853         },
1854  
1855 -               chopText:function(buf1,maxWidth,context){
1856 +       chopText:function(buf1,maxWidth,context){
1857                 var buf2;
1858                 var index=0;
1859                 
1860 @@ -702,6 +889,9 @@ var DayAssistant = Class.create({
1861                 //Mojo.Log.info("day-assistant: renderEvent");
1862                 if (this.animating && !event.animatible)
1863                         return;
1864 +
1865 +
1866 +//Mojo.Log.error(Object.toJSON(event));
1867         
1868                 var ctx = this.divs[whichDay].ctxEvents;
1869                 var marginLeft = 28;
1870 @@ -743,21 +933,101 @@ var DayAssistant = Class.create({
1871                 ctx.fillRect(left+1, top+height-3, width-2, 1);
1872                 
1873                 var textTop = top + 30;
1874 -               
1875 +
1876 +               // get more details
1877 +               if (!event.subject && event.gotFullDetails === undefined) {
1878 +                       // get more infos for this event
1879 +                       getCalendarService().getEvent(event.id,
1880 +                               this.getEventDetails.bind(this, whichDay, event, selected, ghost),
1881 +                               function(response) {Mojo.Log.error(response.errorText);},
1882 +                               this.controller);
1883 +               }
1884                 // Subject
1885                 ctx.fillStyle = this.colors[event.calendarColor].text;
1886 -               if (selected)
1887 -                       ctx.fillStyle = "rgb(255, 255, 255)";
1888 -               ctx.font = "bold 14px Prelude";
1889 -               bottom = textTop;
1890 -               var subjectTop = top+15;
1891 -               if (bottom >= (top + height))
1892 -                       subjectTop = top+17;    // no room for location or note, therefore vertically center subject text
1893 -               this.fillText(event.subject, ctx, left+4, subjectTop, width, bottom, 15 /*line height*/);       
1894 -               
1895 +               if (selected) {
1896 +                       ctx.fillStyle = "rgb(255, 255, 255)"; }
1897 +               if(this.enhancedView && this.dayViewShrink != "none") {
1898 +                       ctx.font = (this.dayViewShrink == "strong") ? "bold 10px Prelude" : "bold 12px Prelude";
1899 +                       bottom = textTop;
1900 +                       // prepend the subject with a human readable time stamp
1901 +                       var subjectTop = top+12;
1902 +                       var timeText = "";
1903 +                       var d = new Date(event.start);
1904 +                       var timeH = d.getHours();
1905 +                       var timeM = d.getMinutes();
1906 +                       timeM = timeM <10 ? '0' + String(timeM) : String(timeM);
1907 +                       if (this.currentTimeFormat == "HH12") {
1908 +                               if ( timeM > 0 ) {
1909 +                                       if ( timeH == 0 ) {
1910 +                                               timeText = "12:" + timeM + "a";
1911 +                                       } else if ( timeH == 12 ) {
1912 +                                               timeText = timeH + ":" + timeM + "p";
1913 +                                       } else if ( timeH < 12 ) {
1914 +                                               timeText = timeH + ":" + timeM + "a";
1915 +                                       } else {
1916 +                                               timeText = String(timeH - 12) + ":" + timeM + "p";
1917 +                                       }
1918 +                               }
1919 +                               else {
1920 +                                       if ( timeH == 0 ) {
1921 +                                               timeText = "12a";
1922 +                                       } else if ( timeH == 12 ) {
1923 +                                               timeText = timeH + "p";
1924 +                                       } else if ( timeH < 12 ) {
1925 +                                               timeText = timeH + "a";
1926 +                                       } else {
1927 +                                               timeText = String(timeH - 12) + "p";
1928 +                                       }
1929 +                               }
1930 +                       } else {
1931 +                               timeText = timeH + ":" + timeM;
1932 +                       }
1933 +                       //var str = Object.toJSON(event);
1934 +                       //console.error(str);
1935 +                       this.fillText(timeText + " " + event.subject, ctx, left+4, subjectTop, width, bottom, 15 /*line height*/);      
1936 +               } else {
1937 +                       ctx.font = "bold 14px Prelude";
1938 +                       bottom = textTop;
1939 +                       var subjectTop = top+15;
1940 +                       if (bottom >= (top + height))
1941 +                               subjectTop = top+17;    // no room for location or note, therefore vertically center subject text
1942 +                       this.fillText(event.subject, ctx, left+4, subjectTop, width-30, bottom, 15 /*line height*/);    
1943 +               }
1944 +               if(this.enhancedView) {
1945 +                       // Alarm
1946 +                       if ((event.alarm !== undefined) && (event.alarm != "none")) {
1947 +                               if(this.dayViewShrink != "none") {
1948 +                                       try{ ctx.drawImage(this.imgAlarm, left+4+width-18, subjectTop-10, 12, 12); }catch(e) {}
1949 +                               } else {
1950 +                               try{ ctx.drawImage(this.imgAlarm, left+4+width-18, subjectTop+1, 12, 12); }catch(e) {}
1951 +                               }
1952 +                       }
1953 +                       // Icon
1954 +                       if (event.note !== undefined && this.dayViewIcons) {
1955 +                               try {
1956 +                                       var patt = /((.|\n|\r)*?)ICON=([a-z0-9_-]{1,20});((.|\n|\r)*)/;
1957 +                                       var start = event.note.match(patt);
1958 +                                       if (start && start[3]) {
1959 +                                               var icon = start[3];
1960 +                                               if(this.dayViewShrink != "none") {
1961 +                                                       ctx.drawImage(this.imgIcons[icon], left+4+width-30, subjectTop-10, 12, 12);
1962 +                                               } else {
1963 +                                                       ctx.drawImage(this.imgIcons[icon], left+4+width-30, subjectTop+12, 12, 12);
1964 +                                               }
1965 +                                       }
1966 +                               } catch(e) {}
1967 +                       }
1968 +               }
1969                 // Location
1970                 if (event.location && (event.location.length > 0) && (textTop < (top + height))) {
1971 -                       ctx.font = "italic bold 14px Prelude";
1972 +                       if(this.enhancedView && this.dayViewShrink == "strong") {
1973 +                               ctx.font = "italic bold 10px Prelude";
1974 +                       } else if(this.enhancedView && this.dayViewShrink == "medium") {
1975 +                               ctx.font = "italic bold 12px Prelude";
1976 +                       } else {
1977 +                               ctx.font = "italic bold 14px Prelude";
1978 +                       }
1979 +                       //ctx.font = (this.enhancedView && this.dayViewShrink) ? "italic bold 10px Prelude" : "italic bold 14px Prelude";
1980                         bottom = textTop+15;
1981                         this.fillText(event.location,ctx,left+4,textTop,width,bottom,15 /*line height*/);               
1982                         textTop += 15;
1983 @@ -765,11 +1035,18 @@ var DayAssistant = Class.create({
1984                 
1985                 // Notes
1986                 if (event.note && (event.note.length > 0) && (textTop < (top + height))) {
1987 +                       var patt = /((.|\n|\r)*?)ICON=([a-z0-9_-]{1,20});((.|\n|\r)*)/;
1988 +                       var start = event.note.match(patt);
1989 +                       if(start && start[3] && this.enhancedView) {
1990 +                               var uberNoteTxt = start[1] + start[4];
1991 +                       } else {
1992 +                               var uberNoteTxt = event.note;
1993 +                       }
1994                         ctx.font = "12px Prelude";
1995                         bottom = top+height;
1996 -                       this.fillText(event.note, ctx, left+4, textTop-2, width, bottom-2, 12 /*line height*/);                 
1997 +                       this.fillText(uberNoteTxt, ctx, left+4, textTop-2, width, bottom-2, 12 /*line height*/);                        
1998                 }
1999 -               
2000 +