aolists-webtop
Version:
Web interface for aoLists
1,023 lines (824 loc) • 26.6 kB
JavaScript
/**
* Copyright Intermesh
*
* This file is part of Group-Office. You should have received a copy of the
* Group-Office license along with Group-Office. See the file /LICENSE.TXT
*
* If you have questions write an e-mail to info@intermesh.nl
*
* @copyright Copyright Intermesh
* @version $Id: MonthGrid.js 2780 2009-07-06 14:40:08Z mschering $
* @author Merijn Schering <mschering@intermesh.nl>
*/
Ext.ux.go.grid.MonthGrid = Ext.extend(Ext.Panel, {
/**
* @cfg {String} The components handles dates in this format
*/
dateFormat : 'Y-m-d',
/**
* @cfg {String} The components handles dates in this format
*/
dateTimeFormat : 'Y-m-d H:i',
timeFormat : 'H:i',
/**
* @cfg {Number} Start day of the week. Monday or sunday
*/
firstWeekday : 1,
/**
* @cfg {Date} The date set by the user
*/
configuredDate : false,
/**
* @cfg {Date} The date where the grid starts. This can be recalculated after a user sets a date
*/
startDate : false,
//private var that is used when an event is dragged to another location
dragEvent : false,
//all the grid appointments are stored in this array. First index is day and second is the dom ID.
appointments : Array(),
//The remote database ID's can be stored in this array. Useful for database updates
remoteEvents : Array(),
//domids that need to be moved along with another. When an event spans multiple days
domIds : Array(),
//eventIdToDomId : {},
//amount of days to display
days : 1,
selected : Array(),
writePermission : false,
/**
* The amount of space to reserve for the scrollbar (defaults to 19 pixels)
* @type Number
*/
scrollOffset: 22,
gridEvents : {},
weekNumberWidth : 16,
// private
initComponent : function(){
this.autoScroll=true;
this.addEvents({
'showday' :true,
/**
* @event click
* Fires when this button is clicked
* @param {Button} this
* @param {EventObject} e The click event
*/
"create" : true,
/**
* @event toggle
* Fires when the "pressed" state of this button changes (only if enableToggle = true)
* @param {Button} this
* @param {Boolean} pressed
*/
"move" : true,
"eventResize" : true,
"eventDblClick" : true
});
if(this.store){
this.setStore(this.store, true);
}
if(!this.startDate)
{
//lose time
var date = new Date();
this.startDate=Date.parseDate(date.format(this.dateFormat), this.dateFormat);
}
this.configuredDate=this.startDate;
Ext.ux.go.grid.MonthGrid.superclass.initComponent.call(this);
},
//build the html grid
afterRender : function(){
Ext.ux.go.grid.MonthGrid.superclass.afterRender.call(this);
//important to do here. Don't remember why :S
this.setDate(this.startDate, false);
//if this is not set the grid does not display well when I put a load mask on it.
//this.body.setStyle("overflow", "hidden");
//Don't select things inside the grid
this.body.unselectable();
//this.renderMonthView();
this.setStore(this.store);
this.initDD();
},
renderMonthView : function()
{
this.body.update('');
var currentMonthStr = this.configuredDate.format('Ym');
var currentDate = new Date();
var currentDateStr = currentDate.format('Ymd');
var weekDay=0;
var cellClass = '';
var dateFormat;
this.cellWrap = Ext.DomHelper.append(this.body,{tag:'div'}, true);
this.gridCells={};
this.weekNumberCells=[];
for(var day=0;day<this.days;day++)
{
var dt = this.startDate.add(Date.DAY, day);
if(day == 0 || dt.format('j')==1)
{
dateFormat = 'j F';
}else
{
dateFormat = 'j';
}
var weekday = dt.format('w');
var monthStr = dt.format('Ym');
var dateStr = dt.format('Ymd');
if(weekday==this.firstWeekday)
{
var weekNo = dt.format('W');
var cell = Ext.DomHelper.append(this.cellWrap,
{
tag: 'div',
style: 'width:'+(this.weekNumberWidth-1)+'px',
cls: 'cal-monthgrid-week-no'
}, true);
var weekLink = Ext.DomHelper.append(cell,{
tag: 'a',
cls: 'x-monthGrid-cell-day-text',
href: '#',
id:'wl-'+dateStr,
html: weekNo
}, true);
weekLink.on('click', this.onWeekClick, this);
this.weekNumberCells.push(cell);
}
if(dateStr==currentDateStr)
{
cellClass = 'cal-monthGrid-cell x-monthGrid-cell-today';
}else if(monthStr==currentMonthStr && (weekday==0 || weekday==6))
{
cellClass = 'cal-monthGrid-cell x-monthGrid-cell-weekend';
}else if (monthStr==currentMonthStr)
{
cellClass = 'cal-monthGrid-cell x-monthGrid-cell-current';
}else
{
cellClass = 'cal-monthGrid-cell';
}
var id = 'd'+dateStr;
var cell = Ext.DomHelper.append(this.cellWrap,
{
tag: 'div',
id: id,
cls: cellClass
}, true);
var dayLink = Ext.DomHelper.append(cell,{
tag: 'a',
cls: 'x-monthGrid-cell-day-text',
href: '#',
html: dt.format(dateFormat)
}, true);
dayLink.on('click', this.onAddClick, this);
this.gridCells[dateStr]=cell;
}
this.syncSize();
},
onMoreClick : function(e, target)
{
var cell = Ext.get(target).findParent('div.cal-monthGrid-cell', 3);
var date = Date.parseDate(cell.id.substring(1, cell.id.length),'Ymd');
this.fireEvent('changeview', this, 1, date);
},
onWeekClick : function(e, target){
var date = Date.parseDate(target.id.substring(3, target.id.length),'Ymd');
this.fireEvent('changeview', this, 7, date);
},
onAddClick : function(e, target){
var cell = Ext.get(target).findParent('div.cal-monthGrid-cell', 3);
var date = Date.parseDate(cell.id.substring(1, cell.id.length),'Ymd');
this.fireEvent('create', this, date);
},
onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
Ext.grid.GridPanel.superclass.onResize.apply(this, arguments);
this.syncSize();
this.checkOverflow();
},
calcCellSize : function (ctSize, scrollOffsetUsed)
{
this.cellHeight = (ctSize['height']/(this.days/7));
if(this.cellHeight<100)
{
this.cellHeight=100;
if(!scrollOffsetUsed)
{
ctSize['width']-= this.scrollOffset;
}
}
this.cellWidth = ((ctSize['width']-this.weekNumberWidth)/7);
if(this.cellWidth<100)
{
this.cellWidth=100;
ctSize['height']-= this.scrollOffset;
if(!scrollOffsetUsed)
{
this.calcCellSize(ctSize, true);
}
}
this.cellHeight=Math.floor(this.cellHeight);
this.cellWidth=Math.floor(this.cellWidth);
},
checkOverflow : function(){
if(this.overflowIndicators)
{
for(var i=0;i<this.overflowIndicators.length;i++)
this.overflowIndicators[i].remove();
}
this.overflowIndicators=[];
for(var i in this.gridCells)
{
if(this.gridCells[i].dom.scrollHeight>this.gridCells[i].dom.clientHeight)
{
var el = Ext.DomHelper.append(this.gridCells[i],
{
tag: 'a',
cls: 'cal-overflow-indicator',
href: '#',
html: Ext.ux.go.lang.more+'...'
}, true);
el.on('click', this.onMoreClick, this);
var pos = this.gridCells[i].getXY();
el.setXY(pos);
this.overflowIndicators.push(el);
}
}
},
syncSize : function(){
if(this.cellWrap)
{
//get content size of element
var ctSize = this.container.getSize(true);
this.calcCellSize(ctSize);
this.cellWrap.setSize(this.cellWidth*7+this.weekNumberWidth, this.cellHeight*(this.days/7));
for(var i in this.gridCells)
{
this.gridCells[i].setSize(this.cellWidth, this.cellHeight);
}
for(var i=0;i<this.weekNumberCells.length;i++)
{
this.weekNumberCells[i].setHeight(this.cellHeight);
}
for(var d in this.gridEvents)
{
for(var i=0;i<this.gridEvents[d].length;i++)
this.gridEvents[d][i].setWidth(this.cellWidth-3);
}
}
},
initDD : function(){
var dragZone = new Ext.ux.go.calendar.dd.MonthDragZone(this.body, {
ddGroup: 'month-grid',
scroll: false,
monthGrid: this
});
var dropTarget = new Ext.ux.go.calendar.dd.MonthDropTarget(this.body, {
ddGroup: 'month-grid',
onNotifyDrop : function(dd, e, data) {
//number of seconds moved
var dragTime = data.dragDate.format('U');
var dropTime = data.dropDate.format('U');
offsetDays = Math.round((dropTime-dragTime)/86400);
var actionData = {offsetDays:offsetDays, dragDate: data.dragDate};
var remoteEvent = this.elementToEvent(data.item.id);
if(remoteEvent['repeats'])
{
this.handleRecurringEvent("move", remoteEvent, actionData);
}else
{
this.fireEvent("move", this, remoteEvent, actionData);
this.removeEvent(remoteEvent.domId);
delete remoteEvent.domId;
remoteEvent.repeats=false;
remoteEvent.startDate = remoteEvent.startDate.add(Date.DAY, offsetDays);
remoteEvent.endDate = remoteEvent.endDate.add(Date.DAY, offsetDays);
remoteEvent.start_time = remoteEvent.startDate.format('U');
remoteEvent.end_time = remoteEvent.endDate.format('U');
this.addMonthGridEvent(remoteEvent);
}
},
scope : this
});
},
setStore : function(store, initial){
if(!initial && this.store){
this.store.un("beforeload", this.reload);
this.store.un("datachanged", this.reload);
this.store.un("clear", this.reload);
}
if(store){
store.on("beforeload", this.mask, this);
store.on("datachanged", this.reload, this);
store.on("clear", this.reload, this);
}
this.store = store;
},
setStoreBaseParams : function(){
this.store.baseParams['start_time']=this.startDate.format(this.dateTimeFormat);
this.store.baseParams['end_time']=this.endDate.format(this.dateTimeFormat);
},
getFirstDateOfWeek : function(date)
{
//Calculate the first day of the week
var weekday = date.getDay();
if(weekday<this.firstWeekday)
weekday=7;
return date.add(Date.DAY, this.firstWeekday-weekday);
},
mask : function()
{
if(this.rendered)
{
this.body.mask(Ext.ux.go.lang.waitMsgLoad,'x-mask-loading');
}
},
unmask : function()
{
if(this.rendered)
{
this.body.unmask();
}
},
getSelectedEvent : function()
{
if(this.selected)
{
return this.elementToEvent(this.selected[0].id);
}
},
isSelected : function(eventEl)
{
for (var i=0;i<this.selected.length;i++)
{
if(this.selected[i].id==eventEl)
{
return true;
}
}
return false;
},
clearSelection : function()
{
for (var i=0;i<this.selected.length;i++)
{
this.selected[i].removeClass('x-calGrid-selected');
}
this.selected=[];
},
selectEventElement : function(eventEl)
{
if(!this.isSelected(eventEl))
{
this.clearSelection();
var elements = this.getRelatedDomElements(eventEl.id);
for (var i=0;i<elements.length;i++)
{
var element = Ext.get(elements[i]);
if(element)
{
element.addClass('x-calGrid-selected');
this.selected.push(element);
}
}
}
},
addMonthGridEvent : function (eventData)
{
//the start of the day the event starts
var eventStartDay = Date.parseDate(eventData.startDate.format('Ymd'),'Ymd');
var eventEndDay = Date.parseDate(eventData.endDate.format('Ymd'),'Ymd');
//get unix timestamps
var eventStartTime = eventStartDay.format('U');
var eventEndTime = eventEndDay.format('U');
//ceil required because of DST changes!
var daySpan = Math.round((eventEndTime-eventStartTime)/86400)+1;
//var daySpan = Math.round((eventEndTime-eventStartTime)/86400);
for(var i=0;i<daySpan;i++)
{
var date = eventStartDay.add(Date.DAY, i);
eventData.domId = Ext.id();
//related events for dragging
if(daySpan>1)
{
if(!this.domIds[eventData.id])
{
this.domIds[eventData.id]=[];
}
this.domIds[eventData.id].push(eventData.domId);
}
var col = Ext.get('d'+date.format('Ymd'));
if(col)
{
var text = '';
if(eventData.startDate.format('G')!='0')
{
text += eventData.startDate.format(Ext.ux.go.settings.time_format)+' ';
}
text += eventData['name'];
var event = Ext.DomHelper.append(col,
{
tag: 'div',
id: eventData.domId,
cls: "x-calGrid-month-event-container",
style:"background-color:#"+eventData.background+';width:'+(this.eventWidth)+'px',
html: text,
qtip: Ext.ux.go.calendar.formatQtip(eventData),
qtitle:eventData.name
}, true);
var dateStr = date.format('Ymd');
if(!this.gridEvents[dateStr])
{
this.gridEvents[dateStr]=[];
}
this.gridEvents[dateStr].push(event);
this.registerEvent(eventData.domId, eventData);
event.on('mousedown', function(e, eventEl){
eventEl = Ext.get(eventEl).findParent('div.x-calGrid-month-event-container', 2, true);
this.selectEventElement(eventEl);
this.clickedEventId=eventEl.id;
}, this);
event.on('dblclick', function(e, eventEl){
eventEl = Ext.get(eventEl).findParent('div.x-calGrid-month-event-container', 2, true);
//this.eventDoubleClicked=true;
var event = this.elementToEvent(this.clickedEventId);
if(event['repeats'] && this.writePermission)
{
this.handleRecurringEvent("eventDblClick", event, {});
}else
{
this.fireEvent("eventDblClick", this, event, {singleInstance : this.writePermission});
}
}, this);
}
}
if(!this.loading)
this.checkOverflow();
return eventData.domId;
},
/*
* Removes a single event and it's associated dom elements
*/
removeEvent : function(domId){
var ids = this.getRelatedDomElements(domId);
if(ids)
{
for(var i=0;i<ids.length;i++)
{
var el = Ext.get(ids[i]);
if(el)
{
el.removeAllListeners();
el.remove();
}
this.unregisterDomId(ids[i]);
}
}
this.checkOverflow();
},
unregisterDomId : function(domId)
{
delete this.remoteEvents[domId];
var found = false;
for(var e in this.domIds)
{
for(var i=0;i<this.domIds[e].length;i++)
{
if(this.domIds[e][i]==domId)
{
this.domIds[e].splice(i,1);
found=true;
break;
}
}
if(found)
{
break;
}
}
},
setNewEventId : function(dom_id, new_event_id){
this.remoteEvents[dom_id].event_id=new_event_id;
},
handleRecurringEvent : function(fireEvent, event, actionData){
//store them here so the already created window can use these values
this.currentRecurringEvent = event;
this.currentFireEvent=fireEvent;
this.currentActionData = actionData;
if(!this.recurrenceDialog)
{
this.recurrenceDialog = new Ext.Window({
width:400,
autoHeight:true,
closeable:false,
closeAction:'hide',
plain:true,
border: false,
title:Ext.ux.go.calendar.lang.recurringEvent,
modal:false,
html: Ext.ux.go.calendar.lang.editRecurringEvent,
buttons: [{
text: Ext.ux.go.calendar.lang.singleOccurence,
handler: function(){
this.currentActionData.singleInstance=true;
var remoteEvent = this.currentRecurringEvent;
this.fireEvent(this.currentFireEvent, this, remoteEvent , this.currentActionData);
if(this.currentActionData.offsetDays)
{
this.removeEvent(remoteEvent.domId);
remoteEvent.repeats=false;
remoteEvent.startDate = remoteEvent.startDate.add(Date.DAY, offsetDays);
remoteEvent.endDate = remoteEvent.endDate.add(Date.DAY, offsetDays);
remoteEvent.start_time = remoteEvent.startDate.format('U');
remoteEvent.end_time = remoteEvent.endDate.format('U');
this.addMonthGridEvent(remoteEvent);
}
this.recurrenceDialog.hide();
},
scope: this
},{
text: Ext.ux.go.calendar.lang.entireSeries,
handler: function(){
this.currentActionData.singleInstance=false;
this.fireEvent(this.currentFireEvent, this, this.currentRecurringEvent, this.currentActionData);
this.recurrenceDialog.hide();
},
scope: this
}]
});
}
this.recurrenceDialog.show();
},
clearGrid : function()
{
this.gridEvents={};
this.appointments=Array();
this.remoteEvents=Array();
this.domIds=Array();
},
setDate : function(date, load)
{
var oldStartDate = this.startDate;
var oldEndDate = this.endDate;
this.configuredDate = date;
//calculate first date of month
var firstDateOfMonth = date.getFirstDateOfMonth();
var lastDateOfMonth = date.getLastDateOfMonth();
//start at the monday of the week the current month starts in
this.startDate=this.getFirstDateOfWeek(firstDateOfMonth);
var startTime = this.startDate.format('U');
var endTime = lastDateOfMonth.format('U');
var daysToShow = ((endTime-startTime)/86400)+1;
var rows = Math.ceil(daysToShow/7);
this.days = rows*7;
this.endDate = this.startDate.add(Date.DAY, this.days);
this.setStoreBaseParams();
if(!oldEndDate || !oldStartDate || oldEndDate.getElapsed(this.endDate)!=0 || oldStartDate.getElapsed(this.startDate)!=0)
{
if(load)
{
this.store.reload();
}else
{
this.loadRequired=true;
}
}
},
reload : function()
{
/*this.clearGrid();
if(!this.monthView)
{
this.createHeadings();
} */
this.load();
},
load : function()
{
if(this.rendered)
{
this.loading=true;
this.clearGrid();
this.renderMonthView();
this.writePermission = this.store.reader.jsonData.write_permission;
var records = this.store.getRange();
for(var i = 0, len = records.length; i < len; i++){
var startDate = Date.parseDate(records[i].data['start_time'], this.dateTimeFormat);
var endDate = Date.parseDate(records[i].data['end_time'], this.dateTimeFormat);
var eventData = records[i].data;
eventData['startDate']=startDate;
eventData['endDate']=endDate;
this.addMonthGridEvent (eventData);
}
this.checkOverflow();
this.unmask();
this.loading=false;
this.loadRequired=false;
}
},
/**
* An array of domId=>database ID should be kept so that we can figure out
* which event to update when it's modified.
* @param {String} domId The unique DOM id of the element
* @param {String} remoteId The unique database id of the element
* @return void
*/
registerEvent : function(domId, eventData)
{
this.remoteEvents[domId]=eventData;
/*if(!this.eventIdToDomId[eventData.event_id])
{
this.eventIdToDomId[eventData.event_id]=[];
}
this.eventIdToDomId[eventData.event_id].push(domId);*/
},
getEventDomElements : function(id)
{
return Ext.ux.go.util.clone(this.domIds[id]);
},
getRelatedDomElements : function(eventDomId)
{
var eventData = this.remoteEvents[eventDomId];
if(!eventData)
{
return false;
}
var domElements = this.getEventDomElements(eventData.id);
if(!domElements)
{
domElements = [eventDomId];
}
return domElements;
},
elementToEvent : function(elementId, allDay)
{
this.remoteEvents[elementId]['domId']=elementId;
return this.remoteEvents[elementId];
}
});
Ext.ux.go.calendar.dd.MonthDragZone = function(el, config) {
config = config || {};
Ext.apply(config, {
ddel: document.createElement('div')
});
Ext.ux.go.calendar.dd.MonthDragZone.superclass.constructor.call(this, el, config);
};
Ext.extend(Ext.ux.go.calendar.dd.MonthDragZone, Ext.dd.DragZone, {
onInitDrag: function(e) {
if(!this.monthGrid.writePermission || this.monthGrid.remoteEvents[this.dragData.item.id]['private'])
{
return false;
}else
{
this.ddel.innerHTML = this.dragData.item.dom.innerHTML;
this.ddel.className = this.dragData.item.dom.className;
this.ddel.style.width = this.dragData.item.getWidth() + "px";
this.proxy.update(this.ddel);
this.eventDomElements = this.monthGrid.getRelatedDomElements(this.dragData.item.id);
var td = Ext.get(this.dragData.item).findParent('div.cal-monthGrid-cell', 3, true);
//this.proxyCount = eventDomElements.length;
this.eventProxies=[];
this.proxyDragPos = 0;
for(var i=0;i<this.eventDomElements.length;i++)
{
this.eventProxies.push(Ext.DomHelper.append(document.body,
{
tag: 'div',
id: Ext.id(),
cls: "x-calGrid-month-event-proxy",
style: "width:"+this.ddel.style.width+"px;"
},true));
if (this.eventDomElements[i]==this.dragData.item.id)
{
this.proxyDragPos=i;
}else
{
//hide event element
var el = Ext.get(this.eventDomElements[i]);
if(el)
{
el.setStyle({'position' : 'absolute', 'top':-10000, 'display':'none'});
}
}
}
}
},
removeEventProxies : function(){
var proxies = Ext.query('div.x-calGrid-month-event-proxy');
for (var i=0;i<proxies.length;i++)
{
Ext.get(proxies[i]).remove();
}
delete this.lastTdOverId;
//unhide event elements
for(var i=0;i<this.eventDomElements.length;i++)
{
var el = Ext.get(this.eventDomElements[i]);
if(el)
{
el.setStyle({'position' : 'static', 'top': '', 'display':'block'});
}
}
},
afterRepair : function(){
Ext.ux.go.calendar.dd.MonthDragZone.superclass.afterRepair.call(this);
this.removeEventProxies();
},
getRepairXY: function(e, data) {
data.item.highlight('#e8edff');
return data.item.getXY();
},
getDragData: function(e) {
if(!this.monthGrid.writePermission)
{
return false;
}else
{
var target = Ext.get(e.getTarget());
var td = target.parent();
var dragDate = Date.parseDate(td.id.substr(1),'Ymd');
if(target.hasClass('x-calGrid-month-event-container') && !this.monthGrid.remoteEvents[target.id]['private']) {
return {
ddel:this.ddel,
item:target,
dragDate: dragDate
};
}else
{
return false;
}
}
}
});
Ext.ux.go.calendar.dd.MonthDropTarget = function(el, config) {
Ext.ux.go.calendar.dd.MonthDropTarget.superclass.constructor.call(this, el, config);
};
Ext.extend(Ext.ux.go.calendar.dd.MonthDropTarget, Ext.dd.DropTarget, {
notifyDrop: function(dd, e, data) {
if(!this.scope.writePermission)
{
return false;
}else
{
var target = Ext.get(e.getTarget()).findParent('div.cal-monthGrid-cell', 3, true);
data.dropDate = Date.parseDate(target.id.substr(1),'Ymd');
dd.removeEventProxies();
this.el.removeClass(this.overClass);
target.appendChild(data.item);
if(this.onNotifyDrop)
{
if(!this.scope)
{
this.scope=this;
}
var onNotifyDrop = this.onNotifyDrop.createDelegate(this.scope);
onNotifyDrop.call(this, dd, e, data);
}
return true;
}
},
notifyOver : function(dd, e, data){
var tdOver = Ext.get(e.getTarget()).findParent('div.cal-monthGrid-cell', 3, true);
if(tdOver)
{
if(dd.lastTdOverId!=tdOver.id)
{
var currentTd=tdOver;
for(var i=0;i<dd.proxyDragPos;i++)
{
if(currentTd)
{
var nextTd = currentTd.prev('div.cal-monthGrid-cell');
currentTd = nextTd;
}
if(nextTd)
{
dd.eventProxies[i].insertAfter(nextTd.first());
dd.eventProxies[i].setStyle({'position' : 'static', 'top': '', 'display':'block'});
}else
{
dd.eventProxies[i].setStyle({'position' : 'absolute', 'top':-10000, 'display':'none'});
}
}
dd.eventProxies[i].insertAfter(tdOver.first());
var currentTd=tdOver;
for(var i=dd.proxyDragPos+1;i<dd.eventProxies.length;i++)
{
if(currentTd)
{
var nextTd = currentTd.next('div.cal-monthGrid-cell');
currentTd = nextTd;
}
if(nextTd)
{
dd.eventProxies[i].insertAfter(nextTd.first());
dd.eventProxies[i].setStyle({'position' : 'static', 'top': '', 'display':'block'});
}else
{
dd.eventProxies[i].setStyle({'position' : 'absolute', 'top':-10000, 'display':'none'});
}
}
}
dd.lastTdOverId=tdOver.id;
}
return this.dropAllowed;
}
});