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)
|
||||
{
|
||||
// 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);
|
||||
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)
|
||||
{
|
||||
planner._drag_helper(this,{
|
||||
top:ui.position.top,
|
||||
left: ui.position.left + ui.helper.width()
|
||||
},ui.helper.outerHeight());
|
||||
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 + 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());
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
|
||||
// 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);
|
||||
|
||||
widget_object.updateActionLinks(action_links);
|
||||
//widget_object.updateActionLinks(action_links);
|
||||
this._actionObject = widget_object;
|
||||
},
|
||||
|
||||
@ -1311,6 +1361,8 @@ var et2_calendar_planner = (function(){ "use strict"; return et2_calendar_view.e
|
||||
var self = this;
|
||||
|
||||
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');
|
||||
|
||||
// Check if this app supports linking
|
||||
@ -1371,11 +1423,83 @@ var et2_calendar_planner = (function(){ "use strict"; return et2_calendar_view.e
|
||||
).sendRequest();
|
||||
}
|
||||
},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)
|
||||
{
|
||||
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
|
||||
// This does not handle files dragged from the desktop. They are
|
||||
// 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);
|
||||
}
|
||||
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
|
||||
{
|
||||
// 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;
|
||||
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._draw();
|
||||
|
||||
this._link_actions([]);
|
||||
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
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user