4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
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 * @cfg {string} tooltip Text for the tooltip
20 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
21 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
24 * Do not use directly - it does not do anything..
25 * @param {Object} config The config object
30 Roo.bootstrap.Component = function(config){
31 Roo.bootstrap.Component.superclass.constructor.call(this, config);
35 * @event childrenrendered
36 * Fires when the children have been rendered..
37 * @param {Roo.bootstrap.Component} this
39 "childrenrendered" : true
47 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
50 allowDomMove : false, // to stop relocations in parent onRender...
60 * Initialize Events for the element
62 initEvents : function() { },
68 can_build_overlaid : true,
70 container_method : false,
77 // returns the parent component..
78 return Roo.ComponentMgr.get(this.parentId)
84 onRender : function(ct, position)
86 // Roo.log("Call onRender: " + this.xtype);
88 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
91 if (this.el.attr('xtype')) {
92 this.el.attr('xtypex', this.el.attr('xtype'));
93 this.el.dom.removeAttribute('xtype');
103 var cfg = Roo.apply({}, this.getAutoCreate());
105 cfg.id = this.id || Roo.id();
107 // fill in the extra attributes
108 if (this.xattr && typeof(this.xattr) =='object') {
109 for (var i in this.xattr) {
110 cfg[i] = this.xattr[i];
115 cfg.dataId = this.dataId;
119 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
122 if (this.style) { // fixme needs to support more complex style data.
123 cfg.style = this.style;
127 cfg.name = this.name;
130 this.el = ct.createChild(cfg, position);
133 this.tooltipEl().attr('tooltip', this.tooltip);
136 if(this.tabIndex !== undefined){
137 this.el.dom.setAttribute('tabIndex', this.tabIndex);
144 * Fetch the element to add children to
145 * @return {Roo.Element} defaults to this.el
147 getChildContainer : function()
152 * Fetch the element to display the tooltip on.
153 * @return {Roo.Element} defaults to this.el
155 tooltipEl : function()
160 * This is really a wrapper for addxtypeChild
161 * it handles stuff relating to flexy:foreach / flexy:if
162 * = some of our projects use a flat rendering of the output, and try and overlay it with dynamic data.
163 * -- this is a bit of a nightmare... and is even more confusing to debug..
168 addxtype : function(tree,cntr)
170 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
172 var cn = Roo.factory(tree); // this is posibly the first of two times that the ctor get's called...
173 cn.parentType = this.xtype; //??
174 cn.parentId = this.id;
175 if (typeof(cn.container_method) == 'string') {
176 cntr = cn.container_method;
180 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
182 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
184 var build_from_html = Roo.XComponent.build_from_html;
186 var is_body = (tree.xtype == 'Body') ;
188 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
190 var self_cntr_el = Roo.get(this[cntr](false));
192 // do not try and build conditional elements
193 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
197 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
198 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
199 //return this.addxtypeChild(tree,cntr, is_body);
200 return this.addxtypeChild(tree, cntr, is_body);
203 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
206 return this.addxtypeChild(Roo.apply({}, tree),cntr);
209 Roo.log('skipping render');
215 if (!build_from_html) {
219 // this i think handles overlaying multiple children of the same type
220 // with the sam eelement.. - which might be buggy..
222 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
228 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
232 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
238 * add a child to this element
239 * - turn the child.cfg into a child_instance
240 * - call child_instance.render( this { getContainerMethod()} )
241 * - loop through the children, and call addxtype.. (reall this) on newly created child.
245 addxtypeChild : function (tree, cntr, is_body)
247 Roo.debug && Roo.log('addxtypeChild:' + cntr);
249 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
252 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
253 (typeof(tree['flexy:foreach']) != 'undefined');
257 skip_children = false;
258 // render the element if it's not BODY.
261 // if parent was disabled, then do not try and create the children..
262 if(!this[cntr](true)){
267 cn = Roo.factory(tree);
269 cn.parentType = this.xtype; //??
270 cn.parentId = this.id;
272 var build_from_html = Roo.XComponent.build_from_html;
275 // does the container contain child eleemnts with 'xtype' attributes.
276 // that match this xtype..
277 // note - when we render we create these as well..
278 // so we should check to see if body has xtype set.
279 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
281 var self_cntr_el = Roo.get(this[cntr](false));
282 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
284 //Roo.log(Roo.XComponent.build_from_html);
285 //Roo.log("got echild:");
288 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
289 // and are not displayed -this causes this to use up the wrong element when matching.
290 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
293 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
294 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
300 //echild.dom.removeAttribute('xtype');
302 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
303 Roo.debug && Roo.log(self_cntr_el);
304 Roo.debug && Roo.log(echild);
305 Roo.debug && Roo.log(cn);
311 // if object has flexy:if - then it may or may not be rendered.
312 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
313 // skip a flexy if element.
314 Roo.debug && Roo.log('skipping render');
315 Roo.debug && Roo.log(tree);
317 Roo.debug && Roo.log('skipping all children');
318 skip_children = true;
323 // actually if flexy:foreach is found, we really want to create
324 // multiple copies here...
326 //Roo.log(this[cntr]());
327 // some elements do not have render methods.. like the layouts...
329 if(this[cntr](true) === false){
334 cn.render && cn.render(this[cntr](true));
337 // then add the element..
344 cn.addxtypeChildren(tree.items, skip_children);
350 * add a number of children to this object,
351 * which in turn calls render...
355 addxtypeChildren: function(child_array, skip_children)
358 if (!child_array || !child_array.length ) {
363 for(var i =0;i < child_array.length;i++) {
367 // Roo.log(['add child', items[i]]);
368 nitems.push(this.addxtype(Roo.apply({}, child_array[i])));
372 this.fireEvent('childrenrendered', this);
382 * xAddChildren - the 'sub-compentized' version of the above idea..
384 xAddChildren: function(child_array, skip_children)
387 if (!child_array || !child_array.length ) {
392 for(var i =0;i < child_array.length;i++) {
396 // Roo.log(['add child', items[i]]);
397 nitems.push(this.xAdd(Roo.apply({}, child_array[i])));
401 this.fireEvent('childrenrendered', this);
407 * add a child to this element
408 * - turn the child.cfg into a child_instance
409 * - call child_instance.render( this { getContainerMethod()} )
410 * - loop through the children, and call addxtype.. (reall this) on newly created child.
414 xAdd : function (tree, cntr, is_body)
416 Roo.debug && Roo.log('xadd:' + cntr);
418 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
421 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
422 (typeof(tree['flexy:foreach']) != 'undefined');
426 skip_children = false;
427 // render the element if it's not BODY.
430 // if parent was disabled, then do not try and create the children..
431 if(!this[cntr](true)){
436 cn = Roo.factory(tree);
438 cn.parentType = this.xtype; //??
439 cn.parentId = this.id;
441 var build_from_html = Roo.XComponent.build_from_html;
444 // does the container contain child eleemnts with 'xtype' attributes.
445 // that match this xtype..
446 // note - when we render we create these as well..
447 // so we should check to see if body has xtype set.
448 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
450 var self_cntr_el = Roo.get(this[cntr](false));
451 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
453 //Roo.log(Roo.XComponent.build_from_html);
454 //Roo.log("got echild:");
457 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
458 // and are not displayed -this causes this to use up the wrong element when matching.
459 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
462 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
463 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
469 //echild.dom.removeAttribute('xtype');
471 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
472 Roo.debug && Roo.log(self_cntr_el);
473 Roo.debug && Roo.log(echild);
474 Roo.debug && Roo.log(cn);
480 // if object has flexy:if - then it may or may not be rendered.
481 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
482 // skip a flexy if element.
483 Roo.debug && Roo.log('skipping render');
484 Roo.debug && Roo.log(tree);
486 Roo.debug && Roo.log('skipping all children');
487 skip_children = true;
492 // actually if flexy:foreach is found, we really want to create
493 // multiple copies here...
495 //Roo.log(this[cntr]());
496 // some elements do not have render methods.. like the layouts...
498 if(this[cntr](true) === false){
503 cn.render && cn.render(this[cntr](true));
506 // then add the element..
513 cn.addxtypeChildren(tree.items, skip_children);
520 * Set the element that will be used to show or hide
522 setVisibilityEl : function(el)
524 this.visibilityEl = el;
528 * Get the element that will be used to show or hide
530 getVisibilityEl : function()
532 if (typeof(this.visibilityEl) == 'object') {
533 return this.visibilityEl;
536 if (typeof(this.visibilityEl) == 'string') {
537 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
544 * Show a component - removes 'hidden' class
548 if(!this.getVisibilityEl()){
552 this.getVisibilityEl().removeClass(['hidden','d-none']);
554 this.fireEvent('show', this);
559 * Hide a component - adds 'hidden' class
563 if(!this.getVisibilityEl()){
567 this.getVisibilityEl().addClass(['hidden','d-none']);
569 this.fireEvent('hide', this);
577 * based on jquery fullcalendar
581 Roo.bootstrap = Roo.bootstrap || {};
583 * @class Roo.bootstrap.Calendar
584 * @extends Roo.bootstrap.Component
585 * Bootstrap Calendar class
586 * @cfg {Boolean} loadMask (true|false) default false
587 * @cfg {Object} header generate the user specific header of the calendar, default false
590 * Create a new Container
591 * @param {Object} config The config object
596 Roo.bootstrap.Calendar = function(config){
597 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
601 * Fires when a date is selected
602 * @param {DatePicker} this
603 * @param {Date} date The selected date
608 * Fires when the displayed month changes
609 * @param {DatePicker} this
610 * @param {Date} date The selected month
615 * Fires when mouse over an event
616 * @param {Calendar} this
617 * @param {event} Event
622 * Fires when the mouse leaves an
623 * @param {Calendar} this
629 * Fires when the mouse click an
630 * @param {Calendar} this
639 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
642 * @cfg {Number} startDay
643 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
651 getAutoCreate : function(){
654 var fc_button = function(name, corner, style, content ) {
655 return Roo.apply({},{
657 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
659 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
662 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
673 style : 'width:100%',
680 cls : 'fc-header-left',
682 fc_button('prev', 'left', 'arrow', '‹' ),
683 fc_button('next', 'right', 'arrow', '›' ),
684 { tag: 'span', cls: 'fc-header-space' },
685 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
693 cls : 'fc-header-center',
697 cls: 'fc-header-title',
700 html : 'month / year'
708 cls : 'fc-header-right',
710 /* fc_button('month', 'left', '', 'month' ),
711 fc_button('week', '', '', 'week' ),
712 fc_button('day', 'right', '', 'day' )
724 header = this.header;
727 var cal_heads = function() {
729 // fixme - handle this.
731 for (var i =0; i < Date.dayNames.length; i++) {
732 var d = Date.dayNames[i];
735 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
736 html : d.substring(0,3)
740 ret[0].cls += ' fc-first';
741 ret[6].cls += ' fc-last';
744 var cal_cell = function(n) {
747 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
752 cls: 'fc-day-number',
756 cls: 'fc-day-content',
760 style: 'position: relative;' // height: 17px;
772 var cal_rows = function() {
775 for (var r = 0; r < 6; r++) {
782 for (var i =0; i < Date.dayNames.length; i++) {
783 var d = Date.dayNames[i];
784 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
787 row.cn[0].cls+=' fc-first';
788 row.cn[0].cn[0].style = 'min-height:90px';
789 row.cn[6].cls+=' fc-last';
793 ret[0].cls += ' fc-first';
794 ret[4].cls += ' fc-prev-last';
795 ret[5].cls += ' fc-last';
802 cls: 'fc-border-separate',
803 style : 'width:100%',
811 cls : 'fc-first fc-last',
830 style : "position: relative;",
833 cls : 'fc-view fc-view-month fc-grid',
834 style : 'position: relative',
838 cls : 'fc-event-container',
839 style : 'position:absolute;z-index:8;top:0;left:0;'
857 initEvents : function()
860 throw "can not find store for calendar";
866 style: "text-align:center",
870 style: "background-color:white;width:50%;margin:250 auto",
874 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
885 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
887 var size = this.el.select('.fc-content', true).first().getSize();
888 this.maskEl.setSize(size.width, size.height);
889 this.maskEl.enableDisplayMode("block");
894 this.store = Roo.factory(this.store, Roo.data);
895 this.store.on('load', this.onLoad, this);
896 this.store.on('beforeload', this.onBeforeLoad, this);
900 this.cells = this.el.select('.fc-day',true);
901 //Roo.log(this.cells);
902 this.textNodes = this.el.query('.fc-day-number');
903 this.cells.addClassOnOver('fc-state-hover');
905 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
906 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
907 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
908 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
910 this.on('monthchange', this.onMonthChange, this);
912 this.update(new Date().clearTime());
915 resize : function() {
916 var sz = this.el.getSize();
918 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
919 this.el.select('.fc-day-content div',true).setHeight(34);
924 showPrevMonth : function(e){
925 this.update(this.activeDate.add("mo", -1));
927 showToday : function(e){
928 this.update(new Date().clearTime());
931 showNextMonth : function(e){
932 this.update(this.activeDate.add("mo", 1));
936 showPrevYear : function(){
937 this.update(this.activeDate.add("y", -1));
941 showNextYear : function(){
942 this.update(this.activeDate.add("y", 1));
947 update : function(date)
949 var vd = this.activeDate;
950 this.activeDate = date;
951 // if(vd && this.el){
952 // var t = date.getTime();
953 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
954 // Roo.log('using add remove');
956 // this.fireEvent('monthchange', this, date);
958 // this.cells.removeClass("fc-state-highlight");
959 // this.cells.each(function(c){
960 // if(c.dateValue == t){
961 // c.addClass("fc-state-highlight");
962 // setTimeout(function(){
963 // try{c.dom.firstChild.focus();}catch(e){}
973 var days = date.getDaysInMonth();
975 var firstOfMonth = date.getFirstDateOfMonth();
976 var startingPos = firstOfMonth.getDay()-this.startDay;
978 if(startingPos < this.startDay){
982 var pm = date.add(Date.MONTH, -1);
983 var prevStart = pm.getDaysInMonth()-startingPos;
985 this.cells = this.el.select('.fc-day',true);
986 this.textNodes = this.el.query('.fc-day-number');
987 this.cells.addClassOnOver('fc-state-hover');
989 var cells = this.cells.elements;
990 var textEls = this.textNodes;
992 Roo.each(cells, function(cell){
993 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
998 // convert everything to numbers so it's fast
1000 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
1003 //Roo.log(prevStart);
1005 var today = new Date().clearTime().getTime();
1006 var sel = date.clearTime().getTime();
1007 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
1008 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
1009 var ddMatch = this.disabledDatesRE;
1010 var ddText = this.disabledDatesText;
1011 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
1012 var ddaysText = this.disabledDaysText;
1013 var format = this.format;
1015 var setCellClass = function(cal, cell){
1019 //Roo.log('set Cell Class');
1021 var t = d.getTime();
1027 cell.className += " fc-today";
1028 cell.className += " fc-state-highlight";
1029 cell.title = cal.todayText;
1032 // disable highlight in other month..
1033 //cell.className += " fc-state-highlight";
1038 cell.className = " fc-state-disabled";
1039 cell.title = cal.minText;
1043 cell.className = " fc-state-disabled";
1044 cell.title = cal.maxText;
1048 if(ddays.indexOf(d.getDay()) != -1){
1049 cell.title = ddaysText;
1050 cell.className = " fc-state-disabled";
1053 if(ddMatch && format){
1054 var fvalue = d.dateFormat(format);
1055 if(ddMatch.test(fvalue)){
1056 cell.title = ddText.replace("%0", fvalue);
1057 cell.className = " fc-state-disabled";
1061 if (!cell.initialClassName) {
1062 cell.initialClassName = cell.dom.className;
1065 cell.dom.className = cell.initialClassName + ' ' + cell.className;
1070 for(; i < startingPos; i++) {
1071 textEls[i].innerHTML = (++prevStart);
1072 d.setDate(d.getDate()+1);
1074 cells[i].className = "fc-past fc-other-month";
1075 setCellClass(this, cells[i]);
1080 for(; i < days; i++){
1081 intDay = i - startingPos + 1;
1082 textEls[i].innerHTML = (intDay);
1083 d.setDate(d.getDate()+1);
1085 cells[i].className = ''; // "x-date-active";
1086 setCellClass(this, cells[i]);
1090 for(; i < 42; i++) {
1091 textEls[i].innerHTML = (++extraDays);
1092 d.setDate(d.getDate()+1);
1094 cells[i].className = "fc-future fc-other-month";
1095 setCellClass(this, cells[i]);
1098 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
1100 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
1102 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
1103 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
1106 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
1107 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
1110 this.fireEvent('monthchange', this, date);
1114 if(!this.internalRender){
1115 var main = this.el.dom.firstChild;
1116 var w = main.offsetWidth;
1117 this.el.setWidth(w + this.el.getBorderWidth("lr"));
1118 Roo.fly(main).setWidth(w);
1119 this.internalRender = true;
1120 // opera does not respect the auto grow header center column
1121 // then, after it gets a width opera refuses to recalculate
1122 // without a second pass
1123 if(Roo.isOpera && !this.secondPass){
1124 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
1125 this.secondPass = true;
1126 this.update.defer(10, this, [date]);
1133 findCell : function(dt) {
1134 dt = dt.clearTime().getTime();
1136 this.cells.each(function(c){
1137 //Roo.log("check " +c.dateValue + '?=' + dt);
1138 if(c.dateValue == dt){
1148 findCells : function(ev) {
1149 var s = ev.start.clone().clearTime().getTime();
1151 var e= ev.end.clone().clearTime().getTime();
1154 this.cells.each(function(c){
1155 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
1157 if(c.dateValue > e){
1160 if(c.dateValue < s){
1169 // findBestRow: function(cells)
1173 // for (var i =0 ; i < cells.length;i++) {
1174 // ret = Math.max(cells[i].rows || 0,ret);
1181 addItem : function(ev)
1183 // look for vertical location slot in
1184 var cells = this.findCells(ev);
1186 // ev.row = this.findBestRow(cells);
1188 // work out the location.
1192 for(var i =0; i < cells.length; i++) {
1194 cells[i].row = cells[0].row;
1197 cells[i].row = cells[i].row + 1;
1207 if (crow.start.getY() == cells[i].getY()) {
1209 crow.end = cells[i];
1226 cells[0].events.push(ev);
1228 this.calevents.push(ev);
1231 clearEvents: function() {
1233 if(!this.calevents){
1237 Roo.each(this.cells.elements, function(c){
1243 Roo.each(this.calevents, function(e) {
1244 Roo.each(e.els, function(el) {
1245 el.un('mouseenter' ,this.onEventEnter, this);
1246 el.un('mouseleave' ,this.onEventLeave, this);
1251 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
1257 renderEvents: function()
1261 this.cells.each(function(c) {
1270 if(c.row != c.events.length){
1271 r = 4 - (4 - (c.row - c.events.length));
1274 c.events = ev.slice(0, r);
1275 c.more = ev.slice(r);
1277 if(c.more.length && c.more.length == 1){
1278 c.events.push(c.more.pop());
1281 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
1285 this.cells.each(function(c) {
1287 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
1290 for (var e = 0; e < c.events.length; e++){
1291 var ev = c.events[e];
1294 for(var i = 0; i < rows.length; i++) {
1296 // how many rows should it span..
1299 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
1300 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
1302 unselectable : "on",
1305 cls: 'fc-event-inner',
1309 // cls: 'fc-event-time',
1310 // html : cells.length > 1 ? '' : ev.time
1314 cls: 'fc-event-title',
1315 html : String.format('{0}', ev.title)
1322 cls: 'ui-resizable-handle ui-resizable-e',
1323 html : '  '
1330 cfg.cls += ' fc-event-start';
1332 if ((i+1) == rows.length) {
1333 cfg.cls += ' fc-event-end';
1336 var ctr = _this.el.select('.fc-event-container',true).first();
1337 var cg = ctr.createChild(cfg);
1339 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
1340 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
1342 var r = (c.more.length) ? 1 : 0;
1343 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
1344 cg.setWidth(ebox.right - sbox.x -2);
1346 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
1347 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
1348 cg.on('click', _this.onEventClick, _this, ev);
1359 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
1360 style : 'position: absolute',
1361 unselectable : "on",
1364 cls: 'fc-event-inner',
1368 cls: 'fc-event-title',
1376 cls: 'ui-resizable-handle ui-resizable-e',
1377 html : '  '
1383 var ctr = _this.el.select('.fc-event-container',true).first();
1384 var cg = ctr.createChild(cfg);
1386 var sbox = c.select('.fc-day-content',true).first().getBox();
1387 var ebox = c.select('.fc-day-content',true).first().getBox();
1389 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
1390 cg.setWidth(ebox.right - sbox.x -2);
1392 cg.on('click', _this.onMoreEventClick, _this, c.more);
1402 onEventEnter: function (e, el,event,d) {
1403 this.fireEvent('evententer', this, el, event);
1406 onEventLeave: function (e, el,event,d) {
1407 this.fireEvent('eventleave', this, el, event);
1410 onEventClick: function (e, el,event,d) {
1411 this.fireEvent('eventclick', this, el, event);
1414 onMonthChange: function () {
1418 onMoreEventClick: function(e, el, more)
1422 this.calpopover.placement = 'right';
1423 this.calpopover.setTitle('More');
1425 this.calpopover.setContent('');
1427 var ctr = this.calpopover.el.select('.popover-content', true).first();
1429 Roo.each(more, function(m){
1431 cls : 'fc-event-hori fc-event-draggable',
1434 var cg = ctr.createChild(cfg);
1436 cg.on('click', _this.onEventClick, _this, m);
1439 this.calpopover.show(el);
1446 this.calevents = [];
1449 if(this.store.getCount() > 0){
1450 this.store.data.each(function(d){
1453 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
1454 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
1455 time : d.data.start_time,
1456 title : d.data.title,
1457 description : d.data.description,
1458 venue : d.data.venue
1463 this.renderEvents();
1465 if(this.calevents.length && this.loadMask){
1470 onBeforeLoad: function()
1483 * based on jquery fullcalendar
1489 * @class Roo.Calendar
1490 * @extends Roo.Component
1491 * Bootstrap Calendar class
1494 * Create a new Container
1495 * @param {Object} config The config object
1498 Roo.CalendarPanel = function(config){
1500 Roo.log("cal panel ctr");
1502 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
1503 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
1505 //this.wrapper.dom.appendChild(grid.getGridEl().dom);
1507 Roo.CalendarPanel.superclass.constructor.call(this, this.wrapper, config);
1512 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
1514 // xtype created footer. - not sure if will work as we normally have to render first..
1515 if (this.footer && !this.footer.el && this.footer.xtype) {
1517 //this.footer.container = this.grid.getView().getFooterPanel(true);
1518 //this.footer.dataSource = this.grid.dataSource;
1519 //this.footer = Roo.factory(this.footer, Roo);
1522 this.view = new Roo.calendar.View(Roo.apply({
1523 skipNavHeader : true,
1524 skipMonthHeader : false
1529 this.on('activate', function()
1531 Roo.log('activate');
1533 //console.log('render tree');
1540 * Fires when a date is selected
1541 * @param {DatePicker} this
1542 * @param {Date} date The selected date
1546 * @event monthchange
1547 * Fires when the displayed month changes
1548 * @param {DatePicker} this
1549 * @param {Date} date The selected month
1551 'monthchange': true,
1554 * Fires when mouse over an event
1555 * @param {Calendar} this
1556 * @param {event} Event
1561 * Fires when the mouse leaves an
1562 * @param {Calendar} this
1568 * Fires when the mouse click an
1569 * @param {Calendar} this
1575 * Fires when the grid is rendered
1576 * @param {Calendar} this
1583 this.relayEvents(this.view, ["select","monthchange","evententer","eventleave","rendered"]);
1586 //this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
1590 Roo.extend(Roo.CalendarPanel, Roo.ContentPanel, {
1595 var ct = this.el.appendChild(document.createElement("div"));
1596 this.onRender(this.el, false)
1599 onRender : function(ct, position)
1601 if (this.rendered) {
1604 this.rendered = true;
1606 Roo.log("render calendar");
1609 //Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1612 var cfg = Roo.apply({}, this.view.getAutoCreate());
1615 // fill in the extra attributes
1616 if (this.xattr && typeof(this.xattr) =='object') {
1617 for (var i in this.xattr) {
1618 cfg[i] = this.xattr[i];
1623 cfg.dataId = this.dataId;
1627 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
1630 if (this.style) { // fixme needs to support more complex style data.
1631 cfg.style = this.style;
1635 cfg.name = this.name;
1638 this.view.el = ct.createChild(cfg, position);
1640 //if(this.tabIndex !== undefined){
1641 // this.el.dom.setAttribute('tabIndex', this.tabIndex);
1645 this.view.initEvents();
1646 this.fireEvent('rendered');