aolists-webtop
Version:
Web interface for aoLists
1,036 lines (803 loc) • 25.7 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: ViewGrid.js 1847 2009-02-09 14:40:39Z mschering $
* @author Merijn Schering <mschering@intermesh.nl>
*/
Ext.ux.go.grid.ViewGrid = 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(),
//An object with the event_id as key and the value is an array with dom id's
domIds : Array(),
//amount of days to display
days : 1,
selected : Array(),
view_id : 0,
//a collection of all the gridcells
gridCells : Array(),
// private
initComponent : function(){
Ext.ux.go.grid.ViewGrid.superclass.initComponent.call(this);
this.addEvents({
/**
* @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,
"zoom" : true
});
if(!this.startDate)
{
//lose time
var date = new Date();
this.startDate=Date.parseDate(date.format(this.dateFormat), this.dateFormat);
}
this.configuredDate=this.startDate;
},
setViewId : function(view_id)
{
this.view_id=view_id;
//this.load();
},
//build the html grid
onRender : function(ct, position){
Ext.ux.go.grid.ViewGrid.superclass.onRender.apply(this, arguments);
//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.renderViewView();
this.initDD();
},
renderView : function()
{
this.body.update('');
//get content size of element
var ctSize = this.container.getSize(true);
//column width is the container size minus the time column width
var columnWidth = (ctSize['width']-150)/this.days;
//generate table for headings and all day events
this.headingsTable = Ext.DomHelper.append(this.body,
{
tag: 'table',
id: Ext.id(),
cls: "x-calGrid-headings-table",
style: "width:"+ctSize['width']+"px;"
},true);
var tbody = Ext.DomHelper.append(this.headingsTable,
{
tag: 'tbody'
}, true);
this.headingsRow = Ext.DomHelper.append(tbody,
{
tag: 'tr',
children:{
tag:'td',
style:'width:147px',
cls: "x-calGrid-heading"
}
}, true);
var yearPos = Ext.ux.go.settings.date_format.indexOf('Y');
var dateFormat = 'D '+Ext.ux.go.settings.date_format.substring(0, yearPos-1);
for(var day=0;day<this.days;day++)
{
var dt = this.startDate.add(Date.DAY, day);
//create grid heading
var heading = Ext.DomHelper.append(this.headingsRow,
{tag: 'td', cls: "x-calGrid-heading", style: "width:"+(columnWidth)+"px", html: dt.format(dateFormat) });
}
//for the scrollbar
Ext.DomHelper.append(this.headingsRow,
{
tag: 'td',
style: "width:"+(this.scrollOffset-3)+"px;height:0px",
cls: "x-calGrid-heading"
});
//create container for the grid
this.gridContainer = Ext.DomHelper.append(this.body,
{tag: 'div', cls: "x-calGrid-grid-container"}, true);
//calculate gridContainer size
var headingsHeight = this.headingsTable.getHeight();
var gridContainerHeight = ctSize['height']-headingsHeight;
this.gridContainer.setSize(ctSize['width'],gridContainerHeight );
this.gridTable = Ext.DomHelper.append(this.gridContainer,
{
tag: 'table',
id: Ext.id(),
cls: "x-viewGrid-table",
style: "width:"+ctSize['width']-this.scrollWidth+"px;"
},true);
this.tbody = Ext.DomHelper.append(this.gridTable,
{
tag: 'tbody'
}, true);
this.gridCells = {};
for(var calendar_id in this.jsonData)
{
var gridRow = Ext.DomHelper.append(this.tbody,
{
tag: 'tr'
});
var cell = Ext.DomHelper.append(gridRow, {
tag: 'td',
cls: 'x-viewGrid-calendar-name-cell',
style:'width:150px'
}, true);
var link = Ext.DomHelper.append(cell, {
tag: 'a',
id: 'view_cal_'+calendar_id,
href:'#',
cls:'normal-link',
html:this.jsonData[calendar_id].name
}, true);
link.on('click', function(e, target){
e.preventDefault();
this.fireEvent('zoom', {calendar_id: target.id.substring(9)});
}, this);
this.gridCells[calendar_id]={};
for(var day=0;day<this.days;day++)
{
var dt = this.startDate.add(Date.DAY, day)
this.gridCells[calendar_id][dt.format('Ymd')]= Ext.DomHelper.append(gridRow,{
tag: 'td',
id: 'cal'+this.jsonData[calendar_id].id+'_day'+dt.format('Ymd'),
cls: 'x-viewGrid-cell',
style:'width:'+columnWidth+'px'
}, true);
}
}
},
/*
* 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]);
}
}
},
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;
}
}
/*found=false;
for(var e in this.eventIdToDomId)
{
for(var i=0;i<this.eventIdToDomId[e].length;i++)
{
if(this.eventIdToDomId[e][i]==domId)
{
this.eventIdToDomId[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;
},
initDD : function(){
var dragZone = new Ext.ux.go.calendar.dd.ViewDragZone(this.body, {
ddGroup: 'view-grid',
scroll: false,
viewGrid: this
});
var dropTarget = new Ext.ux.go.calendar.dd.ViewDropTarget(this.body, {
ddGroup: 'view-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, calendar_id: data.calendar_id};
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.calendar_id=data.calendar_id;
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.addViewGridEvent(remoteEvent);
}
},
scope : this
});
},
onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
//Ext.grid.GridPanel.superclass.onResize.apply(this, arguments);
if(this.viewGridTable)
{
this.viewGridTable.setSize(adjWidth, adjHeight);
}
},
getFirstDateOfWeek : function(date)
{
//Calculate the first day of the week
var weekday = date.getDay();
var offset = this.firstWeekday-weekday;
if(offset>0)
{
offset-=7;
}
return date.add(Date.DAY, offset);
},
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);
}
}
}
},
addViewGridEvent : 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;
for(var i=0;i<daySpan;i++)
{
var date = eventStartDay.add(Date.DAY, i);
var domId = eventData.domId ? 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(domId);
}
var col = this.gridCells[eventData['calendar_id']][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: domId,
cls: "x-viewGrid-event-container",
style:"background-color:#"+eventData.background,
html: text,
qtitle:eventData.name,
qtip: Ext.ux.go.calendar.formatQtip(eventData)
}, true);
this.registerEvent(domId, eventData);
event.on('mousedown', function(e, eventEl){
eventEl = Ext.get(eventEl).findParent('div.x-viewGrid-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-viewGrid-event-container', 2, true);
//this.eventDoubleClicked=true;
var event = this.elementToEvent(this.clickedEventId);
if(event['repeats'] && event['write_permission'])
{
this.handleRecurringEvent("eventDblClick", event, {});
}else
{
this.fireEvent("eventDblClick", this, event, {singleInstance : event['write_permission']});
}
}, this);
}
}
return domId;
},
removeEventFromArray : function (day, event_id)
{
for(var i=0;i<this.appointments[day].length;i++)
{
if(this.appointments[day][i].id==event_id)
{
return this.appointments[day].splice(i,1);
}
}
return false;
},
inAppointmentsArray : function (id, appointments)
{
for(var i=0;i<appointments.length;i++)
{
if(appointments[i].id==id)
{
return true;
}
}
return false;
},
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.deleteRecurringEvent,
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);
this.removeEvent(remoteEvent.domId);
remoteEvent.calendar_id=this.currentActionData.calendar_id;
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.addViewGridEvent(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.appointments=Array();
this.remoteEvents=Array();
this.domIds=Array();
},
setDays : function(days, load)
{
this.setDate(this.configuredDate, days, load);
},
setDate : function(date, days, load)
{
var oldStartDate = this.startDate;
var oldEndDate = this.endDate;
if(days)
{
this.days=days;
}
this.configuredDate = date;
if(this.days>4)
{
this.startDate = this.getFirstDateOfWeek(date);
}else
{
this.startDate = date;
}
this.endDate = this.startDate.add(Date.DAY, this.days);
if(load)
{
//if(!oldEndDate || !oldStartDate || oldEndDate.getElapsed(this.endDate)!=0 || oldStartDate.getElapsed(this.startDate)!=0)
//{
this.reload();
//}
}
},
reload : function()
{
/*this.clearGrid();
if(!this.viewView)
{
this.createHeadings();
} */
this.load();
},
load : function(params)
{
if(!params)
{
params={};
}
params['task']='view_events';
params['view_id']=this.view_id;
params['start_time']=this.startDate.format(this.dateTimeFormat);
params['end_time']=this.endDate.format(this.dateTimeFormat);
this.mask();
Ext.Ajax.request({
url: Ext.ux.go.settings.modules.calendar.url+'json.php',
params: params,
callback: function(options, success, response)
{
if(!success)
{
Ext.MessageBox.alert(Ext.ux.go.lang.strError, response.result.feedback);
}else
{
this.jsonData = Ext.decode(response.responseText);
this.clearGrid();
this.renderView();
for(var calendar_id in this.jsonData)
{
var events = this.jsonData[calendar_id].events;
for(var i=0; i< events.length;i++)
{
var eventData = events[i];
eventData['startDate'] = Date.parseDate(events[i]['start_time'], this.dateTimeFormat);
eventData['endDate'] = Date.parseDate(events[i]['end_time'], this.dateTimeFormat);
this.addViewGridEvent(eventData);
}
}
}
this.unmask();
},
scope:this
});
},
/**
* 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.domIds[eventData.event_id])
{
this.domIds[eventData.event_id]=[];
}
this.domIds[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];
}/*,
// private
destroy : function(){
this.store.un("beforeload", this.reload, this);
this.store.un("datachanged", this.reload, this);
this.store.un("clear", this.reload, this);
this.el.update('');
Ext.ux.go.grid.CalendarGrid.superclass.destroy.call(this);
delete this.el;
this.rendered=false;
}*/
});
Ext.ux.go.calendar.dd.ViewDragZone = function(el, config) {
config = config || {};
Ext.apply(config, {
ddel: document.createElement('div')
});
Ext.ux.go.calendar.dd.ViewDragZone.superclass.constructor.call(this, el, config);
};
Ext.extend(Ext.ux.go.calendar.dd.ViewDragZone, Ext.dd.DragZone, {
onInitDrag: function(e) {
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.viewGrid.getRelatedDomElements(this.dragData.item.id);
var td = Ext.get(this.dragData.item).findParent('td', 10, 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-viewGrid-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-viewGrid-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.ViewDragZone.superclass.afterRepair.call(this);
this.removeEventProxies();
},
getRepairXY: function(e, data) {
data.item.highlight('#e8edff');
return data.item.getXY();
},
getDragData: function(e) {
var target = Ext.get(e.getTarget());
if(target.hasClass('x-viewGrid-event-container'))
{
var td = target.parent();
var dateIndex = td.id.indexOf('_day')+4;
var calendar_id = td.id.substr(3,dateIndex-7);
if(!this.viewGrid.remoteEvents[target.id]['private'] && this.viewGrid.jsonData[calendar_id].write_permission)
{
var dateStr = td.id.substr(dateIndex);
var dragDate = Date.parseDate(dateStr,'Ymd');
return {
ddel:this.ddel,
item:target,
dragDate: dragDate
};
}
return false;
}
}
});
Ext.ux.go.calendar.dd.ViewDropTarget = function(el, config) {
Ext.ux.go.calendar.dd.ViewDropTarget.superclass.constructor.call(this, el, config);
};
Ext.extend(Ext.ux.go.calendar.dd.ViewDropTarget, Ext.dd.DropTarget, {
notifyDrop: function(dd, e, data) {
var td = Ext.get(e.getTarget()).findParent('td', 10, true);
if(!td)
{
return false;
}
var dateIndex = td.id.indexOf('_day')+4;
var calendar_id = td.id.substr(3,dateIndex-7);
if(!this.scope.jsonData[calendar_id] || !this.scope.jsonData[calendar_id].write_permission)
{
return false;
}
var dateStr = td.id.substr(dateIndex);
data.dropDate = Date.parseDate(dateStr,'Ymd');
data.calendar_id=td.id.substr(3,dateIndex-7);
dd.removeEventProxies();
this.el.removeClass(this.overClass);
td.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('td.x-viewGrid-cell', 10, true);
if(tdOver)
{
var dateIndex = tdOver.id.indexOf('_day');
var calendar_id = tdOver.id.substr(3,dateIndex-3);
if(this.scope.jsonData[calendar_id] && this.scope.jsonData[calendar_id].write_permission)
{
if(dd.lastTdOverId!=tdOver.id)
{
var currentTd=tdOver;
for(var i=0;i<dd.proxyDragPos;i++)
{
if(currentTd)
{
var nextTd = currentTd.prev('td.x-viewGrid-cell');
currentTd = nextTd;
}
if(nextTd)
{
//dd.eventProxies[i].insertAfter(nextTd.first());
nextTd.insertFirst(dd.eventProxies[i].id);
dd.eventProxies[i].setStyle({'position' : 'static', 'top': '', 'display':'block'});
}else
{
dd.eventProxies[i].setStyle({'position' : 'absolute', 'top':-10000, 'display':'none'});
}
}
tdOver.insertFirst(dd.eventProxies[i].id);
//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('td.x-viewGrid-cell');
currentTd = nextTd;
}
if(nextTd)
{
//dd.eventProxies[i].insertAfter(nextTd.first());
nextTd.insertFirst(dd.eventProxies[i].id);
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;
}
}
return false;
}
});