Changed docs/src/Roo_htmleditor_FilterWord.js.html
[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  * @abstract
13  * @children Roo.bootstrap.Component
14  * Bootstrap Component base class
15  * @cfg {String} cls css class
16  * @cfg {String} style any extra css
17  * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
18  * @cfg {Boolean} can_build_overlaid  True if element can be rebuild from a HTML page
19  * @cfg {string} dataId cutomer id
20  * @cfg {string} name Specifies name attribute
21  * @cfg {string} tooltip  Text for the tooltip
22  * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar -  getHeaderChildContainer)
23  * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
24  
25  * @constructor
26  * Do not use directly - it does not do anything..
27  * @param {Object} config The config object
28  */
29
30
31
32 Roo.bootstrap.Component = function(config){
33     Roo.bootstrap.Component.superclass.constructor.call(this, config);
34        
35     this.addEvents({
36         /**
37          * @event childrenrendered
38          * Fires when the children have been rendered..
39          * @param {Roo.bootstrap.Component} this
40          */
41         "childrenrendered" : true
42         
43         
44         
45     });
46     
47     
48 };
49
50 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent,  {
51     
52     
53     allowDomMove : false, // to stop relocations in parent onRender...
54     
55     cls : false,
56     
57     style : false,
58     
59     autoCreate : false,
60     
61     tooltip : null,
62     /**
63      * Initialize Events for the element
64      */
65     initEvents : function() { },
66     
67     xattr : false,
68     
69     parentId : false,
70     
71     can_build_overlaid : true,
72     
73     container_method : false,
74     
75     dataId : false,
76     
77     name : false,
78     
79     parent: function() {
80         // returns the parent component..
81         return Roo.ComponentMgr.get(this.parentId)
82         
83         
84     },
85     
86     // private
87     onRender : function(ct, position)
88     {
89        // Roo.log("Call onRender: " + this.xtype);
90         
91         Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
92         
93         if(this.el){
94             if (this.el.attr('xtype')) {
95                 this.el.attr('xtypex', this.el.attr('xtype'));
96                 this.el.dom.removeAttribute('xtype');
97                 
98                 this.initEvents();
99             }
100             
101             return;
102         }
103         
104          
105         
106         var cfg = Roo.apply({},  this.getAutoCreate());
107         
108         cfg.id = this.id || Roo.id();
109         
110         // fill in the extra attributes 
111         if (this.xattr && typeof(this.xattr) =='object') {
112             for (var i in this.xattr) {
113                 cfg[i] = this.xattr[i];
114             }
115         }
116         
117         if(this.dataId){
118             cfg.dataId = this.dataId;
119         }
120         
121         if (this.cls) {
122             cfg.cls = (typeof(cfg.cls) == 'undefined' ? this.cls : cfg.cls) + ' ' + this.cls;
123         }
124         
125         if (this.style) { // fixme needs to support more complex style data.
126             cfg.style = (typeof(cfg.style) == 'undefined' ? this.style : cfg.style) + '; ' + this.style;
127         }
128         
129         if(this.name){
130             cfg.name = this.name;
131         }
132         
133         this.el = ct.createChild(cfg, position);
134         
135         if (this.tooltip) {
136             this.tooltipEl().attr('tooltip', this.tooltip);
137         }
138         
139         if(this.tabIndex !== undefined){
140             this.el.dom.setAttribute('tabIndex', this.tabIndex);
141         }
142         
143         this.initEvents();
144         
145     },
146     /**
147      * Fetch the element to add children to
148      * @return {Roo.Element} defaults to this.el
149      */
150     getChildContainer : function()
151     {
152         return this.el;
153     },
154     getDocumentBody : function() // used by menus - as they are attached to the body so zIndexes work
155     {
156         return Roo.get(document.body);
157     },
158     
159     /**
160      * Fetch the element to display the tooltip on.
161      * @return {Roo.Element} defaults to this.el
162      */
163     tooltipEl : function()
164     {
165         return this.el;
166     },
167         
168     addxtype  : function(tree,cntr)
169     {
170         var cn = this;
171         
172         cn = Roo.factory(tree);
173         //Roo.log(['addxtype', cn]);
174            
175         cn.parentType = this.xtype; //??
176         cn.parentId = this.id;
177         
178         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
179         if (typeof(cn.container_method) == 'string') {
180             cntr = cn.container_method;
181         }
182         
183         
184         var has_flexy_each =  (typeof(tree['flexy:foreach']) != 'undefined');
185         
186         var has_flexy_if =  (typeof(tree['flexy:if']) != 'undefined');
187         
188         var build_from_html =  Roo.XComponent.build_from_html;
189           
190         var is_body  = (tree.xtype == 'Body') ;
191           
192         var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
193           
194         var self_cntr_el = Roo.get(this[cntr](false));
195         
196         // do not try and build conditional elements 
197         if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
198             return false;
199         }
200         
201         if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
202             if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
203                 return this.addxtypeChild(tree,cntr, is_body);
204             }
205             
206             var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
207                 
208             if(echild){
209                 return this.addxtypeChild(Roo.apply({}, tree),cntr);
210             }
211             
212             Roo.log('skipping render');
213             return cn;
214             
215         }
216         
217         var ret = false;
218         if (!build_from_html) {
219             return false;
220         }
221         
222         // this i think handles overlaying multiple children of the same type
223         // with the sam eelement.. - which might be buggy..
224         while (true) {
225             var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
226             
227             if (!echild) {
228                 break;
229             }
230             
231             if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
232                 break;
233             }
234             
235             ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
236         }
237        
238         return ret;
239     },
240     
241     
242     addxtypeChild : function (tree, cntr, is_body)
243     {
244         Roo.debug && Roo.log('addxtypeChild:' + cntr);
245         var cn = this;
246         cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
247         
248         
249         var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
250                     (typeof(tree['flexy:foreach']) != 'undefined');
251           
252     
253         
254         skip_children = false;
255         // render the element if it's not BODY.
256         if (!is_body) {
257             
258             // if parent was disabled, then do not try and create the children..
259             if(!this[cntr](true)){
260                 tree.items = [];
261                 return tree;
262             }
263            
264             cn = Roo.factory(tree);
265            
266             cn.parentType = this.xtype; //??
267             cn.parentId = this.id;
268             
269             var build_from_html =  Roo.XComponent.build_from_html;
270             
271             
272             // does the container contain child eleemnts with 'xtype' attributes.
273             // that match this xtype..
274             // note - when we render we create these as well..
275             // so we should check to see if body has xtype set.
276             if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
277                
278                 var self_cntr_el = Roo.get(this[cntr](false));
279                 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
280                 if (echild) { 
281                     //Roo.log(Roo.XComponent.build_from_html);
282                     //Roo.log("got echild:");
283                     //Roo.log(echild);
284                 }
285                 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
286                 // and are not displayed -this causes this to use up the wrong element when matching.
287                 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
288                 
289                 
290                 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
291                   //  Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
292                   
293                   
294                   
295                     cn.el = echild;
296                   //  Roo.log("GOT");
297                     //echild.dom.removeAttribute('xtype');
298                 } else {
299                     Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
300                     Roo.debug && Roo.log(self_cntr_el);
301                     Roo.debug && Roo.log(echild);
302                     Roo.debug && Roo.log(cn);
303                 }
304             }
305            
306             
307            
308             // if object has flexy:if - then it may or may not be rendered.
309             if (build_from_html && has_flexy && !cn.el &&  cn.can_build_overlaid) {
310                 // skip a flexy if element.
311                 Roo.debug && Roo.log('skipping render');
312                 Roo.debug && Roo.log(tree);
313                 if (!cn.el) {
314                     Roo.debug && Roo.log('skipping all children');
315                     skip_children = true;
316                 }
317                 
318              } else {
319                  
320                 // actually if flexy:foreach is found, we really want to create 
321                 // multiple copies here...
322                 //Roo.log('render');
323                 //Roo.log(this[cntr]());
324                 // some elements do not have render methods.. like the layouts...
325                 /*
326                 if(this[cntr](true) === false){
327                     cn.items = [];
328                     return cn;
329                 }
330                 */
331                 cn.render && cn.render(this[cntr](true));
332                 
333              }
334             // then add the element..
335         }
336          
337         // handle the kids..
338         
339         var nitems = [];
340         /*
341         if (typeof (tree.menu) != 'undefined') {
342             tree.menu.parentType = cn.xtype;
343             tree.menu.triggerEl = cn.el;
344             nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
345             
346         }
347         */
348         if (!tree.items || !tree.items.length) {
349             cn.items = nitems;
350             //Roo.log(["no children", this]);
351             
352             return cn;
353         }
354          
355         var items = tree.items;
356         delete tree.items;
357         
358         //Roo.log(items.length);
359             // add the items..
360         if (!skip_children) {    
361             for(var i =0;i < items.length;i++) {
362               //  Roo.log(['add child', items[i]]);
363                 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
364             }
365         }
366         
367         cn.items = nitems;
368         
369         //Roo.log("fire childrenrendered");
370         
371         cn.fireEvent('childrenrendered', this);
372         
373         return cn;
374     },
375     
376     /**
377      * Set the element that will be used to show or hide
378      */
379     setVisibilityEl : function(el)
380     {
381         this.visibilityEl = el;
382     },
383     
384      /**
385      * Get the element that will be used to show or hide
386      */
387     getVisibilityEl : function()
388     {
389         if (typeof(this.visibilityEl) == 'object') {
390             return this.visibilityEl;
391         }
392         
393         if (typeof(this.visibilityEl) == 'string') {
394             return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
395         }
396         
397         return this.getEl();
398     },
399     
400     /**
401      * Show a component - removes 'hidden' class
402      */
403     show : function()
404     {
405         if(!this.getVisibilityEl()){
406             return;
407         }
408          
409         this.getVisibilityEl().removeClass(['hidden','d-none']);
410         
411         this.fireEvent('show', this);
412         
413         
414     },
415     /**
416      * Hide a component - adds 'hidden' class
417      */
418     hide: function()
419     {
420         if(!this.getVisibilityEl()){
421             return;
422         }
423         
424         this.getVisibilityEl().addClass(['hidden','d-none']);
425         
426         this.fireEvent('hide', this);
427         
428     }
429 });
430
431  /*
432  * - LGPL
433  *
434  * based on jquery fullcalendar
435  * 
436  */
437
438 Roo.bootstrap = Roo.bootstrap || {};
439 /**
440  * @class Roo.bootstrap.Calendar
441  * @extends Roo.bootstrap.Component
442  * Bootstrap Calendar class
443  * @cfg {Boolean} loadMask (true|false) default false
444  * @cfg {Object} header generate the user specific header of the calendar, default false
445
446  * @constructor
447  * Create a new Container
448  * @param {Object} config The config object
449  */
450
451
452
453 Roo.bootstrap.Calendar = function(config){
454     Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
455      this.addEvents({
456         /**
457              * @event select
458              * Fires when a date is selected
459              * @param {DatePicker} this
460              * @param {Date} date The selected date
461              */
462         'select': true,
463         /**
464              * @event monthchange
465              * Fires when the displayed month changes 
466              * @param {DatePicker} this
467              * @param {Date} date The selected month
468              */
469         'monthchange': true,
470         /**
471              * @event evententer
472              * Fires when mouse over an event
473              * @param {Calendar} this
474              * @param {event} Event
475              */
476         'evententer': true,
477         /**
478              * @event eventleave
479              * Fires when the mouse leaves an
480              * @param {Calendar} this
481              * @param {event}
482              */
483         'eventleave': true,
484         /**
485              * @event eventclick
486              * Fires when the mouse click an
487              * @param {Calendar} this
488              * @param {event}
489              */
490         'eventclick': true
491         
492     });
493
494 };
495
496 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component,  {
497     
498           /**
499      * @cfg {Roo.data.Store} store
500      * The data source for the calendar
501      */
502         store : false,
503      /**
504      * @cfg {Number} startDay
505      * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
506      */
507     startDay : 0,
508     
509     loadMask : false,
510     
511     header : false,
512       
513     getAutoCreate : function(){
514         
515         
516         var fc_button = function(name, corner, style, content ) {
517             return Roo.apply({},{
518                 tag : 'span',
519                 cls : 'fc-button fc-button-'+name+' fc-state-default ' + 
520                          (corner.length ?
521                             'fc-corner-' + corner.split(' ').join(' fc-corner-') :
522                             ''
523                         ),
524                 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
525                 unselectable: 'on'
526             });
527         };
528         
529         var header = {};
530         
531         if(!this.header){
532             header = {
533                 tag : 'table',
534                 cls : 'fc-header',
535                 style : 'width:100%',
536                 cn : [
537                     {
538                         tag: 'tr',
539                         cn : [
540                             {
541                                 tag : 'td',
542                                 cls : 'fc-header-left',
543                                 cn : [
544                                     fc_button('prev', 'left', 'arrow', '&#8249;' ),
545                                     fc_button('next', 'right', 'arrow', '&#8250;' ),
546                                     { tag: 'span', cls: 'fc-header-space' },
547                                     fc_button('today', 'left right', '', 'today' )  // neds state disabled..
548
549
550                                 ]
551                             },
552
553                             {
554                                 tag : 'td',
555                                 cls : 'fc-header-center',
556                                 cn : [
557                                     {
558                                         tag: 'span',
559                                         cls: 'fc-header-title',
560                                         cn : {
561                                             tag: 'H2',
562                                             html : 'month / year'
563                                         }
564                                     }
565
566                                 ]
567                             },
568                             {
569                                 tag : 'td',
570                                 cls : 'fc-header-right',
571                                 cn : [
572                               /*      fc_button('month', 'left', '', 'month' ),
573                                     fc_button('week', '', '', 'week' ),
574                                     fc_button('day', 'right', '', 'day' )
575                                 */    
576
577                                 ]
578                             }
579
580                         ]
581                     }
582                 ]
583             };
584         }
585         
586         header = this.header;
587         
588        
589         var cal_heads = function() {
590             var ret = [];
591             // fixme - handle this.
592             
593             for (var i =0; i < Date.dayNames.length; i++) {
594                 var d = Date.dayNames[i];
595                 ret.push({
596                     tag: 'th',
597                     cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
598                     html : d.substring(0,3)
599                 });
600                 
601             }
602             ret[0].cls += ' fc-first';
603             ret[6].cls += ' fc-last';
604             return ret;
605         };
606         var cal_cell = function(n) {
607             return  {
608                 tag: 'td',
609                 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
610                 cn : [
611                     {
612                         cn : [
613                             {
614                                 cls: 'fc-day-number',
615                                 html: 'D'
616                             },
617                             {
618                                 cls: 'fc-day-content',
619                              
620                                 cn : [
621                                      {
622                                         style: 'position: relative;' // height: 17px;
623                                     }
624                                 ]
625                             }
626                             
627                             
628                         ]
629                     }
630                 ]
631                 
632             }
633         };
634         var cal_rows = function() {
635             
636             var ret = [];
637             for (var r = 0; r < 6; r++) {
638                 var row= {
639                     tag : 'tr',
640                     cls : 'fc-week',
641                     cn : []
642                 };
643                 
644                 for (var i =0; i < Date.dayNames.length; i++) {
645                     var d = Date.dayNames[i];
646                     row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
647
648                 }
649                 row.cn[0].cls+=' fc-first';
650                 row.cn[0].cn[0].style = 'min-height:90px';
651                 row.cn[6].cls+=' fc-last';
652                 ret.push(row);
653                 
654             }
655             ret[0].cls += ' fc-first';
656             ret[4].cls += ' fc-prev-last';
657             ret[5].cls += ' fc-last';
658             return ret;
659             
660         };
661         
662         var cal_table = {
663             tag: 'table',
664             cls: 'fc-border-separate',
665             style : 'width:100%',
666             cellspacing  : 0,
667             cn : [
668                 { 
669                     tag: 'thead',
670                     cn : [
671                         { 
672                             tag: 'tr',
673                             cls : 'fc-first fc-last',
674                             cn : cal_heads()
675                         }
676                     ]
677                 },
678                 { 
679                     tag: 'tbody',
680                     cn : cal_rows()
681                 }
682                   
683             ]
684         };
685          
686          var cfg = {
687             cls : 'fc fc-ltr',
688             cn : [
689                 header,
690                 {
691                     cls : 'fc-content',
692                     style : "position: relative;",
693                     cn : [
694                         {
695                             cls : 'fc-view fc-view-month fc-grid',
696                             style : 'position: relative',
697                             unselectable : 'on',
698                             cn : [
699                                 {
700                                     cls : 'fc-event-container',
701                                     style : 'position:absolute;z-index:8;top:0;left:0;'
702                                 },
703                                 cal_table
704                             ]
705                         }
706                     ]
707     
708                 }
709            ] 
710             
711         };
712         
713          
714         
715         return cfg;
716     },
717     
718     
719     initEvents : function()
720     {
721         if(!this.store){
722             throw "can not find store for calendar";
723         }
724         
725         var mark = {
726             tag: "div",
727             cls:"x-dlg-mask",
728             style: "text-align:center",
729             cn: [
730                 {
731                     tag: "div",
732                     style: "background-color:white;width:50%;margin:250 auto",
733                     cn: [
734                         {
735                             tag: "img",
736                             src: Roo.rootURL + '/images/ux/lightbox/loading.gif' 
737                         },
738                         {
739                             tag: "span",
740                             html: "Loading"
741                         }
742                         
743                     ]
744                 }
745             ]
746         };
747         this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
748         
749         var size = this.el.select('.fc-content', true).first().getSize();
750         this.maskEl.setSize(size.width, size.height);
751         this.maskEl.enableDisplayMode("block");
752         if(!this.loadMask){
753             this.maskEl.hide();
754         }
755         
756         this.store = Roo.factory(this.store, Roo.data);
757         this.store.on('load', this.onLoad, this);
758         this.store.on('beforeload', this.onBeforeLoad, this);
759         
760         this.resize();
761         
762         this.cells = this.el.select('.fc-day',true);
763         //Roo.log(this.cells);
764         this.textNodes = this.el.query('.fc-day-number');
765         this.cells.addClassOnOver('fc-state-hover');
766         
767         this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
768         this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
769         this.el.select('.fc-button-today',true).on('click', this.showToday, this);
770         this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
771         
772         this.on('monthchange', this.onMonthChange, this);
773         
774         this.update(new Date().clearTime());
775     },
776     
777     resize : function() {
778         var sz  = this.el.getSize();
779         
780         this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
781         this.el.select('.fc-day-content div',true).setHeight(34);
782     },
783     
784     
785     // private
786     showPrevMonth : function(e){
787         this.update(this.activeDate.add("mo", -1));
788     },
789     showToday : function(e){
790         this.update(new Date().clearTime());
791     },
792     // private
793     showNextMonth : function(e){
794         this.update(this.activeDate.add("mo", 1));
795     },
796
797     // private
798     showPrevYear : function(){
799         this.update(this.activeDate.add("y", -1));
800     },
801
802     // private
803     showNextYear : function(){
804         this.update(this.activeDate.add("y", 1));
805     },
806
807     
808    // private
809     update : function(date)
810     {
811         var vd = this.activeDate;
812         this.activeDate = date;
813 //        if(vd && this.el){
814 //            var t = date.getTime();
815 //            if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
816 //                Roo.log('using add remove');
817 //                
818 //                this.fireEvent('monthchange', this, date);
819 //                
820 //                this.cells.removeClass("fc-state-highlight");
821 //                this.cells.each(function(c){
822 //                   if(c.dateValue == t){
823 //                       c.addClass("fc-state-highlight");
824 //                       setTimeout(function(){
825 //                            try{c.dom.firstChild.focus();}catch(e){}
826 //                       }, 50);
827 //                       return false;
828 //                   }
829 //                   return true;
830 //                });
831 //                return;
832 //            }
833 //        }
834         
835         var days = date.getDaysInMonth();
836         
837         var firstOfMonth = date.getFirstDateOfMonth();
838         var startingPos = firstOfMonth.getDay()-this.startDay;
839         
840         if(startingPos < this.startDay){
841             startingPos += 7;
842         }
843         
844         var pm = date.add(Date.MONTH, -1);
845         var prevStart = pm.getDaysInMonth()-startingPos;
846 //        
847         this.cells = this.el.select('.fc-day',true);
848         this.textNodes = this.el.query('.fc-day-number');
849         this.cells.addClassOnOver('fc-state-hover');
850         
851         var cells = this.cells.elements;
852         var textEls = this.textNodes;
853         
854         Roo.each(cells, function(cell){
855             cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
856         });
857         
858         days += startingPos;
859
860         // convert everything to numbers so it's fast
861         var day = 86400000;
862         var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
863         //Roo.log(d);
864         //Roo.log(pm);
865         //Roo.log(prevStart);
866         
867         var today = new Date().clearTime().getTime();
868         var sel = date.clearTime().getTime();
869         var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
870         var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
871         var ddMatch = this.disabledDatesRE;
872         var ddText = this.disabledDatesText;
873         var ddays = this.disabledDays ? this.disabledDays.join("") : false;
874         var ddaysText = this.disabledDaysText;
875         var format = this.format;
876         
877         var setCellClass = function(cal, cell){
878             cell.row = 0;
879             cell.events = [];
880             cell.more = [];
881             //Roo.log('set Cell Class');
882             cell.title = "";
883             var t = d.getTime();
884             
885             //Roo.log(d);
886             
887             cell.dateValue = t;
888             if(t == today){
889                 cell.className += " fc-today";
890                 cell.className += " fc-state-highlight";
891                 cell.title = cal.todayText;
892             }
893             if(t == sel){
894                 // disable highlight in other month..
895                 //cell.className += " fc-state-highlight";
896                 
897             }
898             // disabling
899             if(t < min) {
900                 cell.className = " fc-state-disabled";
901                 cell.title = cal.minText;
902                 return;
903             }
904             if(t > max) {
905                 cell.className = " fc-state-disabled";
906                 cell.title = cal.maxText;
907                 return;
908             }
909             if(ddays){
910                 if(ddays.indexOf(d.getDay()) != -1){
911                     cell.title = ddaysText;
912                     cell.className = " fc-state-disabled";
913                 }
914             }
915             if(ddMatch && format){
916                 var fvalue = d.dateFormat(format);
917                 if(ddMatch.test(fvalue)){
918                     cell.title = ddText.replace("%0", fvalue);
919                     cell.className = " fc-state-disabled";
920                 }
921             }
922             
923             if (!cell.initialClassName) {
924                 cell.initialClassName = cell.dom.className;
925             }
926             
927             cell.dom.className = cell.initialClassName  + ' ' +  cell.className;
928         };
929
930         var i = 0;
931         
932         for(; i < startingPos; i++) {
933             textEls[i].innerHTML = (++prevStart);
934             d.setDate(d.getDate()+1);
935             
936             cells[i].className = "fc-past fc-other-month";
937             setCellClass(this, cells[i]);
938         }
939         
940         var intDay = 0;
941         
942         for(; i < days; i++){
943             intDay = i - startingPos + 1;
944             textEls[i].innerHTML = (intDay);
945             d.setDate(d.getDate()+1);
946             
947             cells[i].className = ''; // "x-date-active";
948             setCellClass(this, cells[i]);
949         }
950         var extraDays = 0;
951         
952         for(; i < 42; i++) {
953             textEls[i].innerHTML = (++extraDays);
954             d.setDate(d.getDate()+1);
955             
956             cells[i].className = "fc-future fc-other-month";
957             setCellClass(this, cells[i]);
958         }
959         
960         this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
961         
962         var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
963         
964         this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
965         this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
966         
967         if(totalRows != 6){
968             this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
969             this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
970         }
971         
972         this.fireEvent('monthchange', this, date);
973         
974         
975         /*
976         if(!this.internalRender){
977             var main = this.el.dom.firstChild;
978             var w = main.offsetWidth;
979             this.el.setWidth(w + this.el.getBorderWidth("lr"));
980             Roo.fly(main).setWidth(w);
981             this.internalRender = true;
982             // opera does not respect the auto grow header center column
983             // then, after it gets a width opera refuses to recalculate
984             // without a second pass
985             if(Roo.isOpera && !this.secondPass){
986                 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
987                 this.secondPass = true;
988                 this.update.defer(10, this, [date]);
989             }
990         }
991         */
992         
993     },
994     
995     findCell : function(dt) {
996         dt = dt.clearTime().getTime();
997         var ret = false;
998         this.cells.each(function(c){
999             //Roo.log("check " +c.dateValue + '?=' + dt);
1000             if(c.dateValue == dt){
1001                 ret = c;
1002                 return false;
1003             }
1004             return true;
1005         });
1006         
1007         return ret;
1008     },
1009     
1010     findCells : function(ev) {
1011         var s = ev.start.clone().clearTime().getTime();
1012        // Roo.log(s);
1013         var e= ev.end.clone().clearTime().getTime();
1014        // Roo.log(e);
1015         var ret = [];
1016         this.cells.each(function(c){
1017              ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
1018             
1019             if(c.dateValue > e){
1020                 return ;
1021             }
1022             if(c.dateValue < s){
1023                 return ;
1024             }
1025             ret.push(c);
1026         });
1027         
1028         return ret;    
1029     },
1030     
1031 //    findBestRow: function(cells)
1032 //    {
1033 //        var ret = 0;
1034 //        
1035 //        for (var i =0 ; i < cells.length;i++) {
1036 //            ret  = Math.max(cells[i].rows || 0,ret);
1037 //        }
1038 //        return ret;
1039 //        
1040 //    },
1041     
1042     
1043     addItem : function(ev)
1044     {
1045         // look for vertical location slot in
1046         var cells = this.findCells(ev);
1047         
1048 //        ev.row = this.findBestRow(cells);
1049         
1050         // work out the location.
1051         
1052         var crow = false;
1053         var rows = [];
1054         for(var i =0; i < cells.length; i++) {
1055             
1056             cells[i].row = cells[0].row;
1057             
1058             if(i == 0){
1059                 cells[i].row = cells[i].row + 1;
1060             }
1061             
1062             if (!crow) {
1063                 crow = {
1064                     start : cells[i],
1065                     end :  cells[i]
1066                 };
1067                 continue;
1068             }
1069             if (crow.start.getY() == cells[i].getY()) {
1070                 // on same row.
1071                 crow.end = cells[i];
1072                 continue;
1073             }
1074             // different row.
1075             rows.push(crow);
1076             crow = {
1077                 start: cells[i],
1078                 end : cells[i]
1079             };
1080             
1081         }
1082         
1083         rows.push(crow);
1084         ev.els = [];
1085         ev.rows = rows;
1086         ev.cells = cells;
1087         
1088         cells[0].events.push(ev);
1089         
1090         this.calevents.push(ev);
1091     },
1092     
1093     clearEvents: function() {
1094         
1095         if(!this.calevents){
1096             return;
1097         }
1098         
1099         Roo.each(this.cells.elements, function(c){
1100             c.row = 0;
1101             c.events = [];
1102             c.more = [];
1103         });
1104         
1105         Roo.each(this.calevents, function(e) {
1106             Roo.each(e.els, function(el) {
1107                 el.un('mouseenter' ,this.onEventEnter, this);
1108                 el.un('mouseleave' ,this.onEventLeave, this);
1109                 el.remove();
1110             },this);
1111         },this);
1112         
1113         Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
1114             e.remove();
1115         });
1116         
1117     },
1118     
1119     renderEvents: function()
1120     {   
1121         var _this = this;
1122         
1123         this.cells.each(function(c) {
1124             
1125             if(c.row < 5){
1126                 return;
1127             }
1128             
1129             var ev = c.events;
1130             
1131             var r = 4;
1132             if(c.row != c.events.length){
1133                 r = 4 - (4 - (c.row - c.events.length));
1134             }
1135             
1136             c.events = ev.slice(0, r);
1137             c.more = ev.slice(r);
1138             
1139             if(c.more.length && c.more.length == 1){
1140                 c.events.push(c.more.pop());
1141             }
1142             
1143             c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
1144             
1145         });
1146             
1147         this.cells.each(function(c) {
1148             
1149             c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
1150             
1151             
1152             for (var e = 0; e < c.events.length; e++){
1153                 var ev = c.events[e];
1154                 var rows = ev.rows;
1155                 
1156                 for(var i = 0; i < rows.length; i++) {
1157                 
1158                     // how many rows should it span..
1159
1160                     var  cfg = {
1161                         cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
1162                         style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
1163
1164                         unselectable : "on",
1165                         cn : [
1166                             {
1167                                 cls: 'fc-event-inner',
1168                                 cn : [
1169     //                                {
1170     //                                  tag:'span',
1171     //                                  cls: 'fc-event-time',
1172     //                                  html : cells.length > 1 ? '' : ev.time
1173     //                                },
1174                                     {
1175                                       tag:'span',
1176                                       cls: 'fc-event-title',
1177                                       html : String.format('{0}', ev.title)
1178                                     }
1179
1180
1181                                 ]
1182                             },
1183                             {
1184                                 cls: 'ui-resizable-handle ui-resizable-e',
1185                                 html : '&nbsp;&nbsp;&nbsp'
1186                             }
1187
1188                         ]
1189                     };
1190
1191                     if (i == 0) {
1192                         cfg.cls += ' fc-event-start';
1193                     }
1194                     if ((i+1) == rows.length) {
1195                         cfg.cls += ' fc-event-end';
1196                     }
1197
1198                     var ctr = _this.el.select('.fc-event-container',true).first();
1199                     var cg = ctr.createChild(cfg);
1200
1201                     var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
1202                     var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
1203
1204                     var r = (c.more.length) ? 1 : 0;
1205                     cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);    
1206                     cg.setWidth(ebox.right - sbox.x -2);
1207
1208                     cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
1209                     cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
1210                     cg.on('click', _this.onEventClick, _this, ev);
1211
1212                     ev.els.push(cg);
1213                     
1214                 }
1215                 
1216             }
1217             
1218             
1219             if(c.more.length){
1220                 var  cfg = {
1221                     cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
1222                     style : 'position: absolute',
1223                     unselectable : "on",
1224                     cn : [
1225                         {
1226                             cls: 'fc-event-inner',
1227                             cn : [
1228                                 {
1229                                   tag:'span',
1230                                   cls: 'fc-event-title',
1231                                   html : 'More'
1232                                 }
1233
1234
1235                             ]
1236                         },
1237                         {
1238                             cls: 'ui-resizable-handle ui-resizable-e',
1239                             html : '&nbsp;&nbsp;&nbsp'
1240                         }
1241
1242                     ]
1243                 };
1244
1245                 var ctr = _this.el.select('.fc-event-container',true).first();
1246                 var cg = ctr.createChild(cfg);
1247
1248                 var sbox = c.select('.fc-day-content',true).first().getBox();
1249                 var ebox = c.select('.fc-day-content',true).first().getBox();
1250                 //Roo.log(cg);
1251                 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);    
1252                 cg.setWidth(ebox.right - sbox.x -2);
1253
1254                 cg.on('click', _this.onMoreEventClick, _this, c.more);
1255                 
1256             }
1257             
1258         });
1259         
1260         
1261         
1262     },
1263     
1264     onEventEnter: function (e, el,event,d) {
1265         this.fireEvent('evententer', this, el, event);
1266     },
1267     
1268     onEventLeave: function (e, el,event,d) {
1269         this.fireEvent('eventleave', this, el, event);
1270     },
1271     
1272     onEventClick: function (e, el,event,d) {
1273         this.fireEvent('eventclick', this, el, event);
1274     },
1275     
1276     onMonthChange: function () {
1277         this.store.load();
1278     },
1279     
1280     onMoreEventClick: function(e, el, more)
1281     {
1282         var _this = this;
1283         
1284         this.calpopover.placement = 'right';
1285         this.calpopover.setTitle('More');
1286         
1287         this.calpopover.setContent('');
1288         
1289         var ctr = this.calpopover.el.select('.popover-content', true).first();
1290         
1291         Roo.each(more, function(m){
1292             var cfg = {
1293                 cls : 'fc-event-hori fc-event-draggable',
1294                 html : m.title
1295             };
1296             var cg = ctr.createChild(cfg);
1297             
1298             cg.on('click', _this.onEventClick, _this, m);
1299         });
1300         
1301         this.calpopover.show(el);
1302         
1303         
1304     },
1305     
1306     onLoad: function () 
1307     {   
1308         this.calevents = [];
1309         var cal = this;
1310         
1311         if(this.store.getCount() > 0){
1312             this.store.data.each(function(d){
1313                cal.addItem({
1314                     id : d.data.id,
1315                     start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
1316                     end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
1317                     time : d.data.start_time,
1318                     title : d.data.title,
1319                     description : d.data.description,
1320                     venue : d.data.venue
1321                 });
1322             });
1323         }
1324         
1325         this.renderEvents();
1326         
1327         if(this.calevents.length && this.loadMask){
1328             this.maskEl.hide();
1329         }
1330     },
1331     
1332     onBeforeLoad: function()
1333     {
1334         this.clearEvents();
1335         if(this.loadMask){
1336             this.maskEl.show();
1337         }
1338     }
1339 });
1340
1341  
1342  /*
1343  * - LGPL
1344  *
1345  * based on jquery fullcalendar
1346  * 
1347  */
1348
1349
1350 /**
1351  * @class Roo.Calendar
1352  * @extends Roo.Component
1353  * Bootstrap Calendar class
1354     
1355  * @constructor
1356  * Create a new Container
1357  * @param {Object} config The config object
1358  */
1359
1360 Roo.CalendarPanel = function(config){
1361     
1362     Roo.log("cal panel ctr");
1363   
1364     this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
1365         {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
1366         
1367     //this.wrapper.dom.appendChild(grid.getGridEl().dom);
1368     
1369     Roo.CalendarPanel.superclass.constructor.call(this, this.wrapper, config);
1370     
1371     Roo.log(this.el);
1372     
1373     if(this.toolbar){
1374         this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
1375     }
1376     // xtype created footer. - not sure if will work as we normally have to render first..
1377     if (this.footer && !this.footer.el && this.footer.xtype) {
1378         
1379         //this.footer.container = this.grid.getView().getFooterPanel(true);
1380         //this.footer.dataSource = this.grid.dataSource;
1381         //this.footer = Roo.factory(this.footer, Roo);
1382         
1383     }
1384     this.view = new Roo.calendar.View(Roo.apply({
1385         skipNavHeader : true,
1386         skipMonthHeader : false
1387         
1388     },config));
1389     
1390      
1391     this.on('activate', function()
1392     {
1393         Roo.log('activate');
1394          
1395         //console.log('render tree');
1396         this.render();
1397     },this);
1398     
1399     this.addEvents({
1400         /**
1401              * @event select
1402              * Fires when a date is selected
1403              * @param {DatePicker} this
1404              * @param {Date} date The selected date
1405              */
1406         'select': true,
1407         /**
1408              * @event monthchange
1409              * Fires when the displayed month changes 
1410              * @param {DatePicker} this
1411              * @param {Date} date The selected month
1412              */
1413         'monthchange': true,
1414         /**
1415              * @event evententer
1416              * Fires when mouse over an event
1417              * @param {Calendar} this
1418              * @param {event} Event
1419              */
1420         'evententer': true,
1421         /**
1422              * @event eventleave
1423              * Fires when the mouse leaves an
1424              * @param {Calendar} this
1425              * @param {event}
1426              */
1427         'eventleave': true,
1428         /**
1429              * @event eventclick
1430              * Fires when the mouse click an
1431              * @param {Calendar} this
1432              * @param {event}
1433              */
1434         'eventclick': true,
1435         /**
1436              * @event rendered
1437              * Fires when the grid is rendered
1438              * @param {Calendar} this
1439             
1440              */
1441         'rendered': true
1442         
1443         
1444     });
1445     this.relayEvents(this.view, ["select","monthchange","evententer","eventleave","rendered"]);
1446
1447     //this.grid = grid;
1448     //this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
1449 };
1450
1451
1452 Roo.extend(Roo.CalendarPanel, Roo.ContentPanel, {
1453     
1454       
1455     render : function()
1456     {
1457         var ct = this.el.appendChild(document.createElement("div"));
1458         this.onRender(this.el, false)
1459     },
1460     
1461     onRender : function(ct, position)
1462     {
1463         if (this.rendered) {
1464             return;
1465         }
1466         this.rendered = true;
1467         
1468         Roo.log("render calendar");
1469         
1470         
1471         //Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1472         
1473         
1474         var cfg = Roo.apply({},  this.view.getAutoCreate());
1475         cfg.id = Roo.id();
1476         
1477         // fill in the extra attributes 
1478         if (this.xattr && typeof(this.xattr) =='object') {
1479             for (var i in this.xattr) {
1480                 cfg[i] = this.xattr[i];
1481             }
1482         }
1483         
1484         if(this.dataId){
1485             cfg.dataId = this.dataId;
1486         }
1487         
1488         if (this.cls) {
1489             cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
1490         }
1491         
1492         if (this.style) { // fixme needs to support more complex style data.
1493             cfg.style = this.style;
1494         }
1495         
1496         if(this.name){
1497             cfg.name = this.name;
1498         }
1499         
1500         this.view.el =  ct.createChild(cfg, position);
1501         
1502         //if(this.tabIndex !== undefined){
1503         //    this.el.dom.setAttribute('tabIndex', this.tabIndex);
1504         //}
1505         
1506         
1507         this.view.initEvents();
1508         this.fireEvent('rendered');
1509     }
1510     
1511     
1512     
1513     
1514 });
1515
1516