Roo/grid/Calendar.js
[roojs1] / Roo / grid / Calendar.js
1 /*
2   
3  * Licence LGPL
4  
5  */
6  
7 /**
8  * @class Roo.grid.Calendar
9  * @extends Roo.util.Grid
10  * This class extends the Grid to provide a calendar widget
11  * <br><br>Usage:<pre><code>
12  var grid = new Roo.grid.Calendar("my-container-id", {
13      ds: myDataStore,
14      cm: myColModel,
15      selModel: mySelectionModel,
16      autoSizeColumns: true,
17      monitorWindowResize: false,
18      trackMouseOver: true
19      eventstore : real data store..
20  });
21  // set any options
22  grid.render();
23   
24   * @constructor
25  * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
26  * The container MUST have some type of size defined for the grid to fill. The container will be
27  * automatically set to position relative if it isn't already.
28  * @param {Object} config A config object that sets properties on this grid.
29  */
30 Roo.grid.Calendar = function(container, config){
31         // initialize the container
32         this.container = Roo.get(container);
33         this.container.update("");
34         this.container.setStyle("overflow", "hidden");
35     this.container.addClass('x-grid-container');
36
37     this.id = this.container.id;
38
39     Roo.apply(this, config);
40     // check and correct shorthanded configs
41     
42     var rows = [];
43     var d =1;
44     for (var r = 0;r < 6;r++) {
45         
46         rows[r]=[];
47         for (var c =0;c < 7;c++) {
48             rows[r][c]= '';
49         }
50     }
51     if (this.eventStore) {
52         this.eventStore= Roo.factory(this.eventStore, Roo.data);
53         this.eventStore.on('load',this.onLoad, this);
54          
55     }
56     
57     this.dataSource = new Roo.data.Store({
58             proxy: new Roo.data.MemoryProxy(rows),
59             reader: new Roo.data.ArrayReader({}, [
60                    'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
61     });
62
63     this.dataSource.load();
64     this.ds = this.dataSource;
65     this.ds.xmodule = this.xmodule || false;
66     
67     this.colModel = new Roo.grid.ColumnModel( [
68         {
69             xtype: 'ColumnModel',
70             xns: Roo.grid,
71             dataIndex : 'weekday0',
72             header : 'Sunday',
73             //renderer : function(v,x,r) { return _this.grid.cellrenderer(v,x,r); }
74         },
75         {
76             xtype: 'ColumnModel',
77             xns: Roo.grid,
78             dataIndex : 'weekday1',
79             header : 'Monday',
80             //renderer : function(v,x,r) { return _this.grid.cellrenderer(v,x,r); }
81         },
82         {
83             xtype: 'ColumnModel',
84             xns: Roo.grid,
85             dataIndex : 'weekday2',
86             header : 'Tuesday',
87             //renderer : function(v,x,r) { return _this.grid.cellrenderer(v,x,r); }
88         },
89         {
90             xtype: 'ColumnModel',
91             xns: Roo.grid,
92             dataIndex : 'weekday3',
93             header : 'Wednesday',
94             //renderer : function(v,x,r) { return _this.grid.cellrenderer(v,x,r); }
95         },
96         {
97             xtype: 'ColumnModel',
98             xns: Roo.grid,
99             dataIndex : 'weekday4',
100             header : 'Thursday',
101             //renderer : function(v,x,r) { return _this.grid.cellrenderer(v,x,r); }
102         },
103         {
104             xtype: 'ColumnModel',
105             xns: Roo.grid,
106             dataIndex : 'weekday5',
107             header : 'Friday',
108             //renderer : function(v,x,r) { return _this.grid.cellrenderer(v,x,r); }
109         },
110         {
111             xtype: 'ColumnModel',
112             xns: Roo.grid,
113             dataIndex : 'weekday6',
114             header : 'Saturday',
115             //renderer : function(v,x,r) { return _this.grid.cellrenderer(v,x,r); }
116         }
117     ]);
118     this.cm = this.colModel;
119     this.cm.xmodule = this.xmodule || false;
120  
121         
122           
123     //this.selModel = new Roo.grid.CellSelectionModel();
124     //this.sm = this.selModel;
125     //this.selModel.init(this);
126     
127     
128     if(this.width){
129         this.container.setWidth(this.width);
130     }
131
132     if(this.height){
133         this.container.setHeight(this.height);
134     }
135     /** @private */
136         this.addEvents({
137         // raw events
138         /**
139          * @event click
140          * The raw click event for the entire grid.
141          * @param {Roo.EventObject} e
142          */
143         "click" : true,
144         /**
145          * @event dblclick
146          * The raw dblclick event for the entire grid.
147          * @param {Roo.EventObject} e
148          */
149         "dblclick" : true,
150         /**
151          * @event contextmenu
152          * The raw contextmenu event for the entire grid.
153          * @param {Roo.EventObject} e
154          */
155         "contextmenu" : true,
156         /**
157          * @event mousedown
158          * The raw mousedown event for the entire grid.
159          * @param {Roo.EventObject} e
160          */
161         "mousedown" : true,
162         /**
163          * @event mouseup
164          * The raw mouseup event for the entire grid.
165          * @param {Roo.EventObject} e
166          */
167         "mouseup" : true,
168         /**
169          * @event mouseover
170          * The raw mouseover event for the entire grid.
171          * @param {Roo.EventObject} e
172          */
173         "mouseover" : true,
174         /**
175          * @event mouseout
176          * The raw mouseout event for the entire grid.
177          * @param {Roo.EventObject} e
178          */
179         "mouseout" : true,
180         /**
181          * @event keypress
182          * The raw keypress event for the entire grid.
183          * @param {Roo.EventObject} e
184          */
185         "keypress" : true,
186         /**
187          * @event keydown
188          * The raw keydown event for the entire grid.
189          * @param {Roo.EventObject} e
190          */
191         "keydown" : true,
192
193         // custom events
194
195         /**
196          * @event cellclick
197          * Fires when a cell is clicked
198          * @param {Grid} this
199          * @param {Number} rowIndex
200          * @param {Number} columnIndex
201          * @param {Roo.EventObject} e
202          */
203         "cellclick" : true,
204         /**
205          * @event celldblclick
206          * Fires when a cell is double clicked
207          * @param {Grid} this
208          * @param {Number} rowIndex
209          * @param {Number} columnIndex
210          * @param {Roo.EventObject} e
211          */
212         "celldblclick" : true,
213         /**
214          * @event rowclick
215          * Fires when a row is clicked
216          * @param {Grid} this
217          * @param {Number} rowIndex
218          * @param {Roo.EventObject} e
219          */
220         "rowclick" : true,
221         /**
222          * @event rowdblclick
223          * Fires when a row is double clicked
224          * @param {Grid} this
225          * @param {Number} rowIndex
226          * @param {Roo.EventObject} e
227          */
228         "rowdblclick" : true,
229         /**
230          * @event headerclick
231          * Fires when a header is clicked
232          * @param {Grid} this
233          * @param {Number} columnIndex
234          * @param {Roo.EventObject} e
235          */
236         "headerclick" : true,
237         /**
238          * @event headerdblclick
239          * Fires when a header cell is double clicked
240          * @param {Grid} this
241          * @param {Number} columnIndex
242          * @param {Roo.EventObject} e
243          */
244         "headerdblclick" : true,
245         /**
246          * @event rowcontextmenu
247          * Fires when a row is right clicked
248          * @param {Grid} this
249          * @param {Number} rowIndex
250          * @param {Roo.EventObject} e
251          */
252         "rowcontextmenu" : true,
253         /**
254          * @event cellcontextmenu
255          * Fires when a cell is right clicked
256          * @param {Grid} this
257          * @param {Number} rowIndex
258          * @param {Number} cellIndex
259          * @param {Roo.EventObject} e
260          */
261          "cellcontextmenu" : true,
262         /**
263          * @event headercontextmenu
264          * Fires when a header is right clicked
265          * @param {Grid} this
266          * @param {Number} columnIndex
267          * @param {Roo.EventObject} e
268          */
269         "headercontextmenu" : true,
270         /**
271          * @event bodyscroll
272          * Fires when the body element is scrolled
273          * @param {Number} scrollLeft
274          * @param {Number} scrollTop
275          */
276         "bodyscroll" : true,
277         /**
278          * @event columnresize
279          * Fires when the user resizes a column
280          * @param {Number} columnIndex
281          * @param {Number} newSize
282          */
283         "columnresize" : true,
284         /**
285          * @event columnmove
286          * Fires when the user moves a column
287          * @param {Number} oldIndex
288          * @param {Number} newIndex
289          */
290         "columnmove" : true,
291         /**
292          * @event startdrag
293          * Fires when row(s) start being dragged
294          * @param {Grid} this
295          * @param {Roo.GridDD} dd The drag drop object
296          * @param {event} e The raw browser event
297          */
298         "startdrag" : true,
299         /**
300          * @event enddrag
301          * Fires when a drag operation is complete
302          * @param {Grid} this
303          * @param {Roo.GridDD} dd The drag drop object
304          * @param {event} e The raw browser event
305          */
306         "enddrag" : true,
307         /**
308          * @event dragdrop
309          * Fires when dragged row(s) are dropped on a valid DD target
310          * @param {Grid} this
311          * @param {Roo.GridDD} dd The drag drop object
312          * @param {String} targetId The target drag drop object
313          * @param {event} e The raw browser event
314          */
315         "dragdrop" : true,
316         /**
317          * @event dragover
318          * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
319          * @param {Grid} this
320          * @param {Roo.GridDD} dd The drag drop object
321          * @param {String} targetId The target drag drop object
322          * @param {event} e The raw browser event
323          */
324         "dragover" : true,
325         /**
326          * @event dragenter
327          *  Fires when the dragged row(s) first cross another DD target while being dragged
328          * @param {Grid} this
329          * @param {Roo.GridDD} dd The drag drop object
330          * @param {String} targetId The target drag drop object
331          * @param {event} e The raw browser event
332          */
333         "dragenter" : true,
334         /**
335          * @event dragout
336          * Fires when the dragged row(s) leave another DD target while being dragged
337          * @param {Grid} this
338          * @param {Roo.GridDD} dd The drag drop object
339          * @param {String} targetId The target drag drop object
340          * @param {event} e The raw browser event
341          */
342         "dragout" : true,
343         /**
344          * @event rowclass
345          * Fires when a row is rendered, so you can change add a style to it.
346          * @param {GridView} gridview   The grid view
347          * @param {Object} rowcfg   contains record  rowIndex and rowClass - set rowClass to add a style.
348          */
349         'rowclass' : true,
350
351         /**
352          * @event render
353          * Fires when the grid is rendered
354          * @param {Grid} grid
355          */
356         'render' : true,
357             /**
358              * @event select
359              * Fires when a date is selected
360              * @param {DatePicker} this
361              * @param {Date} date The selected date
362              */
363         'select': true,
364         /**
365              * @event monthchange
366              * Fires when the displayed month changes 
367              * @param {DatePicker} this
368              * @param {Date} date The selected month
369              */
370         'monthchange': true,
371         /**
372              * @event evententer
373              * Fires when mouse over an event
374              * @param {Calendar} this
375              * @param {event} Event
376              */
377         'evententer': true,
378         /**
379              * @event eventleave
380              * Fires when the mouse leaves an
381              * @param {Calendar} this
382              * @param {event}
383              */
384         'eventleave': true,
385         /**
386              * @event eventclick
387              * Fires when the mouse click an
388              * @param {Calendar} this
389              * @param {event}
390              */
391         'eventclick': true
392     });
393
394     Roo.grid.Grid.superclass.constructor.call(this);
395     this.on('render', function() {
396               (function() { this.setDate(new Date()); }).defer(100,this); //default today..
397
398     });
399     
400 };
401 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
402     /**
403      * @cfg {Store} eventStore The store that loads events.
404      */
405     eventStore : 25,
406
407     
408     activeDate : false,
409     startDay : 0,
410     autoWidth : true,
411     monitorWindowResize : false,
412
413     
414     resizeColumns : function() {
415         var col = (this.view.el.getWidth() / 7) - 3;
416         // loop through cols, and setWidth
417         for(var i =0 ; i < 7 ; i++){
418             this.cm.setColumnWidth(i, col);
419         }
420     },
421      setDate :function(date) {
422           this.resizeColumns();
423         var vd = this.activeDate;
424         this.activeDate = date;
425 //        if(vd && this.el){
426 //            var t = date.getTime();
427 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
428 //                Roo.log('using add remove');
429 //                
430 //                this.fireEvent('monthchange', this, date);
431 //                
432 //                this.cells.removeClass("fc-state-highlight");
433 //                this.cells.each(function(c){
434 //                   if(c.dateValue == t){
435 //                       c.addClass("fc-state-highlight");
436 //                       setTimeout(function(){
437 //                            try{c.dom.firstChild.focus();}catch(e){}
438 //                       }, 50);
439 //                       return false;
440 //                   }
441 //                   return true;
442 //                });
443 //                return;
444 //            }
445 //        }
446         
447         var days = date.getDaysInMonth();
448         
449         var firstOfMonth = date.getFirstDateOfMonth();
450         var startingPos = firstOfMonth.getDay()-this.startDay;
451         
452         if(startingPos < this.startDay){
453             startingPos += 7;
454         }
455         
456         var pm = date.add(Date.MONTH, -1);
457         var prevStart = pm.getDaysInMonth()-startingPos;
458 //        
459         
460         
461         this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
462         
463         this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
464         //this.cells.addClassOnOver('fc-state-hover');
465         
466         var cells = this.cells.elements;
467         var textEls = this.textNodes;
468         
469         //Roo.each(cells, function(cell){
470         //    cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
471         //});
472         
473         days += startingPos;
474
475         // convert everything to numbers so it's fast
476         var day = 86400000;
477         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
478         //Roo.log(d);
479         //Roo.log(pm);
480         //Roo.log(prevStart);
481         
482         var today = new Date().clearTime().getTime();
483         var sel = date.clearTime().getTime();
484         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
485         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
486         var ddMatch = this.disabledDatesRE;
487         var ddText = this.disabledDatesText;
488         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
489         var ddaysText = this.disabledDaysText;
490         var format = this.format;
491         
492         var setCellClass = function(cal, cell){
493             
494             //Roo.log('set Cell Class');
495             cell.title = "";
496             var t = d.getTime();
497             
498             //Roo.log(d);
499             
500             cell.dateValue = t;
501             if(t == today){
502                // cell.className += " fc-today";
503                // cell.className += " fc-state-highlight";
504                 cell.title = cal.todayText;
505             }
506             if(t == sel){
507                 // disable highlight in other month..
508                 //cell.className += " fc-state-highlight";
509                 
510             }
511             // disabling
512             if(t < min) {
513                 //cell.className = " fc-state-disabled";
514                 cell.title = cal.minText;
515                 return;
516             }
517             if(t > max) {
518                 //cell.className = " fc-state-disabled";
519                 cell.title = cal.maxText;
520                 return;
521             }
522             if(ddays){
523                 if(ddays.indexOf(d.getDay()) != -1){
524                     // cell.title = ddaysText;
525                    // cell.className = " fc-state-disabled";
526                 }
527             }
528             if(ddMatch && format){
529                 var fvalue = d.dateFormat(format);
530                 if(ddMatch.test(fvalue)){
531                     cell.title = ddText.replace("%0", fvalue);
532                    // cell.className = " fc-state-disabled";
533                 }
534             }
535             
536             if (!cell.initialClassName) {
537                 //cell.initialClassName = cell.dom.className;
538             }
539             
540             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
541         };
542
543         var i = 0;
544         
545         for(; i < startingPos; i++) {
546             cells[i].dayName =  (++prevStart);
547             Roo.log(textEls[i]);
548             d.setDate(d.getDate()+1);
549             
550             //cells[i].className = "fc-past fc-other-month";
551             setCellClass(this, cells[i]);
552         }
553         
554         var intDay = 0;
555         
556         for(; i < days; i++){
557             intDay = i - startingPos + 1;
558             cells[i].dayName =  (intDay);
559             d.setDate(d.getDate()+1);
560             
561             cells[i].className = ''; // "x-date-active";
562             setCellClass(this, cells[i]);
563         }
564         var extraDays = 0;
565         
566         for(; i < 42; i++) {
567             //textEls[i].innerHTML = (++extraDays);
568             
569             d.setDate(d.getDate()+1);
570             cells[i].dayName = (++extraDays);
571             cells[i].className = "fc-future fc-other-month";
572             setCellClass(this, cells[i]);
573         }
574         
575         //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
576         
577         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
578         
579         var rows= [];
580         var i =0;
581         for (var r = 0;r < 6;r++) {
582             for (var c =0;c < 7;c++) {
583                 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
584             }
585             
586         }
587         
588         
589         //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
590         //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
591         
592         ////if(totalRows != 6){
593             //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
594            // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
595        // }
596         
597         this.fireEvent('monthchange', this, date);
598         
599         
600     },
601  /**
602      * Returns the grid's SelectionModel.
603      * @return {SelectionModel}
604      */
605     getSelectionModel : function(){
606         if(!this.selModel){
607             this.selModel = new Roo.grid.CellSelectionModel();
608         }
609         return this.selModel;
610     },
611
612     load: function() {
613         this.eventStore.load()
614         
615         
616         
617     }
618     
619     findCell : function(dt) {
620         dt = dt.clearTime().getTime();
621         var ret = false;
622         this.cells.each(function(c){
623             //Roo.log("check " +c.dateValue + '?=' + dt);
624             if(c.dateValue == dt){
625                 ret = c;
626                 return false;
627             }
628             return true;
629         });
630         
631         return ret;
632     },
633     
634     findCells : function(ev) {
635         var s = ev.start_dt.clone().clearTime().getTime();
636        // Roo.log(s);
637         var e= ev.end_dt.clone().clearTime().getTime();
638        // Roo.log(e);
639         var ret = [];
640         this.cells.each(function(c){
641              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
642             
643             if(c.dateValue > e){
644                 return ;
645             }
646             if(c.dateValue < s){
647                 return ;
648             }
649             ret.push(c);
650         });
651         
652         return ret;    
653     },
654     
655     findBestRow: function(cells)
656     {
657         var ret = 0;
658         
659         for (var i =0 ; i < cells.length;i++) {
660             ret  = Math.max(cells[i].rows || 0,ret);
661         }
662         return ret;
663         
664     },
665     
666     
667     addItem : function(ev)
668     {
669         // look for vertical location slot in
670         var cells = this.findCells(ev);
671         
672         ev.row = this.findBestRow(cells);
673         
674         // work out the location.
675         
676         var crow = false;
677         var rows = [];
678         for(var i =0; i < cells.length; i++) {
679             if (!crow) {
680                 crow = {
681                     start : cells[i],
682                     end :  cells[i]
683                 };
684                 continue;
685             }
686             if (crow.start.getY() == cells[i].getY()) {
687                 // on same row.
688                 crow.end = cells[i];
689                 continue;
690             }
691             // different row.
692             rows.push(crow);
693             crow = {
694                 start: cells[i],
695                 end : cells[i]
696             };
697             
698         }
699         
700         rows.push(crow);
701         ev.els = [];
702         ev.rows = rows;
703         ev.cells = cells;
704         for (var i = 0; i < cells.length;i++) {
705             cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
706             
707         }
708         
709         this.calevents.push(ev);
710     },
711     
712     clearEvents: function() {
713         
714         if(!this.calevents){
715             return;
716         }
717         
718         Roo.each(this.cells.elements, function(c){
719             c.rows = 0;
720         });
721         
722         Roo.each(this.calevents, function(e) {
723             Roo.each(e.els, function(el) {
724                 el.un('mouseenter' ,this.onEventEnter, this);
725                 el.un('mouseleave' ,this.onEventLeave, this);
726                 el.remove();
727             },this);
728         },this);
729         
730     },
731     
732     renderEvents: function()
733     {   
734         // first make sure there is enough space..
735         
736         this.cells.each(function(c) {
737         
738             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
739         });
740         
741         for (var e = 0; e < this.calevents.length; e++) {
742             var ev = this.calevents[e];
743             var cells = ev.cells;
744             var rows = ev.rows;
745             
746             for(var i =0; i < rows.length; i++) {
747                 
748                  
749                 // how many rows should it span..
750                 
751                 var  cfg = {
752                     cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
753                     style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
754                     
755                     unselectable : "on",
756                     cn : [
757                         {
758                             cls: 'fc-event-inner',
759                             cn : [
760                                 {
761                                   tag:'span',
762                                   cls: 'fc-event-time',
763                                   html : cells.length > 1 ? '' : ev.start_dt.format('h:ia')
764                                 },
765                                 {
766                                   tag:'span',
767                                   cls: 'fc-event-title',
768                                   html : String.format('{0}', ev.title)
769                                 }
770                                 
771                                 
772                             ]
773                         },
774                         {
775                             cls: 'ui-resizable-handle ui-resizable-e',
776                             html : '&nbsp;&nbsp;&nbsp'
777                         }
778                         
779                     ]
780                 };
781                 if (i == 0) {
782                     cfg.cls += ' fc-event-start';
783                 }
784                 if ((i+1) == rows.length) {
785                     cfg.cls += ' fc-event-end';
786                 }
787                 
788                 var ctr = this.el.select('.fc-event-container',true).first();
789                 var cg = ctr.createChild(cfg);
790                 
791                 cg.on('mouseenter' ,this.onEventEnter, this, ev);
792                 cg.on('mouseleave' ,this.onEventLeave, this, ev);
793                 cg.on('click', this.onEventClick, this, ev);
794                 
795                 ev.els.push(cg);
796                 
797                 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
798                 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
799                 //Roo.log(cg);
800                 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);    
801                 cg.setWidth(ebox.right - sbox.x -2);
802             }
803             
804             
805         }
806         
807     },
808     
809     onEventEnter: function (e, el,event,d) {
810         this.fireEvent('evententer', this, el, event);
811     },
812     
813     onEventLeave: function (e, el,event,d) {
814         this.fireEvent('eventleave', this, el, event);
815     },
816     
817     onEventClick: function (e, el,event,d) {
818         this.fireEvent('eventclick', this, el, event);
819     },
820     
821     onMonthChange: function () {
822         this.store.load();
823     },
824     
825     onLoad: function () {
826         
827         this.clearEvents();
828         //Roo.log('calendar onload');
829 //        
830         this.calevents = [];
831          
832         if(this.store.getCount() > 0){
833             this.store.data.each(function(d){
834                 
835                 
836                 // FIXME..
837                 var add = Roo.apply({}, d.data);
838                 if (typeof(add.end_dt) == 'undefined')  {
839                     Roo.log("Missing End time in calendar data: ");
840                     Roo.log(d);
841                     return;
842                 }
843                 if (typeof(add.start_dt) == 'undefined')  {
844                     Roo.log("Missing Start time in calendar data: ");
845                     Roo.log(d);
846                     return;
847                 }
848                 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
849                 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
850                 add.id = add.id || d.id;
851                 add.title = add.title || '??';
852                 this.addItem(add);
853                 
854                 // other than the 'required' coluns, we should just pass the data from the store.
855                 
856                 
857                /*cal.addItem({
858                     id : d.data.id,
859                     start: new Date(d.data.start_dt),
860                     end : new Date(d.data.end_dt),
861                     time : d.data.start_time,
862                     title : d.data.title,
863                     description : d.data.description,
864                     venue : d.data.venue
865                 });*/
866             },this);
867         }
868         
869         this.renderEvents();
870     }
871     
872
873 });
874 /*
875  grid : {
876                 xtype: 'Grid',
877                 xns: Roo.grid,
878                 listeners : {
879                     render : function ()
880                     {
881                         _this.grid = this;
882                         
883                         if (!this.view.el.hasClass('course-timesheet')) {
884                             this.view.el.addClass('course-timesheet');
885                         }
886                         if (this.tsStyle) {
887                             this.ds.load({});
888                             return; 
889                         }
890                         Roo.log('width');
891                         Roo.log(_this.grid.view.el.getWidth());
892                         
893                         
894                         this.tsStyle =  Roo.util.CSS.createStyleSheet({
895                             '.course-timesheet .x-grid-row' : {
896                                 height: '80px'
897                             },
898                             '.x-grid-row td' : {
899                                 'vertical-align' : 0
900                             },
901                             '.course-edit-link' : {
902                                 'color' : 'blue',
903                                 'text-overflow' : 'ellipsis',
904                                 'overflow' : 'hidden',
905                                 'white-space' : 'nowrap',
906                                 'cursor' : 'pointer'
907                             },
908                             '.sub-link' : {
909                                 'color' : 'green'
910                             },
911                             '.de-act-sup-link' : {
912                                 'color' : 'purple',
913                                 'text-decoration' : 'line-through'
914                             },
915                             '.de-act-link' : {
916                                 'color' : 'red',
917                                 'text-decoration' : 'line-through'
918                             },
919                             '.course-timesheet .course-highlight' : {
920                                 'border-top-style': 'dashed !important',
921                                 'border-bottom-bottom': 'dashed !important'
922                             },
923                             '.course-timesheet .course-item' : {
924                                 'font-family'   : 'tahoma, arial, helvetica',
925                                 'font-size'     : '11px',
926                                 'overflow'      : 'hidden',
927                                 'padding-left'  : '10px',
928                                 'padding-right' : '10px',
929                                 'padding-top' : '10px' 
930                             }
931                             
932                         }, Roo.id());
933                                 this.ds.load({});
934                     }
935                 },
936                 autoWidth : true,
937                 monitorWindowResize : false,
938                 cellrenderer : function(v,x,r)
939                 {
940                     return v;
941                 },
942                 sm : {
943                     xtype: 'CellSelectionModel',
944                     xns: Roo.grid
945                 },
946                 dataSource : {
947                     xtype: 'Store',
948                     xns: Roo.data,
949                     listeners : {
950                         beforeload : function (_self, options)
951                         {
952                             options.params = options.params || {};
953                             options.params._month = _this.monthField.getValue();
954                             options.params.limit = 9999;
955                             options.params['sort'] = 'when_dt';    
956                             options.params['dir'] = 'ASC';    
957                             this.proxy.loadResponse = this.loadResponse;
958                             Roo.log("load?");
959                             //this.addColumns();
960                         },
961                         load : function (_self, records, options)
962                         {
963                             _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
964                                 // if you click on the translation.. you can edit it...
965                                 var el = Roo.get(this);
966                                 var id = el.dom.getAttribute('data-id');
967                                 var d = el.dom.getAttribute('data-date');
968                                 var t = el.dom.getAttribute('data-time');
969                                 //var id = this.child('span').dom.textContent;
970                                 
971                                 //Roo.log(this);
972                                 Pman.Dialog.CourseCalendar.show({
973                                     id : id,
974                                     when_d : d,
975                                     when_t : t,
976                                     productitem_active : id ? 1 : 0
977                                 }, function() {
978                                     _this.grid.ds.load({});
979                                 });
980                            
981                            });
982                            
983                            _this.panel.fireEvent('resize', [ '', '' ]);
984                         }
985                     },
986                     loadResponse : function(o, success, response){
987                             // this is overridden on before load..
988                             
989                             Roo.log("our code?");       
990                             //Roo.log(success);
991                             //Roo.log(response)
992                             delete this.activeRequest;
993                             if(!success){
994                                 this.fireEvent("loadexception", this, o, response);
995                                 o.request.callback.call(o.request.scope, null, o.request.arg, false);
996                                 return;
997                             }
998                             var result;
999                             try {
1000                                 result = o.reader.read(response);
1001                             }catch(e){
1002                                 Roo.log("load exception?");
1003                                 this.fireEvent("loadexception", this, o, response, e);
1004                                 o.request.callback.call(o.request.scope, null, o.request.arg, false);
1005                                 return;
1006                             }
1007                             Roo.log("ready...");        
1008                             // loop through result.records;
1009                             // and set this.tdate[date] = [] << array of records..
1010                             _this.tdata  = {};
1011                             Roo.each(result.records, function(r){
1012                                 //Roo.log(r.data);
1013                                 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
1014                                     _this.tdata[r.data.when_dt.format('j')] = [];
1015                                 }
1016                                 _this.tdata[r.data.when_dt.format('j')].push(r.data);
1017                             });
1018                             
1019                             //Roo.log(_this.tdata);
1020                             
1021                             result.records = [];
1022                             result.totalRecords = 6;
1023                     
1024                             // let's generate some duumy records for the rows.
1025                             //var st = _this.dateField.getValue();
1026                             
1027                             // work out monday..
1028                             //st = st.add(Date.DAY, -1 * st.format('w'));
1029                             
1030                             var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
1031                             
1032                             var firstOfMonth = date.getFirstDayOfMonth();
1033                             var days = date.getDaysInMonth();
1034                             var d = 1;
1035                             var firstAdded = false;
1036                             for (var i = 0; i < result.totalRecords ; i++) {
1037                                 //var d= st.add(Date.DAY, i);
1038                                 var row = {};
1039                                 var added = 0;
1040                                 for(var w = 0 ; w < 7 ; w++){
1041                                     if(!firstAdded && firstOfMonth != w){
1042                                         continue;
1043                                     }
1044                                     if(d > days){
1045                                         continue;
1046                                     }
1047                                     firstAdded = true;
1048                                     var dd = (d > 0 && d < 10) ? "0"+d : d;
1049                                     row['weekday'+w] = String.format(
1050                                                     '<span style="font-size: 16px;"><b>{0}</b></span>'+
1051                                                     '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
1052                                                     d,
1053                                                     date.format('Y-m-')+dd
1054                                                 );
1055                                     added++;
1056                                     if(typeof(_this.tdata[d]) != 'undefined'){
1057                                         Roo.each(_this.tdata[d], function(r){
1058                                             var is_sub = '';
1059                                             var deactive = '';
1060                                             var id = r.id;
1061                                             var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
1062                                             if(r.parent_id*1>0){
1063                                                 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
1064                                                 id = r.parent_id;
1065                                             }
1066                                             if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
1067                                                 deactive = 'de-act-link';
1068                                             }
1069                                             
1070                                             row['weekday'+w] += String.format(
1071                                                     '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
1072                                                     id, //0
1073                                                     r.product_id_name, //1
1074                                                     r.when_dt.format('h:ia'), //2
1075                                                     is_sub, //3
1076                                                     deactive, //4
1077                                                     desc // 5
1078                                             );
1079                                         });
1080                                     }
1081                                     d++;
1082                                 }
1083                                 
1084                                 // only do this if something added..
1085                                 if(added > 0){ 
1086                                     result.records.push(_this.grid.dataSource.reader.newRow(row));
1087                                 }
1088                                 
1089                                 
1090                                 // push it twice. (second one with an hour..
1091                                 
1092                             }
1093                             //Roo.log(result);
1094                             this.fireEvent("load", this, o, o.request.arg);
1095                             o.request.callback.call(o.request.scope, result, o.request.arg, true);
1096                         },
1097                     sortInfo : {field: 'when_dt', direction : 'ASC' },
1098                     proxy : {
1099                         xtype: 'HttpProxy',
1100                         xns: Roo.data,
1101                         method : 'GET',
1102                         url : baseURL + '/Roo/Shop_course.php'
1103                     },
1104                     reader : {
1105                         xtype: 'JsonReader',
1106                         xns: Roo.data,
1107                         id : 'id',
1108                         fields : [
1109                             {
1110                                 'name': 'id',
1111                                 'type': 'int'
1112                             },
1113                             {
1114                                 'name': 'when_dt',
1115                                 'type': 'string'
1116                             },
1117                             {
1118                                 'name': 'end_dt',
1119                                 'type': 'string'
1120                             },
1121                             {
1122                                 'name': 'parent_id',
1123                                 'type': 'int'
1124                             },
1125                             {
1126                                 'name': 'product_id',
1127                                 'type': 'int'
1128                             },
1129                             {
1130                                 'name': 'productitem_id',
1131                                 'type': 'int'
1132                             },
1133                             {
1134                                 'name': 'guid',
1135                                 'type': 'int'
1136                             }
1137                         ]
1138                     }
1139                 },
1140                 toolbar : {
1141                     xtype: 'Toolbar',
1142                     xns: Roo,
1143                     items : [
1144                         {
1145                             xtype: 'Button',
1146                             xns: Roo.Toolbar,
1147                             listeners : {
1148                                 click : function (_self, e)
1149                                 {
1150                                     var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
1151                                     sd.setMonth(sd.getMonth()-1);
1152                                     _this.monthField.setValue(sd.format('Y-m-d'));
1153                                     _this.grid.ds.load({});
1154                                 }
1155                             },
1156                             text : "Back"
1157                         },
1158                         {
1159                             xtype: 'Separator',
1160                             xns: Roo.Toolbar
1161                         },
1162                         {
1163                             xtype: 'MonthField',
1164                             xns: Roo.form,
1165                             listeners : {
1166                                 render : function (_self)
1167                                 {
1168                                     _this.monthField = _self;
1169                                    // _this.monthField.set  today
1170                                 },
1171                                 select : function (combo, date)
1172                                 {
1173                                     _this.grid.ds.load({});
1174                                 }
1175                             },
1176                             value : (function() { return new Date(); })()
1177                         },
1178                         {
1179                             xtype: 'Separator',
1180                             xns: Roo.Toolbar
1181                         },
1182                         {
1183                             xtype: 'TextItem',
1184                             xns: Roo.Toolbar,
1185                             text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
1186                         },
1187                         {
1188                             xtype: 'Fill',
1189                             xns: Roo.Toolbar
1190                         },
1191                         {
1192                             xtype: 'Button',
1193                             xns: Roo.Toolbar,
1194                             listeners : {
1195                                 click : function (_self, e)
1196                                 {
1197                                     var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
1198                                     sd.setMonth(sd.getMonth()+1);
1199                                     _this.monthField.setValue(sd.format('Y-m-d'));
1200                                     _this.grid.ds.load({});
1201                                 }
1202                             },
1203                             text : "Next"
1204                         }
1205                     ]
1206                 },
1207                  
1208             }
1209         };
1210         
1211         */