forked from extern/egroupware
Implement drag to invite / move to for planner by user view
This commit is contained in:
parent
eba29d3541
commit
115f420996
@ -840,7 +840,7 @@ var et2_calendar_event = (function(){ "use strict"; return et2_valueWidget.exten
|
|||||||
if(!this._actionObject)
|
if(!this._actionObject)
|
||||||
{
|
{
|
||||||
// Get the top level element - timegrid or so
|
// Get the top level element - timegrid or so
|
||||||
var objectManager = this.getParent().getParent()._actionObject ||
|
var objectManager = this.getParent()._actionObject || this.getParent().getParent()._actionObject ||
|
||||||
egw_getAppObjectManager(true).getObjectById(this._parent._parent._parent.id) || egw_getAppObjectManager(true);
|
egw_getAppObjectManager(true).getObjectById(this._parent._parent._parent.id) || egw_getAppObjectManager(true);
|
||||||
this._actionObject = objectManager.getObjectById('calendar::'+this.options.value.row_id);
|
this._actionObject = objectManager.getObjectById('calendar::'+this.options.value.row_id);
|
||||||
}
|
}
|
||||||
|
@ -236,10 +236,15 @@ var et2_calendar_planner = (function(){ "use strict"; return et2_calendar_view.e
|
|||||||
*/
|
*/
|
||||||
resize:function(event, ui)
|
resize:function(event, ui)
|
||||||
{
|
{
|
||||||
planner._drag_helper(this,{
|
if(planner.options.group_by == 'month')
|
||||||
top:ui.position.top,
|
{
|
||||||
left: ui.position.left + ui.helper.width()
|
var position = {left: event.clientX, top: event.clientY};
|
||||||
},ui.helper.outerHeight());
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var position = {top:ui.position.top, left: ui.position.left + ui.helper.width()};
|
||||||
|
}
|
||||||
|
planner._drag_helper(this,position,ui.helper.outerHeight());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
@ -1215,6 +1220,51 @@ var et2_calendar_planner = (function(){ "use strict"; return et2_calendar_view.e
|
|||||||
|
|
||||||
var aoi = new et2_action_object_impl(this,this.getDOMNode());
|
var aoi = new et2_action_object_impl(this,this.getDOMNode());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if we allow a dropped event to use the invite/change actions,
|
||||||
|
* and enable or disable them appropriately
|
||||||
|
*
|
||||||
|
* @param {egwAction} action
|
||||||
|
* @param {et2_calendar_event} event The event widget being dragged
|
||||||
|
* @param {egwActionObject} target Planner action object
|
||||||
|
*/
|
||||||
|
var _invite_enabled = function(action, event, target)
|
||||||
|
{
|
||||||
|
var event = event.iface.getWidget();
|
||||||
|
var planner = target.iface.getWidget() || false;
|
||||||
|
//debugger;
|
||||||
|
if(event === planner || !event || !planner ||
|
||||||
|
!event.options || !event.options.value.participants || !planner.options.owner
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
var owner_match = false;
|
||||||
|
var own_row = false;
|
||||||
|
|
||||||
|
for(var id in event.options.value.participants)
|
||||||
|
{
|
||||||
|
planner.iterateOver(function(row) {
|
||||||
|
// Check scroll section or header section
|
||||||
|
if(row.div.hasClass('drop-hover') || row.div.has(':hover'))
|
||||||
|
{
|
||||||
|
owner_match = owner_match || row.node.dataset[planner.options.group_by] === ''+id;
|
||||||
|
own_row = (row === event.getParent());
|
||||||
|
}
|
||||||
|
}, this, et2_calendar_planner_row);
|
||||||
|
|
||||||
|
}
|
||||||
|
var enabled = !owner_match &&
|
||||||
|
// Not inside its own row
|
||||||
|
!own_row;
|
||||||
|
|
||||||
|
widget_object.getActionLink('invite').enabled = enabled;
|
||||||
|
widget_object.getActionLink('change_participant').enabled = enabled;
|
||||||
|
|
||||||
|
// If invite or change participant are enabled, drag is not
|
||||||
|
widget_object.getActionLink('egw_link_drop').enabled = !enabled;
|
||||||
|
};
|
||||||
|
|
||||||
aoi.doTriggerEvent = function(_event, _data) {
|
aoi.doTriggerEvent = function(_event, _data) {
|
||||||
|
|
||||||
// Determine target node
|
// Determine target node
|
||||||
@ -1294,7 +1344,7 @@ var et2_calendar_planner = (function(){ "use strict"; return et2_calendar_view.e
|
|||||||
|
|
||||||
this._init_links_dnd(widget_object.manager, action_links);
|
this._init_links_dnd(widget_object.manager, action_links);
|
||||||
|
|
||||||
widget_object.updateActionLinks(action_links);
|
//widget_object.updateActionLinks(action_links);
|
||||||
this._actionObject = widget_object;
|
this._actionObject = widget_object;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1311,6 +1361,8 @@ var et2_calendar_planner = (function(){ "use strict"; return et2_calendar_view.e
|
|||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
var drop_action = mgr.getActionById('egw_link_drop');
|
var drop_action = mgr.getActionById('egw_link_drop');
|
||||||
|
var drop_change_participant = mgr.getActionById('change_participant');
|
||||||
|
var drop_invite = mgr.getActionById('invite');
|
||||||
var drag_action = mgr.getActionById('egw_link_drag');
|
var drag_action = mgr.getActionById('egw_link_drag');
|
||||||
|
|
||||||
// Check if this app supports linking
|
// Check if this app supports linking
|
||||||
@ -1371,11 +1423,83 @@ var et2_calendar_planner = (function(){ "use strict"; return et2_calendar_view.e
|
|||||||
).sendRequest();
|
).sendRequest();
|
||||||
}
|
}
|
||||||
},true);
|
},true);
|
||||||
|
|
||||||
|
drop_action.acceptedTypes = ['default','link'];
|
||||||
|
drop_action.hideOnDisabled = true;
|
||||||
|
|
||||||
|
// Create the drop action for moving events between planner rows
|
||||||
|
var invite_action = function(action, source, target) {
|
||||||
|
|
||||||
|
// Extract link IDs
|
||||||
|
var links = [];
|
||||||
|
var id = '';
|
||||||
|
for(var i = 0; i < source.length; i++)
|
||||||
|
{
|
||||||
|
// Check for no ID (invalid) or same manager (dragging an event)
|
||||||
|
if(!source[i].id) continue;
|
||||||
|
if(source[i].manager === target.manager)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Find the row, could have dropped on an event
|
||||||
|
var row = target.iface.getWidget();
|
||||||
|
while(target.parent && row.instanceOf && !row.instanceOf(et2_calendar_planner_row))
|
||||||
|
{
|
||||||
|
target = target.parent;
|
||||||
|
row = target.iface.getWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leave the helper there until the update is done
|
||||||
|
var loading = action.ui.helper.clone(true).appendTo(jQuery('body'));
|
||||||
|
|
||||||
|
// and add a loading icon so user knows something is happening
|
||||||
|
if(jQuery('.calendar_timeDemo',loading).length == 0)
|
||||||
|
{
|
||||||
|
jQuery('.calendar_calEventHeader',loading).addClass('loading');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
jQuery('.calendar_timeDemo',loading).after('<div class="loading"></div>');
|
||||||
|
}
|
||||||
|
|
||||||
|
var event_data = egw.dataGetUIDdata(source[i].id).data;
|
||||||
|
et2_calendar_event.recur_prompt(event_data, function(button_id) {
|
||||||
|
if(button_id === 'cancel' || !button_id)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var add_owner = jQuery.extend([],row.node.dataset.participants);
|
||||||
|
|
||||||
|
egw().json('calendar.calendar_uiforms.ajax_invite', [
|
||||||
|
button_id==='series' ? event_data.id : event_data.app_id,
|
||||||
|
add_owner,
|
||||||
|
action.id === 'change_participant' ?
|
||||||
|
jQuery.extend([],source[i].iface.getWidget().getParent().node.dataset.participants) :
|
||||||
|
[]
|
||||||
|
],
|
||||||
|
function() { loading.remove();}
|
||||||
|
).sendRequest(true);
|
||||||
|
});
|
||||||
|
// Ok, stop.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
drop_change_participant = mgr.addAction('drop', 'change_participant', egw.lang('Move to'), egw.image('participant'), invite_action,true);
|
||||||
|
drop_change_participant.acceptedTypes = ['calendar'];
|
||||||
|
drop_change_participant.hideOnDisabled = true;
|
||||||
|
|
||||||
|
drop_invite = mgr.addAction('drop', 'invite', egw.lang('Invite'), egw.image('participant'), invite_action,true);
|
||||||
|
drop_invite.acceptedTypes = ['calendar'];
|
||||||
|
drop_invite.hideOnDisabled = true;
|
||||||
}
|
}
|
||||||
if(actionLinks.indexOf(drop_action.id) < 0)
|
if(actionLinks.indexOf(drop_action.id) < 0)
|
||||||
{
|
{
|
||||||
actionLinks.push(drop_action.id);
|
actionLinks.push(drop_action.id);
|
||||||
}
|
}
|
||||||
|
actionLinks.push(drop_invite.id);
|
||||||
|
actionLinks.push(drop_change_participant.id);
|
||||||
|
|
||||||
// Accept other links, and files dragged from the filemanager
|
// Accept other links, and files dragged from the filemanager
|
||||||
// This does not handle files dragged from the desktop. They are
|
// This does not handle files dragged from the desktop. They are
|
||||||
// handled by et2_nextmatch, since it needs DOM stuff
|
// handled by et2_nextmatch, since it needs DOM stuff
|
||||||
@ -1400,7 +1524,7 @@ var et2_calendar_planner = (function(){ "use strict"; return et2_calendar_view.e
|
|||||||
{
|
{
|
||||||
actionLinks.push(drag_action.id);
|
actionLinks.push(drag_action.id);
|
||||||
}
|
}
|
||||||
drag_action.set_dragType('link');
|
drag_action.set_dragType(['link','calendar']);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1864,7 +1988,29 @@ var et2_calendar_planner = (function(){ "use strict"; return et2_calendar_view.e
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Find the correct row so we know which month, then get the offset
|
// Find the correct row so we know which month, then get the offset
|
||||||
var row = jQuery(document.elementFromPoint(x, y)).closest('.calendar_plannerRowWidget');
|
var hidden_nodes = [];
|
||||||
|
var row = null;
|
||||||
|
// Hide any drag or tooltips that may interfere
|
||||||
|
do
|
||||||
|
{
|
||||||
|
row = document.elementFromPoint(x, y);
|
||||||
|
if(this.div.has(row).length == 0)
|
||||||
|
{
|
||||||
|
hidden_nodes.push(jQuery(row).hide());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while(row.nodeName !== 'BODY');
|
||||||
|
// Restore hidden nodes
|
||||||
|
for(var i = 0; i < hidden_nodes.length; i++)
|
||||||
|
{
|
||||||
|
hidden_nodes[i].show();
|
||||||
|
}
|
||||||
|
row = jQuery(row).closest('.calendar_plannerRowWidget');
|
||||||
|
|
||||||
|
|
||||||
var row_widget = null;
|
var row_widget = null;
|
||||||
for(var i = 0; i < this._children.length && row.length > 0; i++)
|
for(var i = 0; i < this._children.length && row.length > 0; i++)
|
||||||
{
|
{
|
||||||
|
@ -73,6 +73,8 @@ var et2_calendar_planner_row = (function(){ "use strict"; return et2_valueWidget
|
|||||||
|
|
||||||
this.set_label(this.options.label);
|
this.set_label(this.options.label);
|
||||||
this._draw();
|
this._draw();
|
||||||
|
|
||||||
|
this._link_actions([]);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -96,6 +98,225 @@ var et2_calendar_planner_row = (function(){ "use strict"; return et2_valueWidget
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link the actions to the DOM nodes / widget bits.
|
||||||
|
*
|
||||||
|
* @param {object} actions {ID: {attributes..}+} map of egw action information
|
||||||
|
*/
|
||||||
|
_link_actions: function(actions)
|
||||||
|
{
|
||||||
|
// Get the parent? Might be a grid row, might not. Either way, it is
|
||||||
|
// just a container with no valid actions
|
||||||
|
var objectManager = egw_getObjectManager(this.getInstanceManager().app,true,1);
|
||||||
|
objectManager = objectManager.getObjectById(this.getInstanceManager().uniqueId,2) || objectManager;
|
||||||
|
var parent = objectManager.getObjectById(this.id,1) || objectManager.getObjectById(this._parent.id,1) || objectManager;
|
||||||
|
if(!parent)
|
||||||
|
{
|
||||||
|
debugger;
|
||||||
|
egw.debug('error','No parent objectManager found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This binds into the egw action system. Most user interactions (drag to move, resize)
|
||||||
|
// are handled internally using jQuery directly.
|
||||||
|
var widget_object = this._actionObject || parent.getObjectById(this.id);
|
||||||
|
var aoi = new et2_action_object_impl(this,this.getDOMNode());
|
||||||
|
var planner = this.getParent();
|
||||||
|
|
||||||
|
for(var i = 0; i < parent.children.length; i++)
|
||||||
|
{
|
||||||
|
var parent_finder = jQuery(parent.children[i].iface.doGetDOMNode()).find(this.div);
|
||||||
|
if(parent_finder.length > 0)
|
||||||
|
{
|
||||||
|
parent = parent.children[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if we allow a dropped event to use the invite/change actions
|
||||||
|
var _invite_enabled = function(action, event, target)
|
||||||
|
{
|
||||||
|
var event = event.iface.getWidget();
|
||||||
|
var row = target.iface.getWidget() || false;
|
||||||
|
if(event === row || !event || !row ||
|
||||||
|
!event.options || !event.options.value.participants
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var owner_match = false;
|
||||||
|
var own_row = event.getParent() === row;
|
||||||
|
|
||||||
|
for(var id in event.options.value.participants)
|
||||||
|
{
|
||||||
|
owner_match = owner_match || row.node.dataset.participants === ''+id;
|
||||||
|
}
|
||||||
|
|
||||||
|
var enabled = !owner_match &&
|
||||||
|
// Not inside its own timegrid
|
||||||
|
!own_row;
|
||||||
|
|
||||||
|
widget_object.getActionLink('invite').enabled = enabled;
|
||||||
|
widget_object.getActionLink('change_participant').enabled = enabled;
|
||||||
|
|
||||||
|
// If invite or change participant are enabled, drag is not
|
||||||
|
widget_object.getActionLink('egw_link_drop').enabled = !enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
aoi.doTriggerEvent = function(_event, _data) {
|
||||||
|
|
||||||
|
// Determine target node
|
||||||
|
var event = _data.event || false;
|
||||||
|
if(!event) return;
|
||||||
|
if(_data.ui.draggable.hasClass('rowNoEdit')) return;
|
||||||
|
/*
|
||||||
|
We have to handle the drop in the normal event stream instead of waiting
|
||||||
|
for the egwAction system so we can get the helper, and destination
|
||||||
|
*/
|
||||||
|
if(event.type === 'drop' && widget_object.getActionLink('egw_link_drop').enabled)
|
||||||
|
{
|
||||||
|
this.getWidget().getParent()._event_drop.call(
|
||||||
|
jQuery('.calendar_d-n-d_timeCounter',_data.ui.helper)[0],
|
||||||
|
this.getWidget().getParent(), event, _data.ui,
|
||||||
|
this.getWidget()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
var drag_listener = function(_event, ui) {
|
||||||
|
if(planner.options.group_by === 'month')
|
||||||
|
{
|
||||||
|
var position = {left: _event.clientX, top: _event.clientY};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var position = {top:ui.position.top, left: ui.position.left - jQuery(this).parent().offset().left};
|
||||||
|
}
|
||||||
|
aoi.getWidget().getParent()._drag_helper(
|
||||||
|
jQuery('.calendar_d-n-d_timeCounter',ui.helper)[0],
|
||||||
|
position,0
|
||||||
|
);
|
||||||
|
|
||||||
|
var event = _data.ui.draggable.data('selected')[0];
|
||||||
|
if(!event || event.id && event.id.indexOf('calendar') !== 0)
|
||||||
|
{
|
||||||
|
event = false;
|
||||||
|
}
|
||||||
|
if(event)
|
||||||
|
{
|
||||||
|
_invite_enabled(
|
||||||
|
widget_object.getActionLink('invite').actionObj,
|
||||||
|
event,
|
||||||
|
widget_object
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var time = jQuery('.calendar_d-n-d_timeCounter',_data.ui.helper);
|
||||||
|
switch(_event)
|
||||||
|
{
|
||||||
|
// Triggered once, when something is dragged into the timegrid's div
|
||||||
|
case EGW_AI_DRAG_OVER:
|
||||||
|
// Listen to the drag and update the helper with the time
|
||||||
|
// This part lets us drag between different timegrids
|
||||||
|
_data.ui.draggable.on('drag.et2_timegrid_row'+widget_object.id, drag_listener);
|
||||||
|
_data.ui.draggable.on('dragend.et2_timegrid_row'+widget_object.id, function() {
|
||||||
|
_data.ui.draggable.off('drag.et2_timegrid_row' + widget_object.id);
|
||||||
|
});
|
||||||
|
widget_object.iface.getWidget().div.addClass('drop-hover');
|
||||||
|
|
||||||
|
// Disable invite / change actions for same calendar or already participant
|
||||||
|
var event = _data.ui.draggable.data('selected')[0];
|
||||||
|
if(!event || event.id && event.id.indexOf('calendar') !== 0)
|
||||||
|
{
|
||||||
|
event = false;
|
||||||
|
}
|
||||||
|
if(event)
|
||||||
|
{
|
||||||
|
_invite_enabled(
|
||||||
|
widget_object.getActionLink('invite').actionObj,
|
||||||
|
event,
|
||||||
|
widget_object
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if(time.length)
|
||||||
|
{
|
||||||
|
// The out will trigger after the over, so we count
|
||||||
|
time.data('count',time.data('count')+1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_data.ui.helper.prepend('<div class="calendar_d-n-d_timeCounter" data-count="1"><span></span></div>');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Triggered once, when something is dragged out of the timegrid
|
||||||
|
case EGW_AI_DRAG_OUT:
|
||||||
|
// Stop listening
|
||||||
|
_data.ui.draggable.off('drag.et2_timegrid_row'+widget_object.id);
|
||||||
|
// Remove highlight
|
||||||
|
widget_object.iface.getWidget().div.removeClass('drop-hover');
|
||||||
|
|
||||||
|
// Out triggers after the over, count to not accidentally remove
|
||||||
|
time.data('count',time.data('count')-1);
|
||||||
|
if(time.length && time.data('count') <= 0)
|
||||||
|
{
|
||||||
|
time.remove();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (widget_object == null) {
|
||||||
|
// Add a new container to the object manager which will hold the widget
|
||||||
|
// objects
|
||||||
|
widget_object = parent.insertObject(false, new egwActionObject(
|
||||||
|
this.id, parent, aoi,
|
||||||
|
this._actionManager|| parent.manager.getActionById(this.id) || parent.manager
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
widget_object.setAOI(aoi);
|
||||||
|
}
|
||||||
|
this._actionObject = widget_object;
|
||||||
|
|
||||||
|
// Delete all old objects
|
||||||
|
widget_object.clear();
|
||||||
|
widget_object.unregisterActions();
|
||||||
|
|
||||||
|
// Go over the widget & add links - this is where we decide which actions are
|
||||||
|
// 'allowed' for this widget at this time
|
||||||
|
var action_links = this._get_action_links(actions);
|
||||||
|
|
||||||
|
this.getParent()._init_links_dnd(widget_object.manager, action_links);
|
||||||
|
|
||||||
|
widget_object.updateActionLinks(action_links);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all action-links / id's of 1.-level actions from a given action object
|
||||||
|
*
|
||||||
|
* Here we are only interested in drop events.
|
||||||
|
*
|
||||||
|
* @param actions
|
||||||
|
* @returns {Array}
|
||||||
|
*/
|
||||||
|
_get_action_links: function(actions)
|
||||||
|
{
|
||||||
|
var action_links = [];
|
||||||
|
// TODO: determine which actions are allowed without an action (empty actions)
|
||||||
|
for(var i in actions)
|
||||||
|
{
|
||||||
|
var action = actions[i];
|
||||||
|
if(action.type == 'drop')
|
||||||
|
{
|
||||||
|
action_links.push(typeof action.id != 'undefined' ? action.id : i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return action_links;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Draw the individual divs for weekends and events
|
* Draw the individual divs for weekends and events
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user