remove debugging code
[roojs1] / roojs-calendar-debug.js
1 /*
2  * - LGPL
3  *
4  * base class for bootstrap elements.
5  * 
6  */
7
8 Roo.bootstrap = Roo.bootstrap || {};
9 /**
10  * @class Roo.bootstrap.Component
11  * @extends Roo.Component
12  * Bootstrap Component base class
13  * @cfg {String} cls css class
14  * @cfg {String} style any extra css
15  * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16  * @cfg {Boolean} can_build_overlaid  True if element can be rebuild from a HTML page
17  * @cfg {string} dataId cutomer id
18  * @cfg {string} name Specifies name attribute
19  * 
20  * @constructor
21  * Do not use directly - it does not do anything..
22  * @param {Object} config The config object
23  */
24
25
26
27 Roo.bootstrap.Component = function(config){
28     Roo.bootstrap.Component.superclass.constructor.call(this, config);
29 };
30
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
32     
33     
34     allowDomMove : false, // to stop relocations in parent onRender...
35     
36     cls : false,
37     
38     style : false,
39     
40     autoCreate : false,
41     
42     initEvents : function() {  },
43     
44     xattr : false,
45     
46     parentId : false,
47     
48     can_build_overlaid : true,
49     
50     dataId : false,
51     
52     name : false,
53     
54     parent: function() {
55         // returns the parent component..
56         return Roo.ComponentMgr.get(this.parentId)
57         
58         
59     },
60     
61     // private
62     onRender : function(ct, position)
63     {
64        // Roo.log("Call onRender: " + this.xtype);
65         
66         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
67         
68         if(this.el){
69             if (this.el.attr('xtype')) {
70                 this.el.attr('xtypex', this.el.attr('xtype'));
71                 this.el.dom.removeAttribute('xtype');
72                 
73                 this.initEvents();
74             }
75             
76             return;
77         }
78         
79          
80         
81         var cfg = Roo.apply({},  this.getAutoCreate());
82         cfg.id = Roo.id();
83         
84         // fill in the extra attributes 
85         if (this.xattr && typeof(this.xattr) =='object') {
86             for (var i in this.xattr) {
87                 cfg[i] = this.xattr[i];
88             }
89         }
90         
91         if(this.dataId){
92             cfg.dataId = this.dataId;
93         }
94         
95         if (this.cls) {
96             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
97         }
98         
99         if (this.style) { // fixme needs to support more complex style data.
100             cfg.style = this.style;
101         }
102         
103         if(this.name){
104             cfg.name = this.name;
105         }
106         
107         this.el = ct.createChild(cfg, position);
108         
109         if(this.tabIndex !== undefined){
110             this.el.dom.setAttribute('tabIndex', this.tabIndex);
111         }
112         this.initEvents();
113         
114         
115     },
116     
117     getChildContainer : function()
118     {
119         return this.el;
120     },
121     
122     
123     addxtype  : function(tree,cntr)
124     {
125         var cn = this;
126         
127         cn = Roo.factory(tree);
128            
129         cn.parentType = this.xtype; //??
130         cn.parentId = this.id;
131         
132         cntr = typeof(cntr == 'undefined' ) ? 'getChildContainer' : cntr;
133         
134         var has_flexy_each =  (typeof(tree['flexy:foreach']) != 'undefined');
135         
136         var has_flexy_if =  (typeof(tree['flexy:if']) != 'undefined');
137         
138         var build_from_html =  Roo.XComponent.build_from_html;
139           
140         var is_body  = (tree.xtype == 'Body') ;
141           
142         var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
143           
144         var self_cntr_el = Roo.get(this[cntr]());
145         
146         if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147             if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148                 return this.addxtypeChild(tree,cntr);
149             }
150             
151             var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
152                 
153             if(echild){
154                 return this.addxtypeChild(Roo.apply({}, tree),cntr);
155             }
156             
157             Roo.log('skipping render');
158             return cn;
159             
160         }
161         
162         var ret = false;
163         
164         while (true) {
165             var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
166             
167             if (!echild) {
168                 break;
169             }
170             
171             if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
172                 break;
173             }
174             
175             ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
176         }
177         return ret;
178     },
179     
180     addxtypeChild : function (tree, cntr)
181     {
182         var cn = this;
183         cntr = typeof(cntr == 'undefined' ) ? 'getChildContainer' : cntr;
184         
185         
186         var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
187                     (typeof(tree['flexy:foreach']) != 'undefined');
188           
189         
190         
191         
192         // render the element if it's not BODY.
193         if (tree.xtype != 'Body') {
194             var test = Roo.factory(tree);
195             cn = Roo.factory(tree);
196            
197             cn.parentType = this.xtype; //??
198             cn.parentId = this.id;
199             
200             var build_from_html =  Roo.XComponent.build_from_html;
201             
202             
203             // does the container contain child eleemnts with 'xtype' attributes.
204             // that match this xtype..
205             // note - when we render we create these as well..
206             // so we should check to see if body has xtype set.
207             if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
208                
209                 var self_cntr_el = Roo.get(this[cntr]());
210                 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
211                 
212                 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
213                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
214                   
215                   
216                   
217                     cn.el = echild;
218                   //  Roo.log("GOT");
219                     //echild.dom.removeAttribute('xtype');
220                 } else {
221                     Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
222                    
223                 }
224             }
225            
226             
227                
228             // if object has flexy:if - then it may or may not be rendered.
229             if (build_from_html && has_flexy && !cn.el &&  cn.can_build_overlaid) {
230                 // skip a flexy if element.
231                 Roo.log('skipping render');
232              } else {
233                  
234                 // actually if flexy:foreach is found, we really want to create 
235                 // multiple copies here...
236                 
237                 cn.render(this[cntr]());
238              }
239             // then add the element..
240         }
241         
242         
243         // handle the kids..
244         
245         var nitems = [];
246         if (typeof (tree.menu) != 'undefined') {
247             tree.menu.parentType = cn.xtype;
248             tree.menu.triggerEl = cn.el;
249             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
250             
251         }
252         
253         if (!tree.items || !tree.items.length) {
254             cn.items = nitems;
255             return cn;
256         }
257         var items = tree.items;
258         delete tree.items;
259         
260         //Roo.log(items.length);
261             // add the items..
262         for(var i =0;i < items.length;i++) {
263             nitems.push(cn.addxtype(Roo.apply({}, items[i])));
264         }
265         
266         cn.items = nitems;
267         
268         return cn;
269     }
270     
271     
272     
273     
274 });
275
276  /*
277  * - LGPL
278  *
279  * based on jquery fullcalendar
280  * 
281  */
282
283 Roo.bootstrap = Roo.bootstrap || {};
284 /**
285  * @class Roo.bootstrap.Calendar
286  * @extends Roo.bootstrap.Component
287  * Bootstrap Calendar class
288     
289  * @constructor
290  * Create a new Container
291  * @param {Object} config The config object
292  */
293
294
295
296 Roo.bootstrap.Calendar = function(config){
297     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
298      this.addEvents({
299         /**
300              * @event select
301              * Fires when a date is selected
302              * @param {DatePicker} this
303              * @param {Date} date The selected date
304              */
305         'select': true,
306         /**
307              * @event monthchange
308              * Fires when the displayed month changes 
309              * @param {DatePicker} this
310              * @param {Date} date The selected month
311              */
312         'monthchange': true,
313         /**
314              * @event evententer
315              * Fires when mouse over an event
316              * @param {Calendar} this
317              * @param {event} Event
318              */
319         'evententer': true,
320         /**
321              * @event eventleave
322              * Fires when the mouse leaves an
323              * @param {Calendar} this
324              * @param {event}
325              */
326         'eventleave': true,
327         /**
328              * @event eventclick
329              * Fires when the mouse click an
330              * @param {Calendar} this
331              * @param {event}
332              */
333         'eventclick': true
334         
335     });
336
337 };
338
339 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
340     
341      /**
342      * @cfg {Number} startDay
343      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
344      */
345     startDay : 0,
346       
347     getAutoCreate : function(){
348         
349         
350         var fc_button = function(name, corner, style, content ) {
351             return Roo.apply({},{
352                 tag : 'span',
353                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
354                          (corner.length ?
355                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
356                             ''
357                         ),
358                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
359                 unselectable: 'on'
360             });
361         };
362         
363         var header = {
364             tag : 'table',
365             cls : 'fc-header',
366             style : 'width:100%',
367             cn : [
368                 {
369                     tag: 'tr',
370                     cn : [
371                         {
372                             tag : 'td',
373                             cls : 'fc-header-left',
374                             cn : [
375                                 fc_button('prev', 'left', 'arrow', '&#8249;' ),
376                                 fc_button('next', 'right', 'arrow', '&#8250;' ),
377                                 { tag: 'span', cls: 'fc-header-space' },
378                                 fc_button('today', 'left right', '', 'today' )  // neds state disabled..
379                                 
380                                 
381                             ]
382                         },
383                         
384                         {
385                             tag : 'td',
386                             cls : 'fc-header-center',
387                             cn : [
388                                 {
389                                     tag: 'span',
390                                     cls: 'fc-header-title',
391                                     cn : {
392                                         tag: 'H2',
393                                         html : 'month / year'
394                                     }
395                                 }
396                                 
397                             ]
398                         },
399                         {
400                             tag : 'td',
401                             cls : 'fc-header-right',
402                             cn : [
403                           /*      fc_button('month', 'left', '', 'month' ),
404                                 fc_button('week', '', '', 'week' ),
405                                 fc_button('day', 'right', '', 'day' )
406                             */    
407                                 
408                             ]
409                         }
410                         
411                     ]
412                 }
413             ]
414         };
415         
416        
417         var cal_heads = function() {
418             var ret = [];
419             // fixme - handle this.
420             
421             for (var i =0; i < Date.dayNames.length; i++) {
422                 var d = Date.dayNames[i];
423                 ret.push({
424                     tag: 'th',
425                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
426                     html : d.substring(0,3)
427                 });
428                 
429             }
430             ret[0].cls += ' fc-first';
431             ret[6].cls += ' fc-last';
432             return ret;
433         };
434         var cal_cell = function(n) {
435             return  {
436                 tag: 'td',
437                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
438                 cn : [
439                     {
440                         cn : [
441                             {
442                                 cls: 'fc-day-number',
443                                 html: 'D'
444                             },
445                             {
446                                 cls: 'fc-day-content',
447                              
448                                 cn : [
449                                      {
450                                         style: 'position: relative;' // height: 17px;
451                                     }
452                                 ]
453                             }
454                             
455                             
456                         ]
457                     }
458                 ]
459                 
460             }
461         };
462         var cal_rows = function() {
463             
464             var ret = []
465             for (var r = 0; r < 6; r++) {
466                 var row= {
467                     tag : 'tr',
468                     cls : 'fc-week',
469                     cn : []
470                 };
471                 
472                 for (var i =0; i < Date.dayNames.length; i++) {
473                     var d = Date.dayNames[i];
474                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
475
476                 }
477                 row.cn[0].cls+=' fc-first';
478                 row.cn[0].cn[0].style = 'min-height:90px';
479                 row.cn[6].cls+=' fc-last';
480                 ret.push(row);
481                 
482             }
483             ret[0].cls += ' fc-first';
484             ret[4].cls += ' fc-prev-last';
485             ret[5].cls += ' fc-last';
486             return ret;
487             
488         };
489         
490         var cal_table = {
491             tag: 'table',
492             cls: 'fc-border-separate',
493             style : 'width:100%',
494             cellspacing  : 0,
495             cn : [
496                 { 
497                     tag: 'thead',
498                     cn : [
499                         { 
500                             tag: 'tr',
501                             cls : 'fc-first fc-last',
502                             cn : cal_heads()
503                         }
504                     ]
505                 },
506                 { 
507                     tag: 'tbody',
508                     cn : cal_rows()
509                 }
510                   
511             ]
512         };
513          
514          var cfg = {
515             cls : 'fc fc-ltr',
516             cn : [
517                 header,
518                 {
519                     cls : 'fc-content',
520                     style : "position: relative;",
521                     cn : [
522                         {
523                             cls : 'fc-view fc-view-month fc-grid',
524                             style : 'position: relative',
525                             unselectable : 'on',
526                             cn : [
527                                 {
528                                     cls : 'fc-event-container',
529                                     style : 'position:absolute;z-index:8;top:0;left:0;'
530                                 },
531                                 cal_table
532                             ]
533                         }
534                     ]
535     
536                 }
537            ] 
538             
539         };
540         
541          
542         
543         return cfg;
544     },
545     
546     
547     initEvents : function()
548     {
549         if(!this.store){
550             throw "can not find store for calendar";
551         }
552         
553         this.store = Roo.factory(this.store, Roo.data);
554         this.store.on('load', this.onLoad, this);
555         
556         this.resize();
557         
558         this.cells = this.el.select('.fc-day',true);
559         //Roo.log(this.cells);
560         this.textNodes = this.el.query('.fc-day-number');
561         this.cells.addClassOnOver('fc-state-hover');
562         
563         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
564         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
565         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
566         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
567         
568         this.on('monthchange', this.onMonthChange, this);
569         
570         this.update(new Date().clearTime());
571     },
572     
573     resize : function() {
574         var sz  = this.el.getSize();
575         
576         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
577         this.el.select('.fc-day-content div',true).setHeight(34);
578     },
579     
580     
581     // private
582     showPrevMonth : function(e){
583         this.update(this.activeDate.add("mo", -1));
584     },
585     showToday : function(e){
586         this.update(new Date().clearTime());
587     },
588     // private
589     showNextMonth : function(e){
590         this.update(this.activeDate.add("mo", 1));
591     },
592
593     // private
594     showPrevYear : function(){
595         this.update(this.activeDate.add("y", -1));
596     },
597
598     // private
599     showNextYear : function(){
600         this.update(this.activeDate.add("y", 1));
601     },
602
603     
604    // private
605     update : function(date)
606     {
607         var vd = this.activeDate;
608         this.activeDate = date;
609 //        if(vd && this.el){
610 //            var t = date.getTime();
611 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
612 //                Roo.log('using add remove');
613 //                
614 //                this.fireEvent('monthchange', this, date);
615 //                
616 //                this.cells.removeClass("fc-state-highlight");
617 //                this.cells.each(function(c){
618 //                   if(c.dateValue == t){
619 //                       c.addClass("fc-state-highlight");
620 //                       setTimeout(function(){
621 //                            try{c.dom.firstChild.focus();}catch(e){}
622 //                       }, 50);
623 //                       return false;
624 //                   }
625 //                   return true;
626 //                });
627 //                return;
628 //            }
629 //        }
630         
631         var days = date.getDaysInMonth();
632         
633         var firstOfMonth = date.getFirstDateOfMonth();
634         var startingPos = firstOfMonth.getDay()-this.startDay;
635         
636         if(startingPos < this.startDay){
637             startingPos += 7;
638         }
639         
640         var pm = date.add(Date.MONTH, -1);
641         var prevStart = pm.getDaysInMonth()-startingPos;
642 //        
643         this.cells = this.el.select('.fc-day',true);
644         this.textNodes = this.el.query('.fc-day-number');
645         this.cells.addClassOnOver('fc-state-hover');
646         
647         var cells = this.cells.elements;
648         var textEls = this.textNodes;
649         
650         Roo.each(cells, function(cell){
651             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
652         });
653         
654         days += startingPos;
655
656         // convert everything to numbers so it's fast
657         var day = 86400000;
658         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
659         //Roo.log(d);
660         //Roo.log(pm);
661         //Roo.log(prevStart);
662         
663         var today = new Date().clearTime().getTime();
664         var sel = date.clearTime().getTime();
665         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
666         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
667         var ddMatch = this.disabledDatesRE;
668         var ddText = this.disabledDatesText;
669         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
670         var ddaysText = this.disabledDaysText;
671         var format = this.format;
672         
673         var setCellClass = function(cal, cell){
674             
675             //Roo.log('set Cell Class');
676             cell.title = "";
677             var t = d.getTime();
678             
679             //Roo.log(d);
680             
681             cell.dateValue = t;
682             if(t == today){
683                 cell.className += " fc-today";
684                 cell.className += " fc-state-highlight";
685                 cell.title = cal.todayText;
686             }
687             if(t == sel){
688                 // disable highlight in other month..
689                 //cell.className += " fc-state-highlight";
690                 
691             }
692             // disabling
693             if(t < min) {
694                 cell.className = " fc-state-disabled";
695                 cell.title = cal.minText;
696                 return;
697             }
698             if(t > max) {
699                 cell.className = " fc-state-disabled";
700                 cell.title = cal.maxText;
701                 return;
702             }
703             if(ddays){
704                 if(ddays.indexOf(d.getDay()) != -1){
705                     cell.title = ddaysText;
706                     cell.className = " fc-state-disabled";
707                 }
708             }
709             if(ddMatch && format){
710                 var fvalue = d.dateFormat(format);
711                 if(ddMatch.test(fvalue)){
712                     cell.title = ddText.replace("%0", fvalue);
713                     cell.className = " fc-state-disabled";
714                 }
715             }
716             
717             if (!cell.initialClassName) {
718                 cell.initialClassName = cell.dom.className;
719             }
720             
721             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
722         };
723
724         var i = 0;
725         
726         for(; i < startingPos; i++) {
727             textEls[i].innerHTML = (++prevStart);
728             d.setDate(d.getDate()+1);
729             
730             cells[i].className = "fc-past fc-other-month";
731             setCellClass(this, cells[i]);
732         }
733         
734         var intDay = 0;
735         
736         for(; i < days; i++){
737             intDay = i - startingPos + 1;
738             textEls[i].innerHTML = (intDay);
739             d.setDate(d.getDate()+1);
740             
741             cells[i].className = ''; // "x-date-active";
742             setCellClass(this, cells[i]);
743         }
744         var extraDays = 0;
745         
746         for(; i < 42; i++) {
747             textEls[i].innerHTML = (++extraDays);
748             d.setDate(d.getDate()+1);
749             
750             cells[i].className = "fc-future fc-other-month";
751             setCellClass(this, cells[i]);
752         }
753         
754         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
755         
756         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
757         
758         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
759         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
760         
761         if(totalRows != 6){
762             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
763             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
764         }
765         
766         this.fireEvent('monthchange', this, date);
767         
768         
769         /*
770         if(!this.internalRender){
771             var main = this.el.dom.firstChild;
772             var w = main.offsetWidth;
773             this.el.setWidth(w + this.el.getBorderWidth("lr"));
774             Roo.fly(main).setWidth(w);
775             this.internalRender = true;
776             // opera does not respect the auto grow header center column
777             // then, after it gets a width opera refuses to recalculate
778             // without a second pass
779             if(Roo.isOpera && !this.secondPass){
780                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
781                 this.secondPass = true;
782                 this.update.defer(10, this, [date]);
783             }
784         }
785         */
786         
787     },
788     
789     findCell : function(dt) {
790         dt = dt.clearTime().getTime();
791         var ret = false;
792         this.cells.each(function(c){
793             //Roo.log("check " +c.dateValue + '?=' + dt);
794             if(c.dateValue == dt){
795                 ret = c;
796                 return false;
797             }
798             return true;
799         });
800         
801         return ret;
802     },
803     
804     findCells : function(ev) {
805         var s = ev.start.clone().clearTime().getTime();
806        // Roo.log(s);
807         var e= ev.end.clone().clearTime().getTime();
808        // Roo.log(e);
809         var ret = [];
810         this.cells.each(function(c){
811              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
812             
813             if(c.dateValue > e){
814                 return ;
815             }
816             if(c.dateValue < s){
817                 return ;
818             }
819             ret.push(c);
820         });
821         
822         return ret;    
823     },
824     
825     findBestRow: function(cells)
826     {
827         var ret = 0;
828         
829         for (var i =0 ; i < cells.length;i++) {
830             ret  = Math.max(cells[i].rows || 0,ret);
831         }
832         return ret;
833         
834     },
835     
836     
837     addItem : function(ev)
838     {
839         // look for vertical location slot in
840         var cells = this.findCells(ev);
841         
842         ev.row = this.findBestRow(cells);
843         
844         // work out the location.
845         
846         var crow = false;
847         var rows = [];
848         for(var i =0; i < cells.length; i++) {
849             if (!crow) {
850                 crow = {
851                     start : cells[i],
852                     end :  cells[i]
853                 };
854                 continue;
855             }
856             if (crow.start.getY() == cells[i].getY()) {
857                 // on same row.
858                 crow.end = cells[i];
859                 continue;
860             }
861             // different row.
862             rows.push(crow);
863             crow = {
864                 start: cells[i],
865                 end : cells[i]
866             };
867             
868         }
869         
870         rows.push(crow);
871         ev.els = [];
872         ev.rows = rows;
873         ev.cells = cells;
874         for (var i = 0; i < cells.length;i++) {
875             cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
876             
877         }
878         
879         this.calevents.push(ev);
880     },
881     
882     clearEvents: function() {
883         
884         if(!this.calevents){
885             return;
886         }
887         
888         Roo.each(this.cells.elements, function(c){
889             c.rows = 0;
890         });
891         
892         Roo.each(this.calevents, function(e) {
893             Roo.each(e.els, function(el) {
894                 el.un('mouseenter' ,this.onEventEnter, this);
895                 el.un('mouseleave' ,this.onEventLeave, this);
896                 el.remove();
897             },this);
898         },this);
899         
900     },
901     
902     renderEvents: function()
903     {   
904         // first make sure there is enough space..
905         
906         this.cells.each(function(c) {
907         
908             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
909         });
910         
911         for (var e = 0; e < this.calevents.length; e++) {
912             var ev = this.calevents[e];
913             var cells = ev.cells;
914             var rows = ev.rows;
915             
916             for(var i =0; i < rows.length; i++) {
917                 
918                  
919                 // how many rows should it span..
920                 
921                 var  cfg = {
922                     cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
923                     style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
924                     
925                     unselectable : "on",
926                     cn : [
927                         {
928                             cls: 'fc-event-inner',
929                             cn : [
930                                 {
931                                   tag:'span',
932                                   cls: 'fc-event-time',
933                                   html : cells.length > 1 ? '' : ev.time
934                                 },
935                                 {
936                                   tag:'span',
937                                   cls: 'fc-event-title',
938                                   html : String.format('{0}', ev.title)
939                                 }
940                                 
941                                 
942                             ]
943                         },
944                         {
945                             cls: 'ui-resizable-handle ui-resizable-e',
946                             html : '&nbsp;&nbsp;&nbsp'
947                         }
948                         
949                     ]
950                 };
951                 if (i == 0) {
952                     cfg.cls += ' fc-event-start';
953                 }
954                 if ((i+1) == rows.length) {
955                     cfg.cls += ' fc-event-end';
956                 }
957                 
958                 var ctr = this.el.select('.fc-event-container',true).first();
959                 var cg = ctr.createChild(cfg);
960                 
961                 cg.on('mouseenter' ,this.onEventEnter, this, ev);
962                 cg.on('mouseleave' ,this.onEventLeave, this, ev);
963                 cg.on('click', this.onEventClick, this, ev);
964                 
965                 ev.els.push(cg);
966                 
967                 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
968                 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
969                 //Roo.log(cg);
970                 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);    
971                 cg.setWidth(ebox.right - sbox.x -2);
972             }
973             
974             
975         }
976         
977     },
978     
979     onEventEnter: function (e, el,event,d) {
980         this.fireEvent('evententer', this, el, event);
981     },
982     
983     onEventLeave: function (e, el,event,d) {
984         this.fireEvent('eventleave', this, el, event);
985     },
986     
987     onEventClick: function (e, el,event,d) {
988         this.fireEvent('eventclick', this, el, event);
989     },
990     
991     onMonthChange: function () {
992         this.store.load();
993     },
994     
995     onLoad: function () {
996         
997         this.clearEvents();
998         //Roo.log('calendar onload');
999 //        
1000         this.calevents = [];
1001         var cal = this;
1002         if(this.store.getCount() > 0){
1003             this.store.data.each(function(d){
1004                cal.addItem({
1005                     id : d.data.id,
1006                     start: new Date(d.data.start_dt),
1007                     end : new Date(d.data.end_dt),
1008                     time : d.data.start_time,
1009                     title : d.data.title,
1010                     description : d.data.description,
1011                     venue : d.data.venue
1012                 });
1013             });
1014         }
1015         
1016         this.renderEvents();
1017     }
1018 });
1019
1020  
1021  /*
1022  * - LGPL
1023  *
1024  * based on jquery fullcalendar
1025  * 
1026  */
1027
1028
1029 /**
1030  * @class Roo.Calendar
1031  * @extends Roo.Component
1032  * Bootstrap Calendar class
1033     
1034  * @constructor
1035  * Create a new Container
1036  * @param {Object} config The config object
1037  */
1038
1039 Roo.CalendarPanel = function(config){
1040     
1041     Roo.log("cal panel ctr");
1042   
1043     this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
1044         {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
1045         
1046     //this.wrapper.dom.appendChild(grid.getGridEl().dom);
1047     
1048     Roo.CalendarPanel.superclass.constructor.call(this, this.wrapper, config);
1049     
1050     Roo.log(this.el);
1051     
1052     if(this.toolbar){
1053         this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
1054     }
1055     // xtype created footer. - not sure if will work as we normally have to render first..
1056     if (this.footer && !this.footer.el && this.footer.xtype) {
1057         
1058         //this.footer.container = this.grid.getView().getFooterPanel(true);
1059         //this.footer.dataSource = this.grid.dataSource;
1060         //this.footer = Roo.factory(this.footer, Roo);
1061         
1062     }
1063     this.view = new Roo.calendar.View(Roo.apply({
1064         skipNavHeader : true,
1065         skipMonthHeader : false
1066         
1067     },config));
1068     
1069      
1070     this.on('activate', function()
1071     {
1072         Roo.log('activate');
1073          
1074         //console.log('render tree');
1075         this.render();
1076     },this);
1077     
1078     this.addEvents({
1079         /**
1080              * @event select
1081              * Fires when a date is selected
1082              * @param {DatePicker} this
1083              * @param {Date} date The selected date
1084              */
1085         'select': true,
1086         /**
1087              * @event monthchange
1088              * Fires when the displayed month changes 
1089              * @param {DatePicker} this
1090              * @param {Date} date The selected month
1091              */
1092         'monthchange': true,
1093         /**
1094              * @event evententer
1095              * Fires when mouse over an event
1096              * @param {Calendar} this
1097              * @param {event} Event
1098              */
1099         'evententer': true,
1100         /**
1101              * @event eventleave
1102              * Fires when the mouse leaves an
1103              * @param {Calendar} this
1104              * @param {event}
1105              */
1106         'eventleave': true,
1107         /**
1108              * @event eventclick
1109              * Fires when the mouse click an
1110              * @param {Calendar} this
1111              * @param {event}
1112              */
1113         'eventclick': true,
1114         /**
1115              * @event rendered
1116              * Fires when the grid is rendered
1117              * @param {Calendar} this
1118             
1119              */
1120         'rendered': true
1121         
1122         
1123     });
1124     this.relayEvents(this.view, ["select","monthchange","evententer","eventleave","rendered"]);
1125
1126     //this.grid = grid;
1127     //this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
1128 };
1129
1130
1131 Roo.extend(Roo.CalendarPanel, Roo.ContentPanel, {
1132     
1133       
1134     render : function()
1135     {
1136         var ct = this.el.appendChild(document.createElement("div"));
1137         this.onRender(this.el, false)
1138     },
1139     
1140     onRender : function(ct, position)
1141     {
1142         if (this.rendered) {
1143             return;
1144         }
1145         this.rendered = true;
1146         
1147         Roo.log("render calendar");
1148         
1149         
1150         //Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1151         
1152         
1153         var cfg = Roo.apply({},  this.view.getAutoCreate());
1154         cfg.id = Roo.id();
1155         
1156         // fill in the extra attributes 
1157         if (this.xattr && typeof(this.xattr) =='object') {
1158             for (var i in this.xattr) {
1159                 cfg[i] = this.xattr[i];
1160             }
1161         }
1162         
1163         if(this.dataId){
1164             cfg.dataId = this.dataId;
1165         }
1166         
1167         if (this.cls) {
1168             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
1169         }
1170         
1171         if (this.style) { // fixme needs to support more complex style data.
1172             cfg.style = this.style;
1173         }
1174         
1175         if(this.name){
1176             cfg.name = this.name;
1177         }
1178         
1179         this.view.el =  ct.createChild(cfg, position);
1180         
1181         //if(this.tabIndex !== undefined){
1182         //    this.el.dom.setAttribute('tabIndex', this.tabIndex);
1183         //}
1184         
1185         
1186         this.view.initEvents();
1187         this.fireEvent('rendered');
1188     }
1189     
1190     
1191     
1192     
1193 });
1194
1195