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