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