/*
* Copyright 2014 Anyware Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* This zone is a Ext.dd.DropZone that is compatible with the Ametys relation system.
*
* That means that any dropped record can have been dragged from any Ametys relation zone and will use the Ametys.relation.RelationManager to connect the results.
* Note that a drop zone can also be a normal zone to just graphically connect the objects (drag a resource explorer file on a file widget)
*
* It is required to implement #setAmetysDropZoneInfos.
* Use:
*
* initComponent: function() {
* this.callParent();
* this.on('render', function() {
* new Ametys.relation.dd.AmetysDropZone(this.getEl(), {setAmetysDropZoneInfos: Ext.bind(this.getDropInfo, this)});
* });
* },
*
* // @private
* // This event is thrown before the beforeDrop event and create the target of the drop operation relation.
* // @param {Ext.data.Model[]} targetRecords The target records of the drop operation.
* // @param {Object} item The default drag data that will be transmitted. You have to add a 'target' item in it:
* // @param {Object} item.target The target (in the relation way) of the drop operation. A Ametys.relation.RelationPoint config.
* //
* getDropInfo: function(targetRecords, item)
* {
* item.target = {
* relationTypes: [Ametys.relation.Relation.MOVE, Ametys.relation.Relation.REFERENCE, Ametys.relation.Relation.COPY],
* targets: {
* id: this._contentMessageType,
* parameters: { ids: [this._contentId] }
* }
* };
* }
*
*/
Ext.define('Ametys.relation.dd.AmetysDropZone', {
extend: 'Ext.dd.DropZone',
/**
* @private
* @cfg {String} [ddGroup="ametys"] The dd group should always be 'ametys'
*/
ddGroup: "ametys",
overClass: "drag-n-drop-over",
/**
* @cfg {Function} setAmetysDropZoneInfos (required) Implements this method called before the beforeDrop event to create the Ametys.relation.RelationPoint of the drop operation.
* @cfg {Object} setAmetysDropZoneInfos.target The target of the drop operation.
* @cfg {Object} setAmetysDropZoneInfos.item The default drag data that will be transmitted. You have to add a 'target' item in it:
* @cfg {Object} setAmetysDropZoneInfos.item.target The target (in the relation way) of the drop operation. A Ametys.relation.RelationPoint config.
*/
onNodeOver: function(node, dragZone, e, data)
{
var me = this;
var parent = this.callParent(arguments);
if (parent != this.dropNotAllowed)
{
if (Ext.isFunction(this.setAmetysDropZoneInfos))
{
this.setAmetysDropZoneInfos(null, data);
if (!data.source || !data.target || !Ametys.relation.RelationManager.testLink(data.source, data.target))
{
parent = this.dropNotAllowed;
}
data.target = null;
}
}
if (this.overClass)
{
if (parent != this.dropNotAllowed)
{
this.el.addCls(this.overClass);
}
else
{
this.el.removeCls(this.overClass);
}
}
return parent;
},
onContainerOver : function(dd, e, data)
{
this.overRecord = null;
if (Ext.isFunction(this.setAmetysDropZoneInfos))
{
this.setAmetysDropZoneInfos(null, data);
if (!data.source || !data.target || !Ametys.relation.RelationManager.testLink(data.source, data.target))
{
data.target = null;
return this.dropNotAllowed;
}
else
{
data.target = null;
return this.dropAllowed;
}
}
return this.dropNotAllowed;
},
notifyOut : function(dd, e, data)
{
if(this.overClass)
{
this.el.removeCls(this.overClass);
}
return this.callParent(arguments);
},
/**
* Called when the drop operation will not be valid
*/
invalidateDrop: function()
{
if(this.overClass)
{
this.el.removeCls(this.overClass);
}
},
onNodeDrop: function(n, dragZone, e, data)
{
var me = this;
var dropHandled = false;
// Create a closure to perform the operation which the event handler may use.
// Users may now set the wait parameter in the beforedrop handler, and perform any kind
// of asynchronous processing such as an Ametys.Msg.confirm, or an Ajax request,
// and complete the drop gesture at some point in the future by calling either the
// processDrop or cancelDrop methods.
var dropHandlers = {
processDrop: function () {
me.invalidateDrop();
dropHandled = true;
},
cancelDrop: function() {
me.invalidateDrop();
dropHandled = true;
}
};
var performOperation = false;
// If overRecord is part of the selection, the target is the whole selection
if (Ext.isFunction(this.setAmetysDropZoneInfos))
{
this.setAmetysDropZoneInfos(n, data);
}
this.el.removeCls(this.overClass);
if (data.source && data.target)
{
// FIXME handle the CTRL / SHIFT / ALT d'n'd and fill the below vars
var relationType = this.defaultRelation;
var forceUserChoice = false;
Ametys.relation.RelationManager.link(data.source, data.target, Ext.bind(this._onDropHandled, this, [data, dropHandlers], true), relationType, forceUserChoice);
return;
}
return performOperation;
},
onContainerDrop : function(dd, e, data) {
return this.onNodeDrop(null, dd, e, data);
},
/**
* @private
* Callback when the Ametys.relation.RelationManager ended.
* @param {Boolean/String} success Has the operation been successful? The success. False is a problem occurred, a Ametys.relation.Relation constant else determining which operation was done
* @param {Object} data The drag data
* @param {Object} dropHandlers This parameter allows to control when the drop action takes place.
*/
_onDropHandled: function(success, data, dropHandlers)
{
// FIXME Was the node moved ? or copy/referenced ? is it new (from another place) ? how to do that (refresh nodes?)...
if (success)
{
switch (success)
{
case Ametys.relation.Relation.MOVE:
data.copy = false;
dropHandlers.processDrop();
break;
case Ametys.relation.Relation.COPY:
data.copy = true;
dropHandlers.processDrop();
break;
case Ametys.relation.Relation.REFERENCE:
data.copy = true;
dropHandlers.cancelDrop();
break;
}
}
else
{
dropHandlers.cancelDrop();
}
}
});