roojs-calendar-debug.js
[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         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     
1064     this.on('activate', function()
1065     {
1066         Roo.log('activate');
1067          
1068         //console.log('render tree');
1069         this.render();
1070     },this);
1071     
1072     this.addEvents({
1073         /**
1074              * @event select
1075              * Fires when a date is selected
1076              * @param {DatePicker} this
1077              * @param {Date} date The selected date
1078              */
1079         'select': true,
1080         /**
1081              * @event monthchange
1082              * Fires when the displayed month changes 
1083              * @param {DatePicker} this
1084              * @param {Date} date The selected month
1085              */
1086         'monthchange': true,
1087         /**
1088              * @event evententer
1089              * Fires when mouse over an event
1090              * @param {Calendar} this
1091              * @param {event} Event
1092              */
1093         'evententer': true,
1094         /**
1095              * @event eventleave
1096              * Fires when the mouse leaves an
1097              * @param {Calendar} this
1098              * @param {event}
1099              */
1100         'eventleave': true,
1101         /**
1102              * @event eventclick
1103              * Fires when the mouse click an
1104              * @param {Calendar} this
1105              * @param {event}
1106              */
1107         'eventclick': true,
1108         /**
1109              * @event rendered
1110              * Fires when the grid is rendered
1111              * @param {Calendar} this
1112             
1113              */
1114         'rendered': true
1115         
1116         
1117     });
1118     
1119     //this.grid = grid;
1120     //this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
1121 };
1122
1123
1124 Roo.extend(Roo.CalendarPanel, Roo.ContentPanel, {
1125     
1126     startDay : 0,
1127     
1128     getId : function(){
1129         return this.id;
1130     },
1131     /*
1132     setSize : function(width, height){
1133         if(!this.ignoreResize(width, height)){
1134             var grid = this.grid;
1135             var size = this.adjustForComponents(width, height);
1136             grid.getGridEl().setSize(size.width, size.height);
1137             grid.autoSize();
1138         }
1139     },
1140     
1141     beforeSlide : function(){
1142         this.grid.getView().scroller.clip();
1143     },
1144     
1145     afterSlide : function(){
1146         this.grid.getView().scroller.unclip();
1147     },
1148     */
1149     destroy : function(){
1150       //  this.grid.destroy();
1151        // delete this.grid;
1152         Roo.GridPanel.superclass.destroy.call(this);
1153          
1154     },
1155     render : function()
1156     {
1157         this.onRender(this.el, false)
1158     },
1159     
1160     onRender : function(ct, position)
1161     {
1162         if (this.rendered) {
1163             return;
1164         }
1165         this.rendered = true;
1166         
1167         Roo.log("render calendar");
1168         
1169         //Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1170         
1171         
1172         var cfg = Roo.apply({},  this.getAutoCreate());
1173         cfg.id = Roo.id();
1174         
1175         // fill in the extra attributes 
1176         if (this.xattr && typeof(this.xattr) =='object') {
1177             for (var i in this.xattr) {
1178                 cfg[i] = this.xattr[i];
1179             }
1180         }
1181         
1182         if(this.dataId){
1183             cfg.dataId = this.dataId;
1184         }
1185         
1186         if (this.cls) {
1187             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
1188         }
1189         
1190         if (this.style) { // fixme needs to support more complex style data.
1191             cfg.style = this.style;
1192         }
1193         
1194         if(this.name){
1195             cfg.name = this.name;
1196         }
1197         
1198         this.el = ct.createChild(cfg, position);
1199         
1200         if(this.tabIndex !== undefined){
1201             this.el.dom.setAttribute('tabIndex', this.tabIndex);
1202         }
1203         
1204         
1205         this.initEvents();
1206         this.fireEvent('rendered');
1207     }
1208     
1209     
1210     
1211     
1212 });
1213
1214
1215
1216 Roo.each([
1217     'getAutoCreate',
1218     'initEvents',
1219     'resize',
1220     'showPrevMonth',
1221     'showToday',
1222     'showNextMonth',
1223     'showPrevYear',
1224     'showNextYear',
1225     'update',
1226     'findCell',
1227     'findCells',
1228     'findBestRow',
1229     'addItem',
1230     'clearEvents',
1231     'renderEvents',
1232     'onEventEnter',
1233     'onEventLeave',
1234     'onEventClick',
1235     'onMonthChange',
1236     'onLoad'
1237
1238     
1239 ], function(p) {
1240     Roo.log('add' + p);
1241     Roo.CalendarPanel.prototype[p] = Roo.bootstrap.Calendar.prototype[p];
1242  
1243 });