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