tine20/Calendar/js/DaysView.js
Rama main · réplica de lectura del repositorio original.
/*
* Tine 2.0
*
* @license http://www.gnu.org/licenses/agpl.html AGPL Version 3
* @author Cornelius Weiss <c.weiss@metaways.de>
* @copyright Copyright (c) 2009-2015 Metaways Infosystems GmbH (http://www.metaways.de)
*/
Ext.ns('Tine.Calendar');
require('../styles/daysviewpanel.scss');
require('./Printer/DaysView');
/**
* @namespace Tine.Calendar
* @class Tine.Calendar.DaysView
* @extends Tine.Calendar.AbstractView
* Calendar view representing each day in a column
* @author Cornelius Weiss <c.weiss@metaways.de>
* @constructor
* @param {Object} config
*/
Tine.Calendar.DaysView = function(config){
Ext.apply(this, config);
Tine.Calendar.DaysView.superclass.constructor.call(this);
this.printRenderer = Tine.Calendar.Printer.DaysViewRenderer;
this.addEvents(
/**
* @event click
* fired if an event got clicked
* @param {Tine.Calendar.Model.Event} event
* @param {Ext.EventObject} e
*/
'click',
/**
* @event contextmenu
* fired if an event got contextmenu
* @param {Ext.EventObject} e
*/
'contextmenu',
/**
* @event dblclick
* fired if an event got dblclicked
* @param {Tine.Calendar.Model.Event} event
* @param {Ext.EventObject} e
*/
'dblclick',
/**
* @event changeView
* fired if user wants to change view
* @param {String} requested view name
* @param {mixed} start param of requested view
*/
'changeView',
/**
* @event changePeriod
* fired when period changed
* @param {Object} period
*/
'changePeriod',
/**
* @event addEvent
* fired when a new event got inserted
*
* @param {Tine.Calendar.Model.Event} event
*/
'addEvent',
/**
* @event updateEvent
* fired when an event go resised/moved
*
* @param {Tine.Calendar.Model.Event} event
*/
'updateEvent',
/**
* @event onBeforeAllDayScrollerResize
* fired when an the allDayArea gets resized
*
* @param {Tine.Calendar.Model.DaysView} this
* @param {number} heigt
*/
'onBeforeAllDayScrollerResize'
);
};
Ext.extend(Tine.Calendar.DaysView, Tine.Calendar.AbstractView, {
/**
* @cfg {Date} startDate
* start date
*/
startDate: new Date(),
/**
* @cfg {Number} numOfDays
* number of days to display
*/
numOfDays: 4,
/**
* @cfg {String} (H:i) defaultStart
* generic scroll start of the (work) day
*/
defaultStart: '08:00',
/**
* @cfg {String} (H:i) dayStart
* generic start of the (work) day
*/
dayStart: '08:00',
/**
* @cfg {String} (H:i) dayEnd
* generic end of the (work) day
*/
dayEnd: '18:00',
/**
* @cfg {Bool} cropDayTime
* crop times before and after dayStart and dayEnd
*/
cropDayTime: false,
/**
* @cfg {Integer} wheelIncrement
* the number of pixels to increment on mouse wheel scrolling (defaults to 50)
*/
wheelIncrement: 50,
/**
* @cfg {String} newEventSummary
* i18n._('New Event')
*/
newEventSummary: 'New Event',
/**
* @cfg {String} dayFormatString
* i18n._('{0}, the {1}. of {2}')
*/
dayFormatString: '{0}, the {1}. of {2}',
/**
* @cfg {Number} timeGranularity
* granularity of timegrid in minutes
*/
timeGranularity: 30,
/**
* @cfg {Number} timeIncrement
* time increment for range adds/edits (minutes)
*/
timeIncrement: 15,
/**
* @cfg {Number} timeVisible
* time visible in scrolling area (minutes)
*/
timeVisible: '10:00',
/**
* @cfg {Boolean} denyDragOnMissingEditGrant
* deny drag action if edit grant for event is missing
*/
denyDragOnMissingEditGrant: true,
/**
* @cfg {Boolean} readOnly
* no dd acionts if read only
*/
readOnly: false,
/**
* store holding timescale
* @property {Ext.data.Store}
* @private
*/
timeScale: null,
/**
* The amount of space to reserve for the scrollbar (defaults to 19 pixels)
* @property {Number}
* @private
*/
scrollOffset: 19,
/**
* The time in milliseconds, a scroll should be delayed after using the mousewheel
* @property Number
* @private
*/
scrollBuffer: 200,
/**
* The minmum all day height in px
* @property Number
* @private
*/
minAllDayScrollerHight: 10,
/**
* record currently being edited or false
* @property {Record} editing
* @private
*/
editing: false,
/**
* @property {Ext.data.Store}
* @private
*/
ds: null,
eventCls: 'cal-daysviewpanel-event',
/**
* updates period to display
* @param {Array} period
*/
updatePeriod: function(period) {
this.startDate = period.from.clearTime(true);
let tbar = this.findParentBy(function(c) {return c.getTopToolbar?.()});
if (tbar) {
tbar = tbar.getTopToolbar();
}
if (tbar && tbar.periodPicker) {
tbar.periodPicker.update(this.startDate);
this.startDate = tbar.periodPicker.getPeriod().from.clearTime(true);
}
this.endDate = this.startDate.add(Date.DAY, this.numOfDays+1);
//this.parallelScrollerEventsRegistry = new Tine.Calendar.ParallelEventsRegistry({dtStart: this.startDate, dtEnd: this.endDate});
//this.parallelWholeDayEventsRegistry = new Tine.Calendar.ParallelEventsRegistry({dtStart: this.startDate, dtEnd: this.endDate});
//this.store.each(this.removeEvent, this);
this.updateDayHeaders();
this.onBeforeScroll();
this.fireEvent('changePeriod', period);
},
/**
* init this view
*/
initComponent: function() {
this.app = Tine.Tinebase.appMgr.get('Calendar');
this.newEventSummary = this.app.i18n._hidden(this.newEventSummary);
this.dayFormatString = this.app.i18n._hidden(this.dayFormatString);
this.startDate.clearTime();
this.endDate = this.startDate.add(Date.DAY, this.numOfDays+1);
this.boxMinWidth = 60*this.numOfDays;
this.parallelScrollerEventsRegistry = new Tine.Calendar.ParallelEventsRegistry({dtStart: this.startDate, dtEnd: this.endDate});
this.parallelWholeDayEventsRegistry = new Tine.Calendar.ParallelEventsRegistry({dtStart: this.startDate, dtEnd: this.endDate});
this.timeIncrement = parseInt(this.app.getRegistry().peek('preferences').get('timeIncrement')) || this.timeIncrement;
this.initTimeScale();
if (Tine.Tinebase.MainScreen) {
this.mon(Tine.Tinebase.MainScreen, 'appactivate', this.onAppActivate, this);
}
// apply preferences
var prefs = this.app.getRegistry().peek('preferences'),
defaultStartTime = Date.parseDate(prefs.get('daysviewdefaultstarttime'), 'H:i'),
startTime = Date.parseDate(prefs.get('daysviewstarttime'), 'H:i'),
endTime = Date.parseDate(prefs.get('daysviewendtime'), 'H:i'),
timeVisible = Date.parseTimePart(prefs.get('daysviewtimevisible'), 'H:i');
this.dayStart = Ext.isDate(startTime) ? startTime : Date.parseDate(this.dayStart, 'H:i');
this.dayEnd = Ext.isDate(endTime) ? endTime : Date.parseDate(this.dayEnd, 'H:i');
// 00:00 in users timezone is a spechial case where the user expects
// something like 24:00 and not 00:00
if (this.dayEnd.format('H:i') == '00:00') {
this.dayEnd = this.dayEnd.add(Date.MINUTE, -1);
}
this.timeVisible = Ext.isDate(timeVisible) ? timeVisible : Date.parseTimePart(this.timeVisible, 'H:i');
this.cropDayTime = !! Tine.Tinebase.configManager.get('daysviewcroptime', 'Calendar');
if (this.cropDayTime) {
this.defaultStart = Ext.isDate(defaultStartTime) ? defaultStartTime : Date.parseDate(this.defaultStart, 'H:i');
} else {
this.defaultStart = this.dayStart;
}
this.wheelIncrement = Tine.Tinebase.configManager.get('daysviewwheelincrement', 'Calendar') || this.wheelIncrement;
Tine.Calendar.DaysView.superclass.initComponent.apply(this, arguments);
},
/**
* inits time scale
* @private
*/
initTimeScale: function() {
var data = [];
var scaleSize = Date.msDAY/(this.timeGranularity * Date.msMINUTE);
var baseDate = this.startDate.clone();
var minutes;
for (var i=0; i<scaleSize; i++) {
minutes = i * this.timeGranularity;
data.push([i, minutes, minutes * Date.msMINUTE, baseDate.add(Date.MINUTE, minutes).format('H:i')]);
}
this.timeScale = new Ext.data.SimpleStore({
fields: ['index', 'minutes', 'milliseconds', 'time'],
data: data,
id: 'index'
});
},
initDropZone: function() {
this.dd = new Ext.dd.DropZone(this.mainWrap.dom, {
ddGroup: 'cal-event',
view: this,
notifyOver : function(dd, e, data) {
var sourceEl = Ext.fly(data.sourceEl),
sourceView = data.scope,
colorIcon = _.get(data,'event.colorSet.text') === '#FFFFFF' ? '-WHITE' : '';
sourceEl.setStyle({'border-left-style': 'dashed'});
sourceEl.setOpacity(0.5);
data.denyDrop = true;
if (data.event) {
var event = data.event;
var targetDateTime = Tine.Calendar.DaysView.prototype.getTargetDateTime.call(data.scope, e);
if (targetDateTime) {
var dtString = targetDateTime.format(targetDateTime.is_all_day_event ? Ext.form.DateField.prototype.format : 'H:i');
if (! event.data.is_all_day_event) {
Ext.fly(dd.proxy.el.query('div[class=cal-daysviewpanel-event-header-inner]')[0]).update(dtString);
}
if (event.get('editGrant')) {
data.denyDrop = this.view == sourceView && Math.abs(targetDateTime.getTime() - event.get('dtstart').getTime()) < Date.msMINUTE;
if (data.dtstartLimit && targetDateTime.getTimePart() > data.dtstartLimit) {
data.denyDrop = true;
}
var eventDrop = data.denyDrop ? 'cal-daysviewpanel-event-drop-nodrop' : 'cal-daysviewpanel-event-drop-ok';
return eventDrop + colorIcon;
}
}
}
return 'cal-daysviewpanel-event-drop-nodrop' + colorIcon;
},
notifyOut : function() {
//delete this.grid;
},
notifyDrop : function(dd, e, data) {
var v = data.scope,
targetDate = v.getTargetDateTime(e);
if (targetDate) {
var event = data.event,
originalDuration = (event.get('dtend').getTime() - event.get('dtstart').getTime()) / Date.msMINUTE;
if (data.denyDrop) {
return false;
}
event.beginEdit();
event.set('dtstart', targetDate);
if (! event.get('is_all_day_event') && targetDate.is_all_day_event && event.duration < Date.msDAY) {
// draged from scroller -> dropped to allDay and duration less than a day
event.set('dtend', targetDate.add(Date.DAY, 1).add(Date.SECOND, -1));
} else if (event.get('is_all_day_event') && !targetDate.is_all_day_event) {
// draged from allDay -> droped to scroller will be resetted to hone hour
event.set('dtend', targetDate.add(Date.MINUTE, Tine.Calendar.Model.Event.getMeta('defaultEventDuration')));
} else {
event.set('dtend', targetDate.add(Date.MINUTE, originalDuration));
}
event.set('is_all_day_event', targetDate.is_all_day_event);
// change attendee in split view
if (this.view.ownerCt.attendee) {
var attendeeStore = Tine.Calendar.Model.Attender.getAttendeeStore(event.get('attendee')),
sourceAttendee = Tine.Calendar.Model.Attender.getAttendeeStore.getAttenderRecord(attendeeStore, event.view.ownerCt.attendee),
destinationAttendee = Tine.Calendar.Model.Attender.getAttendeeStore.getAttenderRecord(attendeeStore, this.view.ownerCt.attendee);
if (! destinationAttendee) {
destinationAttendee = new Tine.Calendar.Model.Attender(this.view.ownerCt.attendee.data);
attendeeStore.remove(sourceAttendee);
attendeeStore.add(destinationAttendee);
Tine.Calendar.Model.Attender.getAttendeeStore.getData(attendeeStore, event);
}
}
event.endEdit();
v.fireEvent('updateEvent', event);
}
return !!targetDate;
}
});
},
/**
* @private
*/
initDragZone: function() {
this.scroller.ddScrollConfig = {
hthresh: -1,
frequency: 500
};
Ext.dd.ScrollManager.register(this.scroller);
// init dragables
this.dragZone = new Ext.dd.DragZone(this.el, {
ddGroup: 'cal-event',
view: this,
scroll: false,
containerScroll: true,
getDragData: function(e) {
// adjust scrollConfig
var scrollUnit = this.view.getTimeOffset(this.view.timeIncrement);
this.view.scroller.ddScrollConfig.vthresh = scrollUnit *2;
this.view.scroller.ddScrollConfig.increment = scrollUnit * 4;
var selected = this.view.getSelectionModel().getSelectedEvents();
var eventEl = e.getTarget('div.cal-daysviewpanel-event', 10);
if (eventEl) {
var parts = eventEl.id.split(':');
var event = this.view.store.getById(parts[1]);
// don't allow dragging of dirty events
// don't allow dragging with missing edit grant
if (! event || event.dirty || this.readOnly || this.view.readOnly || (this.view.denyDragOnMissingEditGrant && ! event.get('editGrant'))) {
return;
}
// we need to clone an event with summary in
var eventEl = Ext.get(event.ui.domIds[0]),
eventBox = eventEl.getBox(),
d = eventEl.dom.cloneNode(true);
d.id = Ext.id();
if (event.get('is_all_day_event')) {
Ext.fly(d).setTop(-2);
Ext.fly(d).setLeft(0);
Ext.fly(d).setWidth(eventBox.width);
} else {
var width = (Ext.fly(this.view.dayCols[0]).getWidth() * 0.9);
Ext.fly(d).setTop(0);
Ext.fly(d).setWidth(width);
Ext.fly(d).setHeight(eventBox.height);
}
return {
scope: this.view,
sourceEl: eventEl,
event: event,
ddel: d,
selections: this.view.getSelectionModel().getSelectedEvents(),
dtstartLimit: this.view.cropDayTime ? this.view.dayEnd.getTimePart() - event.duration : false
}
}
},
getRepairXY: function(e, dd) {
Ext.fly(this.dragData.sourceEl).setStyle({'border-left-style': 'solid'});
Ext.fly(this.dragData.sourceEl).setOpacity(1, 1);
return Ext.fly(this.dragData.sourceEl).getXY();
}
});
},
/**
* renders the view
*/
onRender: function(container, position) {
Tine.Calendar.DaysView.superclass.onRender.apply(this, arguments);
this.templates.master.append(this.el.dom, {
header: this.templates.header.applyTemplate({
daysHeader: this.getDayHeaders(),
wholeDayCols: this.getWholeDayCols()
}),
body: this.templates.body.applyTemplate({
timeRows: this.getTimeRows(),
dayColumns: this.getDayColumns()
})
});
this.initElements();
},
/**
* fill the events into the view
*/
afterRender: function() {
Tine.Calendar.DaysView.superclass.afterRender.apply(this, arguments);
this.mon(this.el, 'mousedown', this.onMouseDown, this);
this.mon(this.el, 'mouseup', this.onMouseUp, this);
this.initDropZone();
this.initDragZone();
this.updatePeriod({from: this.startDate});
// apply os specific scrolling space
Ext.fly(this.innerHd.firstChild.firstChild).setStyle('margin-right', Ext.getScrollBarWidth() + 'px');
// crop daytime
if (this.cropDayTime) {
this.cropper.setStyle('overflow', 'hidden');
this.scroller.addClass('cal-daysviewpanel-body-cropDayTime');
}
if (this.store.getCount()) {
this.onLoad.defer(100, this);
}
this.rendered = true;
},
scrollTo: function(time) {
time = Ext.isDate(time) ? time : new Date();
var scrollTop = this.getTimeOffset(time);
if (this.cropDayTime) {
scrollTop = scrollTop - this.getTimeOffset(this.dayStart);
}
this.scroller.dom.scrollTop = scrollTop;
},
onMouseWheel: function(e) {
var d = e.getWheelDelta()*this.wheelIncrement*-1;
e.stopEvent();
var scrollTop = this.scroller.dom.scrollTop,
newTop = scrollTop + d,
sh = this.scroller.dom.scrollHeight-this.scroller.dom.clientHeight;
var s = Math.max(0, Math.min(sh, newTop));
if(s != scrollTop){
this.scroller.scrollTo('top', s);
}
},
onBeforeScroll: function() {
if (! this.isScrolling) {
this.isScrolling = true;
// walk all cols an hide hints
Ext.each(this.dayCols, function(dayCol, idx) {
this.aboveHints.item(idx).setDisplayed(false);
this.belowHints.item(idx).setDisplayed(false);
}, this);
}
},
/**
* add hint if events are outside visible area
*
* @param {} e
* @param {} t
* @param {} o
*/
onScroll: function(e, t, o) {
// no arguments means programatic scroll (show/hide/...)
if (! arguments.length) {
var topTime = this.lastScrollTime || this.defaultStart;
if (topTime) {
this.scrollTo(topTime);
}
}
var visibleHeight = this.scroller.dom.clientHeight,
visibleStart = this.scroller.dom.scrollTop - this.mainBody.dom.offsetTop,
visibleEnd = visibleStart + visibleHeight,
vStartMinutes = this.getHeightMinutes(visibleStart),
vEndMinutes = this.getHeightMinutes(visibleEnd);
Ext.each(this.dayCols, function(dayCol, idx) {
var dayColEl = Ext.get(dayCol),
dayStart = this.startDate.add(Date.DAY, idx),
aboveEvents = this.parallelScrollerEventsRegistry.getEvents(dayStart, dayStart.add(Date.MINUTE, vStartMinutes)),
belowEvents = this.parallelScrollerEventsRegistry.getEvents(dayStart.add(Date.MINUTE, vEndMinutes), dayStart.add(Date.DAY, 1));
if (aboveEvents.length) {
var aboveHint = this.aboveHints.item(idx);
aboveHint.setTop(visibleStart + 5);
if (!aboveHint.isVisible()) {
aboveHint.fadeIn({duration: 1.6});
}
}
if (belowEvents.length) {
var belowHint = this.belowHints.item(idx);
belowHint.setTop(visibleEnd - 14);
if (!belowHint.isVisible()) {
belowHint.fadeIn({duration: 1.6});
}
}
}, this);
var topOffset = this.scroller ? this.getHeightMinutes(this.scroller.dom.scrollTop) : null;
if (topOffset !== null) {
if (this.cropDayTime) {
topOffset = topOffset + this.dayStart.getHours() * 60 + this.dayStart.getMinutes();
}
this.lastScrollTime = this.dayStart.clearTime(true).add(Date.MINUTE, topOffset);
}
this.isScrolling = false;
},
/**
* renders a single event into this daysview
* @param {Tine.Calendar.Model.Event} event
*
* @todo Add support vor Events spanning over a day boundary
*/
insertEvent: function(event) {
if (! this.mainBody) {
// maybe another app is active and mainBody has not been rendered yet
return;
}
event.ui = new Tine.Calendar.DaysViewEventUI(event);
event.ui.render(this);
},
/**
* creates a new event directly from this view
* @param {} event
*/
createEvent: function(e, event) {
// only add range events if mouse is down long enough
if (this.editing || (event.isRangeAdd && ! this.mouseDown) || !event.isValid()) {
return;
}
// insert event silently into store
this.editing = event;
this.store.suspendEvents();
this.store.add(event);
this.store.resumeEvents();
// draw event
var registry = event.get('is_all_day_event') ? this.parallelWholeDayEventsRegistry : this.parallelScrollerEventsRegistry;
registry.register(event);
this.insertEvent(event);
this.onLayout();
//var eventEls = event.ui.getEls();
//eventEls[0].setStyle({'border-left-style': 'dashed'});
//eventEls[0].setOpacity(0.5);
// start sizing for range adds
if (event.isRangeAdd) {
// don't create events with very small duration
event.ui.resizeable.on('resize', function() {
if (event.get('is_all_day_event')) {
var keep = true;
} else {
var keep = (event.get('dtend').getTime() - event.get('dtstart').getTime()) / Date.msMINUTE >= this.timeIncrement;
}
if (keep) {
this.startEditSummary(event);
} else {
this.abortCreateEvent(event);
}
}, this);
// snap correction for rangeadds
var box = event.ui.resizeable.el.getBox(),
mouseXY = Ext.EventObject.getXY(),
startX = mouseXY[0],
startY = mouseXY[1],
handleX = box.x + box.width,
handleY = box.y + box.height;
event.ui.resizeable.correctionX = handleX - startX;
event.ui.resizeable.correctionY = handleY - startY;
event.ui.resizeable.snap = function(value, inc, min) {
var pos = this.activeHandle.position;
if (pos === 'south' && inc === this.heightIncrement) {
value = value - this.correctionY;
} else if (pos === 'east' && inc === this.widthIncrement) {
value = value - this.correctionX;
}
return Ext.Resizable.prototype.snap.call(this, value, inc, min);
};
var rzPos = event.get('is_all_day_event') ? 'east' : 'south';
event.ui.resizeable[rzPos].onMouseDown.call(event.ui.resizeable[rzPos], e);
// adjust initial size to avoid flickering when start resizing
event.ui.resizeable.onMouseMove(Ext.EventObject);
} else {
this.startEditSummary(event);
}
},
abortCreateEvent: function(event) {
this.store.remove(event);
this.editing = false;
},
startEditSummary: function(event) {
if (event.summaryEditor) {
return false;
}
var eventEls = event.ui.getEls();
var bodyCls = event.get('is_all_day_event') ? 'cal-daysviewpanel-wholedayevent-body' : 'cal-daysviewpanel-event-body';
event.summaryEditor = new Ext.form.TextArea({
event: event,
renderTo: eventEls[0].down('div[class=' + bodyCls + ']'),
width: event.ui.getEls()[0].getWidth() -12,
height: Math.max(12, event.ui.getEls()[0].getHeight() -18),
style: 'background-color: transparent; background: 0: border: 0; position: absolute; top: 0px; font-weight: bold; color: ' + event.ui.colorSet.text + ';' ,
value: this.newEventSummary,
maxLength: 255,
maxLengthText: this.app.i18n._('The summary must not exceed 255 characters.'),
minLength: 1,
minLengthText: this.app.i18n._('The summary must contain at least 1 character.'),
enableKeyEvents: true,
listeners: {
scope: this,
render: function(field) {
field.focus(true, 100);
},
blur: this.endEditSummary,
specialkey: this.endEditSummary,
keydown: this.endEditSummary
}
});
},
endEditSummary: function(f, e) {
if (! this.editing || this.validateMsg) {
return;
}
var field = this.editing.summaryEditor;
var event = field.event;
var summary = field.getValue();
// abort edit on ESC key
if (e && (e.getKey() == e.ESC)) {
this.abortCreateEvent(event);
return;
}
// only commit edit on Enter & blur
if (e && e.getKey() != e.ENTER) {
return;
}
// Validate Summary maxLength
if (summary.length > field.maxLength) {
field.markInvalid();
this.validateMsg = Ext.Msg.alert(this.app.i18n._('Summary too Long'), field.maxLengthText, function(){
field.focus();
this.validateMsg = false;
}, this);
return;
}
// Validate Summary minLength
if (!summary || summary.match(/^\s{1,}$/) || summary.length < field.minLength) {
field.markInvalid();
this.validateMsg = Ext.Msg.alert(this.app.i18n._('Summary too Short'), field.minLengthText, function(){
field.focus();
this.validateMsg = false;
}, this);
return;
}
this.editing = false;
event.summaryEditor = false;
event.set('summary', summary);
this.store.suspendEvents();
this.store.remove(event);
this.store.resumeEvents();
var registry = event.get('is_all_day_event') ? this.parallelWholeDayEventsRegistry : this.parallelScrollerEventsRegistry;
registry.unregister(event);
this.removeEvent(event);
event.dirty = true;
this.store.add(event);
this.fireEvent('addEvent', event);
},
onAppActivate: function(app) {
if (app === this.app) {
this.redrawWholeDayEvents();
}
},
onResize: function() {
Tine.Calendar.DaysView.superclass.onResize.apply(this, arguments);
this.updateDayHeaders();
this.redrawWholeDayEvents.defer(50, this);
this.unbufferedOnLayout();
},
redrawWholeDayEvents: function() {
this.store.each(function(event) {
// check if event is currently visible by looking into ui.domIds
if (event.ui && event.ui.domIds.length > 0 && event.get('is_all_day_event')) {
this.removeEvent(event);
this.insertEvent(event);
}
}, this);
},
onClick: function(e) {
// check for hint clicks first
var hint = e.getTarget('img[class^=cal-daysviewpanel-body-daycolumn-hint-]', 10, true);
if (hint) {
this.scroller.scroll(hint.hasClass('cal-daysviewpanel-body-daycolumn-hint-above') ? 't' : 'b', 10000, true);
return;
}
return Tine.Calendar.DaysView.superclass.onClick.call(this, e);
},
/**
* @private
*/
onDblClick: function(e, target) {
e.stopEvent();
var event = this.getTargetEvent(e);
var dtStart = this.getTargetDateTime(e);
if (event) {
if (event.dirty && this.editing ) {
event.set('summary', this.editing.summaryEditor.getValue());
event.summaryEditor = false;
this.editing = false;
this.abortCreateEvent.defer(500, this, [event]);
}
this.fireEvent('dblclick', event, e);
} else if (dtStart && !this.editing) {
var newId = 'cal-daysviewpanel-new-' + Ext.id();
var dtend = dtStart.add(Date.MINUTE, Tine.Calendar.Model.Event.getMeta('defaultEventDuration'));
if (dtStart.is_all_day_event) {
dtend = dtend.add(Date.HOUR, 23).add(Date.SECOND, -1);
}
// do not create an event exceeding the crop day time limit
else if (this.cropDayTime) {
var format = 'Hms';
if (dtStart.format(format) >= this.dayEnd.format(format)) {
return false;
}
if (dtend.format(format) >= this.dayEnd.format(format)) {
dtend.setHours(this.dayEnd.getHours());
dtend.setMinutes(this.dayEnd.getMinutes());
dtend.setSeconds(this.dayEnd.getSeconds());
}
}
var event = new Tine.Calendar.Model.Event(Ext.apply(Tine.Calendar.Model.Event.getDefaultData(), {
id: newId,
dtstart: dtStart,
dtend: dtend,
is_all_day_event: dtStart.is_all_day_event
}), newId);
this.createEvent(e, event);
event.dirty = true;
} else if (target.className == 'cal-daysviewpanel-dayheader-day'){
var dayHeaders = Ext.DomQuery.select('div[class=cal-daysviewpanel-dayheader-day]', this.innerHd);
var date = this.startDate.add(Date.DAY, dayHeaders.indexOf(target));
this.fireEvent('changeView', 'day', date);
}
},
/**
* @private
*/
onMouseDown: function(e) {
// don't care for right btn
if (e.button > 0) {
return;
}
if (! this.editing) {
this.focusEl.focus();
}
this.mouseDown = true;
var targetEvent = this.getTargetEvent(e);
if (this.editing && this.editing.summaryEditor && (targetEvent != this.editing)) {
this.editing.summaryEditor.fireEvent('blur', this.editing.summaryEditor, null);
return;
}
var sm = this.getSelectionModel();
sm.select(targetEvent);
var dtStart = this.getTargetDateTime(e),
dtEnd = this.getTargetDateTime(e, this.timeIncrement, 's');
if (dtStart && !this.readOnly) {
var newId = 'cal-daysviewpanel-new-' + Ext.id();
var event = new Tine.Calendar.Model.Event(Ext.apply(Tine.Calendar.Model.Event.getDefaultData(), {
id: newId,
dtstart: dtStart,
dtend: dtStart.is_all_day_event ? dtStart.add(Date.HOUR, 24).add(Date.SECOND, -1) : dtEnd,
is_all_day_event: dtStart.is_all_day_event
}), newId);
event.isRangeAdd = true;
event.dirty = true;
e.stopEvent();
e.preventDefault();
this.createEvent.defer(500, this, [e, event]);
}
},
/**
* @private
*/
onMouseUp: function() {
this.mouseDown = false;
},
/**
* @private
*/
onBeforeEventResize: function(rz, e) {
var me = this;
var parts = rz.el.id.split(':');
var event = this.store.getById(parts[1]);
this.getSelectionModel().select(event);
// @TODO compute max minutes also
var maxHeight = 10000;
if (this.cropDayTime) {
var maxMinutes = (this.dayEnd.getTimePart() - event.get('dtstart').getTimePart()) / Date.msMINUTE;
maxHeight = this.getTimeOffset(maxMinutes);
}
rz.heightIncrement = this.getTimeOffset(this.timeIncrement);
rz.maxHeight = maxHeight;
rz.event = event;
rz.originalHeight = rz.el.getHeight();
rz.originalWidth = rz.el.getWidth();
// NOTE: ext dosn't support move events via api
rz.onMouseMove = rz.onMouseMove.createSequence(function(e) {
var event = this.event;
if (! event) {
//event already gone -> late event / busy brower?
return;
}
var ui = event.ui;
var rzInfo = ui.getRzInfo(this);
if (e.type === 'mousemove') {
if (! event.get('is_all_day_event')) {
// getRzInfo calcs wrong values???
let shouldHeight = me.getTimeOffset(rzInfo.dtend) - me.getTimeOffset(event.get('dtstart'));
this.el.setHeight(shouldHeight);
}
if (this.durationEl) {
this.durationEl.update(rzInfo.dtend.format(event.get('is_all_day_event') ? Ext.form.DateField.prototype.format : 'H:i'));
}
}
}, rz);
// adjust initial size to avoid flickering when start resizing
if (e.getTarget('.x-resizable-handle-south')) {
event.ui.resizeable.onMouseMove(e);
}
event.ui.markDirty();
// NOTE: Ext keeps proxy if element is not destroyed (diff !=0)
if (! rz.durationEl) {
rz.durationEl = rz.el.insertFirst({
'class': 'cal-daysviewpanel-event-rzduration',
'style': 'position: absolute; bottom: 3px; right: 2px; z-index: 1000;'
});
}
rz.durationEl.update(event.get('dtend').format(event.get('is_all_day_event') ? Ext.form.DateField.prototype.format : 'H:i'));
},
/**
* @private
*/
onEventResize: function(rz, width, height) {
var event = rz.event;
if (! event) {
//event already gone -> late event / busy brower?
return;
}
var rzInfo = event.ui.getRzInfo(rz, width, height);
if (rzInfo.diff != 0) {
if (rzInfo.duration > 0) {
event.set('dtend', rzInfo.dtend);
} else {
// force event length to at least 1 minute
var date = new Date(event.get('dtstart').getTime());
date.setMinutes(date.getMinutes() + 1);
event.set('dtend', date);
}
}
if (event.summaryEditor) {
event.summaryEditor.setHeight(event.ui.getEls()[0].getHeight() -18);
}
// don't fire update events on rangeAdd
if (rzInfo.diff != 0 && event != this.editing && ! event.isRangeAdd) {
this.fireEvent('updateEvent', event);
} else if (event.isRangeAdd) {
event.ui.clearDirty();
} else {
// NOTE: we need to redraw event as resizer is broken after one attempt
this.removeEvent(event);
this.insertEvent(event);
this.getSelectionModel().select(event);
}
},
getParallelEventRegistry: function(event, original) {
var isAllDayEvent = original && event.modified.hasOwnProperty('is_all_day_event') ?
event.modified.is_all_day_event :
event.get('is_all_day_event');
return isAllDayEvent ?
this.parallelWholeDayEventsRegistry :
this.parallelScrollerEventsRegistry;
},
initParallelEventRegistry: function(event) {
this.parallelScrollerEventsRegistry = new Tine.Calendar.ParallelEventsRegistry({dtStart: this.startDate, dtEnd: this.endDate});
this.parallelWholeDayEventsRegistry = new Tine.Calendar.ParallelEventsRegistry({dtStart: this.startDate, dtEnd: this.endDate});
},
/**
* print wrapper
*/
print: function(printMode) {
var renderer = new this.printRenderer({printMode: printMode});
renderer.print(this);
},
getPeriod: function() {
var tbar = this.findParentBy(function(c) {return c.getTopToolbar()});
if (tbar) {
tbar = tbar.getTopToolbar();
}
return tbar && tbar.periodPicker ? tbar.periodPicker.getPeriod() : {
from: this.startDate,
until: this.startDate.add(Date.DAY, this.numOfDays)
};
},
/**
* get date of a (event) target
*
* @param {Ext.EventObject} e
* @param {number} graticule
* @param {char} graticuleEdge one of n (north) s, (south)
* @return {Date}
*/
getTargetDateTime: function(e, graticule, graticuleHandle) {
var target = e.getTarget('div[class^=cal-daysviewpanel-datetime]');
if (target && target.id.match(/^ext-gen\d+:\d+/)) {
var parts = target.id.split(':');
var date = this.startDate.add(Date.DAY, parseInt(parts[1], 10));
date.is_all_day_event = true;
if (parts[2] ) {
var timePart = this.timeScale.getAt(parts[2]),
eventXY = e.getXY(),
mainBodyXY = this.mainBody.getXY(),
offsetPx = eventXY[1] - mainBodyXY[1],
offsetMinutes = this.getHeightMinutes(offsetPx),
graticule = graticule ? graticule : this.timeGranularity,
graticuleHandle = graticuleHandle ? graticuleHandle : 'n',
graticuleFn = graticuleHandle == 'n' ? Math.floor : Math.ceil;
// constraint to graticule
offsetMinutes = graticuleFn(offsetMinutes/graticule) * graticule;
date = date.add(Date.MINUTE, offsetMinutes);
date.is_all_day_event = false;
}
return date;
}
},
/**
* get offset in px for the time part of given date (with current scaling)
*
* @param {date} date
* @returns {number}
*/
getTimeOffset: function(date) {
if (this.mainBody) {
var minutes = Ext.isDate(date) ? date.getTimePart() / Date.msMINUTE : date,
d = this.getMainBodyHeight() / (24 * 60);
return Math.round(d * minutes);
}
},
/**
* get offset in % for the time part of given date
*
* @param {date|number} date
* @returns {number}
*/
getTimeOffsetPct: function(date) {
var minutes = Ext.isDate(date) ? date.getTimePart() / Date.msMINUTE : date;
return 100 * ((Date.msMINUTE * minutes) / Date.msDAY);
},
/**
* get height in px of the diff for the given dates (with current scaling)
*
* @param {date} dtStart
* @param {date} dtEnd
* @returns {number}
*/
getTimeHeight: function(dtStart, dtEnd) {
if (this.mainBody) {
var d = this.getMainBodyHeight() / (24 * 60);
return Math.round(d * ((dtEnd.getTime() - dtStart.getTime()) / Date.msMINUTE));
}
},
/**
* get height in % of the diff for the given dates
*
* @param {date} dtStart
* @param {date} dtEnd
* @returns {number}
*/
getTimeHeightPct: function(dtStart, dtEnd) {
return 100 * ((dtEnd.getTime() - dtStart.getTime()) / Date.msDAY);
},
/**
* get number of minutes represented by height in px (current scaleing)
*
* @param {number} height
* @returns {number}
*/
getHeightMinutes: function(height) {
var d = (24 * 60) / this.getMainBodyHeight();
return Math.round(d * height);
},
getMainBodyHeight: function() {
if (! this.mainBody) {
// maybe another app is active
return 0;
}
var height = this.mainBody.getHeight();
// hidden atm.
if (! height) {
height = parseInt(this.mainBody.dom.style.height, 10);
}
return height;
},
/**
* fetches elements from our generated dom
*/
initElements : function(){
var E = Ext.Element;
var cs = this.el.dom.firstChild.childNodes;
this.mainWrap = new E(cs[0]);
this.mainHd = new E(this.mainWrap.dom.firstChild);
this.innerHd = this.mainHd.dom.firstChild;
this.wholeDayScroller = new E(this.innerHd.firstChild.childNodes[1]);
this.wholeDayArea = this.wholeDayScroller.dom.firstChild;
this.scroller = new E(this.mainWrap.dom.childNodes[1]);
this.scroller.setStyle('overflow-x', 'hidden');
this.mon(this.scroller, 'mousewheel', this.onMouseWheel, this);
this.mon(this.scroller, 'scroll', this.onBeforeScroll, this);
this.mon(this.scroller, 'scroll', this.onScroll, this, {buffer: 200});
this.cropper = new E(this.scroller.dom.firstChild);
this.mainBody = new E(this.cropper.dom.firstChild);
this.dayCols = this.mainBody.dom.lastChild.childNodes;
this.focusEl = new E(this.el.dom.lastChild.lastChild);
this.focusEl.swallowEvent("click", true);
this.focusEl.swallowEvent("dblclick", true);
this.focusEl.swallowEvent("contextmenu", true);
this.aboveHints = this.mainBody.select('img[class=cal-daysviewpanel-body-daycolumn-hint-above]');
this.belowHints = this.mainBody.select('img[class=cal-daysviewpanel-body-daycolumn-hint-below]');
},
/**
* @TODO this returns wrong cols on DST boundaries:
* e.g. on DST switch form +2 to +1 an all day event is 25 hrs. long
*
* @param {} date
* @return {}
*/
getColumnNumber: function(date) {
return Math.floor((date.add(Date.SECOND, 1).getTime() - this.startDate.getTime()) / Date.msDAY);
},
getDateColumnEl: function(pos) {
return this.dayCols[pos];
},
checkWholeDayEls: function() {
var freeIdxs = [];
for (var i=0; i<this.wholeDayArea.childNodes.length-1; i++) {
if(this.wholeDayArea.childNodes[i].childNodes.length === 1) {
freeIdxs.push(i);
}
}
for (var i=1; i<freeIdxs.length; i++) {
Ext.fly(this.wholeDayArea.childNodes[freeIdxs[i]]).remove();
}
},
/**
* buffered version of this.unbufferedOnLayout
* @see this.initComponent
*/
onLayout: Ext.emptyFn,
/**
* layouts the view
*/
unbufferedOnLayout: function() {
Tine.Calendar.DaysView.superclass.onLayout.apply(this, arguments);
if(!this.mainBody){
return; // not rendered
}
var csize = this.container.getSize(true),
vw = csize.width;
if (! vw) {
return; // hidden
}
this.el.setSize(csize.width, csize.height);
// layout whole day area -> take one third of the available height maximum
var wholeDayAreaEl = Ext.get(this.wholeDayArea),
wholeDayAreaHeight = this.computeAllDayAreaHeight(),
wholeDayScrollerHeight = wholeDayAreaHeight,
maxAllowedHeight = Math.round(csize.height/4),
resizeEvent = {
wholeDayAreaHeight: wholeDayAreaHeight,
wholeDayScrollerHeight: Math.min(wholeDayAreaHeight, maxAllowedHeight),
maxAllowedHeight: maxAllowedHeight
};
wholeDayAreaEl.setHeight(wholeDayAreaHeight);
this.fireEvent('onBeforeAllDayScrollerResize', this, resizeEvent);
this.wholeDayScroller.setHeight(resizeEvent.wholeDayScrollerHeight);
var hdHeight = this.mainHd.getHeight();
var vh = csize.height - (hdHeight);
this.scroller.setSize(vw, vh);
// resize mainBody for visibleMinutes to fit
var timeToDisplay = this.timeVisible.getTime() / Date.msMINUTE,
scrollerHeight = this.scroller.getHeight(),
height = scrollerHeight * (24 * 60)/timeToDisplay;
this.mainBody.setHeight(height);
if (this.cropDayTime) {
var cropHeightPx = this.getTimeHeight(this.dayStart, this.dayEnd),
cropStartPx = this.getTimeOffset(this.dayStart);
this.cropper.setStyle('height', cropHeightPx + 'px');
this.cropper.dom.scrollTop = cropStartPx;
}
if (! this.initialScrolled) {
// scrollTo initial position
this.isScrolling = true;
this.scrollTo(this.defaultStart);
this.initialScrolled = true;
}
// force positioning on scroll hints
this.onBeforeScroll.defer(50, this);
this.onScroll.defer(100, this);
},
computeAllDayAreaHeight: function() {
var wholeDayAreaEl = Ext.get(this.wholeDayArea);
for (var i=0, bottom = wholeDayAreaEl.getTop(); i<this.wholeDayArea.childNodes.length -1; i++) {
bottom = Math.max(parseInt(Ext.get(this.wholeDayArea.childNodes[i]).getBottom(), 10), bottom);
}
// take one third of the available height maximum
return bottom - wholeDayAreaEl.getTop() + this.minAllDayScrollerHight;
},
/**
* returns HTML frament of the day headers
*/
getDayHeaders: function() {
var html = '';
var width = 100/this.numOfDays;
for (var i=0, date; i<this.numOfDays; i++) {
var day = this.startDate.add(Date.DAY, i);
html += this.templates.dayHeader.applyTemplate({
day: String.format(this.dayFormatString, day.format('l'), day.format('j'), day.format('F')),
height: '20px',
width: width + '%',
left: i * width + '%'
});
}
return html;
},
/**
* updates HTML of day headers
*/
updateDayHeaders: function() {
if (! this.rendered) return;
var dayHeaders = Ext.DomQuery.select('div[class=cal-daysviewpanel-dayheader-day]', this.innerHd),
dayWidth = dayHeaders ? Ext.get(dayHeaders[0]).getWidth() : [],
headerString;
for (var i=0, date, isToDay, headerEl, dayColEl; i<dayHeaders.length; i++) {
date = this.startDate.add(Date.DAY, i);
isToDay = date.getTime() == new Date().clearTime().getTime();
headerEl = Ext.get(dayHeaders[i]);
if (dayWidth > 150) {
headerString = String.format(this.dayFormatString, date.format('l'), date.format('j'), date.format('F'));
} else if (dayWidth > 60){
headerString = date.format('D') + ', ' + date.format('j') + '.' + date.format('n');
} else {
headerString = date.format('j') + '.' + date.format('n');
}
headerEl.update(headerString);
headerEl.parent()[(isToDay ? 'add' : 'remove') + 'Class']('cal-daysviewpanel-dayheader-today');
Ext.get(this.dayCols[i])[(isToDay ? 'add' : 'remove') + 'Class']('cal-daysviewpanel-body-daycolumn-today');
}
},
/**
* returns HTML fragment of the whole day cols
*/
getWholeDayCols: function() {
var html = '';
var width = 100/this.numOfDays;
var baseId = Ext.id();
for (var i=0; i<this.numOfDays; i++) {
html += this.templates.wholeDayCol.applyTemplate({
//day: date.get('dateString'),
id: baseId + ':' + i,
width: width + '%',
left: i * width + '%'
});
};
return html;
},
/**
* gets HTML fragment of the horizontal time rows
*/
getTimeRows: function() {
var html = '';
this.timeScale.each(function(time){
var index = time.get('index');
html += this.templates.timeRow.applyTemplate({
cls: time.get('minutes')%60 ? 'cal-daysviewpanel-timeRow-off' : 'cal-daysviewpanel-timeRow-on',
height: 100/(24 * 60 / this.timeGranularity) + '%',
time: time.get('minutes')%60 ? '' : time.get('time')
});
}, this);
return html;
},
/**
* gets HTML fragment of the day columns
*/
getDayColumns: function() {
var html = '';
var width = 100/this.numOfDays;
for (var i=0; i<this.numOfDays; i++) {
html += this.templates.dayColumn.applyTemplate({
width: width + '%',
left: i * width + '%',
overRows: this.getOverRows(i)
});
}
return html;
},
/**
* gets HTML fragment of the time over rows
*/
getOverRows: function(dayIndex) {
var html = '',
baseId = Ext.id();
this.timeScale.each(function(time, index, totalCount) {
var cls = 'cal-daysviewpanel-daycolumn-row-' + (time.get('minutes')%60 ? 'off' : 'on');
if (index+1 == totalCount) {
cls += ' cal-daysviewpanel-daycolumn-row-last';
}
html += this.templates.overRow.applyTemplate({
id: baseId + ':' + dayIndex + ':' + index,
cls: cls,
height: 100/(24 * 60 / this.timeGranularity) + '%',
time: time.get('time')
});
}, this);
return html;
},
/**
* inits all tempaltes of this view
*/
initTemplates: function() {
var ts = this.templates || {};
ts.master = new Ext.XTemplate(
'<div class="cal-daysviewpanel" hidefocus="true">',
'<div class="cal-daysviewpanel-viewport">',
'<div class="cal-daysviewpanel-header">',
'<div class="cal-daysviewpanel-header-inner">',
'<div class="cal-daysviewpanel-header-offset">{header}</div>',
'</div>',
'<div class="x-clear"></div>',
'</div>',
'<div class="cal-daysviewpanel-scroller">',
'<div class="cal-daysviewpanel-cropper">{body}</div>',
'</div>',
'</div>',
'<a href="#" class="cal-daysviewpanel-focus" tabIndex="-1"></a>'
);
ts.header = new Ext.XTemplate(
'<div class="cal-daysviewpanel-daysheader">{daysHeader}</div>',
'<div class="cal-daysviewpanel-wholedayheader-scroller">',
'<div class="cal-daysviewpanel-wholedayheader">',
'<div class="cal-daysviewpanel-wholedayheader-daycols">{wholeDayCols}</div>',
'</div>',
'</div>'
);
ts.dayHeader = new Ext.XTemplate(
'<div class="cal-daysviewpanel-dayheader" style="height: {height}; width: {width}; left: {left};">' +
'<div class="cal-daysviewpanel-dayheader-day-wrap">' +
'<div class="cal-daysviewpanel-dayheader-day">{day}</div>' +
'</div>',
'</div>'
);
ts.wholeDayCol = new Ext.XTemplate(
'<div class="cal-daysviewpanel-body-wholedaycolumn" style="left: {left}; width: {width};">' +
'<div id="{id}" class="cal-daysviewpanel-datetime cal-daysviewpanel-body-wholedaycolumn-over"> </div>' +
'</div>'
);
ts.body = new Ext.XTemplate(
'<div class="cal-daysviewpanel-body">',
'<div class="cal-daysviewpanel-body-timecolumn">{timeRows}</div>',
'<div class="cal-daysviewpanel-body-daycolumns">{dayColumns}</div>',
'</div>'
);
ts.timeRow = new Ext.XTemplate(
'<div class="{cls}" style="height: {height}; top: {top};">',
'<div class="cal-daysviewpanel-timeRow-time">{time}</div>',
'</div>'
);
ts.dayColumn = new Ext.XTemplate(
'<div class="cal-daysviewpanel-body-daycolumn" style="left: {left}; width: {width}; height: 100%">',
'<div class="cal-daysviewpanel-body-daycolumn-inner"> </div>',
'{overRows}',
'<img src="', Ext.BLANK_IMAGE_URL, '" class="cal-daysviewpanel-body-daycolumn-hint-above" />',
'<img src="', Ext.BLANK_IMAGE_URL, '" class="cal-daysviewpanel-body-daycolumn-hint-below" />',
'</div>'
);
ts.overRow = new Ext.XTemplate(
'<div id="{id}" class="cal-daysviewpanel-datetime cal-daysviewpanel-daycolumn-row" style="height: {height};">' +
'<div class="{cls}" >{time}</div>'+
'</div>'
);
ts.event = new Ext.XTemplate(
'<div id="{id}" class="cal-daysviewpanel-event {extraCls}" style="width: {width}; height: {height}; left: {left}; top: {top}; z-index: {zIndex}; background-color: {bgColor};">',
'<div style="position: absolute; height: 100%; width: 4px; left: 0; top: 0; background: {infoColors}"></div>',
'<div class="cal-daysviewpanel-event-header" style="background-color: {bgColor};">',
'<div class="cal-daysviewpanel-event-header-inner" style="background-color: {bgColor}; z-index: {zIndex};">{startTime}</div>',
'<div class="cal-daysviewpanel-event-header-icons">',
'<tpl for="statusIcons">',
'<img src="', Ext.BLANK_IMAGE_URL, '" class="cal-status-icon {parent.textColor} {status}-black" ext:qtip="{[this.encode(values.text)]}" />',
'</tpl>',
'</div>',
'</div>',
'<div class="cal-daysviewpanel-event-body">{[Ext.util.Format.nl2br(Ext.util.Format.htmlEncode(values.summary))]}</div>',
'<div class="cal-daysviewpanel-event-tags">{tagsHtml}</div>',
'</div>',
{
encode: function(v) { return Tine.Tinebase.common.doubleEncode(v); }
}
);
ts.wholeDayEvent = new Ext.XTemplate(
'<div id="{id}" class="cal-daysviewpanel-event {extraCls}" style="width: {width}; height: {height}; left: {left}; top: {top}; z-index: {zIndex}; background-color: {bgColor}; border-color: {color};">' +
'<div class="cal-daysviewpanel-wholedayevent-tags">{tagsHtml}</div>' +
'<div class="cal-daysviewpanel-wholedayevent-body">{[Ext.util.Format.nl2br(Ext.util.Format.htmlEncode(values.summary))]}</div>' +
'<div class="cal-daysviewpanel-event-header-icons" style="background-color: {bgColor};" >' +
'<tpl for="statusIcons">' +
'<img src="', Ext.BLANK_IMAGE_URL, '" class="cal-status-icon {status}-black" ext:qtip="{[this.encode(values.text)]}" />',
'</tpl>' +
'</div>' +
'</div>',
{
encode: function(v) { return Tine.Tinebase.common.doubleEncode(v); }
}
);
for(var k in ts){
var t = ts[k];
if(t && typeof t.compile == 'function' && !t.compiled){
t.disableFormats = true;
t.compile();
}
}
this.templates = ts;
}
});
Ext.reg('Tine.Calendar.DaysView', Tine.Calendar.DaysView);