View Full Version : drag & drop image
wehtam
24 Aug 2007, 4:32 AM
Hello,
On ma page I have many pictures and I wouldl like reorder this pictures with drag & drop and save the news order.
How can i do that ?
Thanks
ps : sorry for my english
Animal
24 Aug 2007, 4:40 AM
Use a DDView: http://extjs.com/forum/showthread.php?t=9629
The template would be "<img src='{imageUrl}'>", and you'd need to create a Store of Records each containing just one field: imageUrl.
There's an example page which drops into examples/view
wehtam
24 Aug 2007, 5:04 AM
thanks, but i don't understand how to do this.
i have you a page with an example please. :">
Because my code doesn't work. :(:((
My code :
<link rel="stylesheet" type="text/css" href="../resources/css/ext-all.css" />
<script type="text/javascript" src="../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="FCKeditor/fckeditor.js"></script>
<script type="text/javascript" src="../ext-all.js"></script>
<script type="text/javascript" src="../source/locale/ext-lang-fr_FR.js"></script>
<script language="javascript">
Ext.namespace("Ext.ux");
/**
* @class Ext.ux.DDView
* A DnD enabled version of Ext.View.
* @param {Element/String} container The Element in which to create the View.
* @param {String} tpl The template string used to create the markup for each element of the View
* @param {Object} config The configuration properties. These include all the config options of
* {@link Ext.View} plus some specific to this class.<br>
* <p>
* Drag/drop is implemented by adding {@link Ext.data.Record}s to the target DDView. If copying is
* not being performed, the original {@link Ext.data.Record} is removed from the source DDView.<br>
* <p>
* The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
.x-view-drag-insert-above {
border-top:1px dotted #3366cc;
}
.x-view-drag-insert-below {
border-bottom:1px dotted #3366cc;
}
</code></pre>
*
*/
Ext.ux.DDView = function(container, tpl, config) {
Ext.ux.DDView.superclass.constructor.apply(this, arguments);
this.getEl().setStyle("outline", "0px none");
this.getEl().unselectable();
if (this.dragGroup) {
this.setDraggable(this.dragGroup.split(","));
}
if (this.dropGroup) {
this.setDroppable(this.dropGroup.split(","));
}
if (this.deletable) {
this.setDeletable();
}
this.isDirtyFlag = false;
this.addEvents({
"drop" : true
});
};
Ext.extend(Ext.ux.DDView, Ext.View, {
/** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
/** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
/** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
/** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
isFormField: true,
reset: Ext.emptyFn,
clearInvalid: Ext.form.Field.prototype.clearInvalid,
validate: function() {
return true;
},
destroy: function() {
this.purgeListeners();
this.getEl.removeAllListeners();
this.getEl().remove();
if (this.dragZone) {
if (this.dragZone.destroy) {
this.dragZone.destroy();
}
}
if (this.dropZone) {
if (this.dropZone.destroy) {
this.dropZone.destroy();
}
}
},
/** Allows this class to be an Ext.form.Field so it can be found using {@link Ext.form.BasicForm#findField}. */
getName: function() {
return this.name;
},
/** Loads the View from a JSON string representing the Records to put into the Store. */
setValue: function(v) {
if (!this.store) {
throw "DDView.setValue(). DDView must be constructed with a valid Store";
}
var data = {};
data[this.store.reader.meta.root] = v ? [].concat(v) : [];
this.store.proxy = new Ext.data.MemoryProxy(data);
this.store.load();
},
/** @return {String} a parenthesised list of the ids of the Records in the View. */
getValue: function() {
var result = '(';
this.store.each(function(rec) {
result += rec.id + ',';
});
return result.substr(0, result.length - 1) + ')';
},
getIds: function() {
var i = 0, result = new Array(this.store.getCount());
this.store.each(function(rec) {
result[i++] = rec.id;
});
return result;
},
isDirty: function() {
return this.isDirtyFlag;
},
/**
* Part of the Ext.dd.DropZone interface. If no target node is found, the
* whole Element becomes the target, and this causes the drop gesture to append.
*/
getTargetFromEvent : function(e) {
var target = e.getTarget();
while ((target !== null) && (target.parentNode != this.el.dom)) {
target = target.parentNode;
}
if (!target) {
target = this.el.dom.lastChild || this.el.dom;
}
return target;
},
/**
* Create the drag data which consists of an object which has the property "ddel" as
* the drag proxy element.
*/
getDragData : function(e) {
var target = this.findItemFromChild(e.getTarget());
if(target) {
this.handleSelection(e);
var selNodes = this.getSelectedNodes();
var dragData = {
source: this,
copy: this.copy || (this.allowCopy && e.ctrlKey),
nodes: selNodes,
records: []
};
var selectedIndices = this.getSelectedIndexes();
for (var i = 0; i < selectedIndices.length; i++) {
dragData.records.push(this.store.getAt(selectedIndices[i]));
}
if (selNodes.length == 1) {
dragData.ddel = target.cloneNode(true); // the div element
} else {
var div = document.createElement('div'); // create the multi element drag "ghost"
div.className = 'multi-proxy';
for (var i = 0, len = selNodes.length; i < len; i++) {
div.appendChild(selNodes[i].cloneNode(true));
}
dragData.ddel = div;
}
return dragData;
}
return false;
},
/** Specify to which ddGroup items in this DDView may be dragged. */
setDraggable: function(ddGroup) {
if (ddGroup instanceof Array) {
Ext.each(ddGroup, this.setDraggable, this);
return;
}
if (this.dragZone) {
this.dragZone.addToGroup(ddGroup);
} else {
this.dragZone = new Ext.dd.DragZone(this.getEl(), {
containerScroll: true,
ddGroup: ddGroup
});
// Draggability implies selection. DragZone's mousedown selects the element.
if (!this.multiSelect) { this.singleSelect = true; }
// Wire the DragZone's handlers up to methods in *this*
this.dragZone.getDragData = this.getDragData.createDelegate(this);
}
},
/** Specify from which ddGroup this DDView accepts drops. */
setDroppable: function(ddGroup) {
if (ddGroup instanceof Array) {
Ext.each(ddGroup, this.setDroppable, this);
return;
}
if (this.dropZone) {
this.dropZone.addToGroup(ddGroup);
} else {
this.dropZone = new Ext.dd.DropZone(this.getEl(), {
containerScroll: true,
ddGroup: ddGroup
});
// Wire the DropZone's handlers up to methods in *this*
this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
}
},
/** Decide whether to drop above or below a View node. */
getDropPoint : function(e, n, dd){
if (n == this.el.dom) { return "above"; }
var t = Ext.lib.Dom.getY(n), b = t + n.offsetHeight;
var c = t + (b - t) / 2;
var y = Ext.lib.Event.getPageY(e);
if(y <= c) {
return "above";
}else{
return "below";
}
},
onNodeEnter : function(n, dd, e, data){
return false;
},
onNodeOver : function(n, dd, e, data){
var pt = this.getDropPoint(e, n, dd);
// set the insert point style on the target node
var dragElClass = this.dropNotAllowed;
if (pt) {
var targetElClass;
if (pt == "above"){
dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
targetElClass = "x-view-drag-insert-above";
} else {
dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
targetElClass = "x-view-drag-insert-below";
}
if (this.lastInsertClass != targetElClass){
Ext.fly(n).replaceClass(this.lastInsertClass, targetElClass);
this.lastInsertClass = targetElClass;
}
}
return dragElClass;
},
onNodeOut : function(n, dd, e, data){
this.removeDropIndicators(n);
},
onNodeDrop : function(n, dd, e, data){
if (this.fireEvent("drop", this, n, dd, e, data) === false) {
return false;
}
var pt = this.getDropPoint(e, n, dd);
var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
if (pt == "below") { insertAt++; }
for (var i = 0; i < data.records.length; i++) {
var r = data.records[i];
var dup = this.store.getById(r.id);
if (dup && (dd != this.dragZone)) {
Ext.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
} else {
if (data.copy) {
this.store.insert(insertAt++, r.copy());
} else {
data.source.isDirtyFlag = true;
r.store.remove(r);
this.store.insert(insertAt++, r);
}
this.isDirtyFlag = true;
}
}
this.dragZone.cachedTarget = null;
return true;
},
removeDropIndicators : function(n){
if(n){
Ext.fly(n).removeClass([
"x-view-drag-insert-above",
"x-view-drag-insert-below"]);
this.lastInsertClass = "_noclass";
}
},
/**
* Utility method. Add a delete option to the DDView's context menu.
* @param {String} imageUrl The URL of the "delete" icon image.
*/
setDeletable: function(imageUrl) {
if (!this.singleSelect && !this.multiSelect) {
this.singleSelect = true;
}
var c = this.getContextMenu();
this.contextMenu.on("itemclick", function(item) {
switch (item.id) {
case "delete":
this.remove(this.getSelectedIndexes());
break;
}
}, this);
this.contextMenu.add({
icon: imageUrl || AU.resolveUrl("/images/delete.gif"),
id: "delete",
text: AU.getMessage("deleteItem")
});
},
/** Return the context menu for this DDView. */
getContextMenu: function() {
if (!this.contextMenu) {
// Create the View's context menu
this.contextMenu = new Ext.menu.Menu({
id: this.id + "-contextmenu"
});
this.el.on("contextmenu", this.showContextMenu, this);
}
return this.contextMenu;
},
disableContextMenu: function() {
if (this.contextMenu) {
this.el.un("contextmenu", this.showContextMenu, this);
}
},
showContextMenu: function(e, item) {
item = this.findItemFromChild(e.getTarget());
if (item) {
e.stopEvent();
this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
this.contextMenu.showAt(e.getXY());
}
},
/**
* Remove {@link Ext.data.Record}s at the specified indices.
* @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
*/
remove: function(selectedIndices) {
selectedIndices = [].concat(selectedIndices);
for (var i = 0; i < selectedIndices.length; i++) {
var rec = this.store.getAt(selectedIndices[i]);
this.store.remove(rec);
}
},
/**
* Double click fires the event, but also, if this is draggable, and there is only one other
* related DropZone, it transfers the selected node.
*/
onDblClick : function(e){
var item = this.findItemFromChild(e.getTarget());
if(item){
if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
return false;
}
if (this.dragGroup) {
var targets = Ext.dd.DragDropMgr.getRelated(this.dragZone, true);
while (targets.contains(this.dropZone)) {
targets.remove(this.dropZone);
}
if (targets.length == 1) {
this.dragZone.cachedTarget = null;
var el = Ext.get(targets[0].getEl());
var box = el.getBox(true);
targets[0].onNodeDrop(el.dom, {
target: el.dom,
xy: [box.x, box.y + box.height - 1]
}, null, this.getDragData(e));
}
}
}
},
handleSelection: function(e) {
this.dragZone.cachedTarget = null;
var item = this.findItemFromChild(e.getTarget());
if (!item) {
this.clearSelections(true);
return;
}
if (item && (this.multiSelect || this.singleSelect)){
if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
}else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
this.unselect(item);
} else {
this.select(item, this.multiSelect && e.ctrlKey);
this.lastSelection = item;
}
}
},
onItemClick : function(item, index, e){
if(this.fireEvent("beforeclick", this, index, item, e) === false){
return false;
}
return true;
},
unselect : function(nodeInfo, suppressEvent){
var node = this.getNode(nodeInfo);
if(node && this.isSelected(node)){
if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
Ext.fly(node).removeClass(this.selectedClass);
this.selections.remove(node);
if(!suppressEvent){
this.fireEvent("selectionchange", this, this.selections);
}
}
}
}
});
// First View:
var collection=[
{'id':'40','imageUrl':'/images/gibier/20070731111110.jpg'},
{'id':'27','imageUrl.':'/images/gibier/20070731111110.jpg'}
];
var rec=Ext.data.Record.create([
{name:'id'},
{name:'imageUrl'}
]);
var reader=new Ext.data.JsonReader({root:'collection',id:'id'},rec);
var ds=new Ext.data.Store({
proxy:new Ext.data.MemoryProxy({collection:collection}),
reader:reader
});
var view=new Ext.ux.DDView('AspicioForm1184919651718View7','<div id=\u0027subcomponent_{id}\u0027 class=\u0027Subcomponent\u0027><img align=\u0027top\u0027 height=\u002716px\u0027 width=\u002716px\u0027 src=\u0027{entityImageUrl}\u0027></div>',{
isFormField:true,
name:'subComponents',
dragGroup:'availableSubcomponents',
dropGroup:'availableSubcomponents',
selectedClass: 'asp-selected',
jsonRoot: 'collection',
store: ds
});
ds.load();
// Second View:
var collection=[];
var rec=Ext.data.Record.create([
{name:'id'},
{name:'imageUrl.'}
]);
var reader=new Ext.data.JsonReader({root:'collection',id:'id'},rec);
var ds=new Ext.data.Store({
proxy:new Ext.data.MemoryProxy({collection:collection}),
reader:reader
});
var view=new Ext.ux.DDView('AspicioForm1184919651718View8','<div id=\u0027component_{id}\u0027 class=\u0027Component\u0027><img align=\u0027top\u0027 height=\u002716px\u0027 width=\u002716px\u0027 src=\u0027{imageUrl}\u0027></div>',{
isFormField:true,
multiSelect: true,
dragGroup:'availableSubcomponents',
dropGroup:'availableSubcomponents',
selectedClass: 'asp-selected',
jsonRoot: 'collection',
store: ds
});
ds.load();
</script>
<link rel="stylesheet" type="text/css" href="../examples/grid/grid-examples.css" />
<link rel="stylesheet" type="text/css" href="../examples/form/forms.css" />
<div id="container">
<div id="toolbar"></div>
<br>
<table align="center"><tr><td>
<div style="width:694px;">
<div style="width:694px;" class="x-box-blue">
<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>
<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc">
<h3 style="margin-bottom:5px;">Images</h3>
<div id="topic-grid" style="border:1px solid #99bbe8;overflow: hidden; width: 665px; height: 400px;"></div>
</div></div></div>
<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>
</div>
</div>
</td></tr></table>
</div>
thanks
Animal
24 Aug 2007, 5:12 AM
"doesn't work" doesn't help us.
Use Firefox with Firebug to debug!
Animal
24 Aug 2007, 5:13 AM
Have you got a div called "AspicioForm1184919651718View7"????
Animal
24 Aug 2007, 5:20 AM
Use the template I gave you
Read the docs:
* @param {Element/String} container The Element in which to create the View.
* @param {String} tpl The template string used to create the markup for each element of the View
* @param {Object} config The configuration properties. These include all the config options of
wehtam
24 Aug 2007, 5:47 AM
no sorry , i replace "AspicioForm1184919651718View7" by "topic-grid"
my code is like this now :
<link rel="stylesheet" type="text/css" href="../resources/css/ext-all.css" />
<script type="text/javascript" src="../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="FCKeditor/fckeditor.js"></script>
<script type="text/javascript" src="../ext-all.js"></script>
<script type="text/javascript" src="../source/locale/ext-lang-fr_FR.js"></script>
<script language="javascript">
Ext.namespace("Ext.ux");
/**
* @class Ext.ux.DDView
* A DnD enabled version of Ext.View.
* @param {Element/String} container The Element in which to create the View.
* @param {String} tpl The template string used to create the markup for each element of the View
* @param {Object} config The configuration properties. These include all the config options of
* {@link Ext.View} plus some specific to this class.<br>
* <p>
* Drag/drop is implemented by adding {@link Ext.data.Record}s to the target DDView. If copying is
* not being performed, the original {@link Ext.data.Record} is removed from the source DDView.<br>
* <p>
* The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
.x-view-drag-insert-above {
border-top:1px dotted #3366cc;
}
.x-view-drag-insert-below {
border-bottom:1px dotted #3366cc;
}
</code></pre>
*
*/
Ext.ux.DDView = function(container, tpl, config) {
Ext.ux.DDView.superclass.constructor.apply(this, arguments);
this.getEl().setStyle("outline", "0px none");
this.getEl().unselectable();
if (this.dragGroup) {
this.setDraggable(this.dragGroup.split(","));
}
if (this.dropGroup) {
this.setDroppable(this.dropGroup.split(","));
}
if (this.deletable) {
this.setDeletable();
}
this.isDirtyFlag = false;
this.addEvents({
"drop" : true
});
};
Ext.extend(Ext.ux.DDView, Ext.View, {
/** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
/** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
/** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
/** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
isFormField: true,
reset: Ext.emptyFn,
clearInvalid: Ext.form.Field.prototype.clearInvalid,
validate: function() {
return true;
},
destroy: function() {
this.purgeListeners();
this.getEl.removeAllListeners();
this.getEl().remove();
if (this.dragZone) {
if (this.dragZone.destroy) {
this.dragZone.destroy();
}
}
if (this.dropZone) {
if (this.dropZone.destroy) {
this.dropZone.destroy();
}
}
},
/** Allows this class to be an Ext.form.Field so it can be found using {@link Ext.form.BasicForm#findField}. */
getName: function() {
return this.name;
},
/** Loads the View from a JSON string representing the Records to put into the Store. */
setValue: function(v) {
if (!this.store) {
throw "DDView.setValue(). DDView must be constructed with a valid Store";
}
var data = {};
data[this.store.reader.meta.root] = v ? [].concat(v) : [];
this.store.proxy = new Ext.data.MemoryProxy(data);
this.store.load();
},
/** @return {String} a parenthesised list of the ids of the Records in the View. */
getValue: function() {
var result = '(';
this.store.each(function(rec) {
result += rec.id + ',';
});
return result.substr(0, result.length - 1) + ')';
},
getIds: function() {
var i = 0, result = new Array(this.store.getCount());
this.store.each(function(rec) {
result[i++] = rec.id;
});
return result;
},
isDirty: function() {
return this.isDirtyFlag;
},
/**
* Part of the Ext.dd.DropZone interface. If no target node is found, the
* whole Element becomes the target, and this causes the drop gesture to append.
*/
getTargetFromEvent : function(e) {
var target = e.getTarget();
while ((target !== null) && (target.parentNode != this.el.dom)) {
target = target.parentNode;
}
if (!target) {
target = this.el.dom.lastChild || this.el.dom;
}
return target;
},
/**
* Create the drag data which consists of an object which has the property "ddel" as
* the drag proxy element.
*/
getDragData : function(e) {
var target = this.findItemFromChild(e.getTarget());
if(target) {
this.handleSelection(e);
var selNodes = this.getSelectedNodes();
var dragData = {
source: this,
copy: this.copy || (this.allowCopy && e.ctrlKey),
nodes: selNodes,
records: []
};
var selectedIndices = this.getSelectedIndexes();
for (var i = 0; i < selectedIndices.length; i++) {
dragData.records.push(this.store.getAt(selectedIndices[i]));
}
if (selNodes.length == 1) {
dragData.ddel = target.cloneNode(true); // the div element
} else {
var div = document.createElement('div'); // create the multi element drag "ghost"
div.className = 'multi-proxy';
for (var i = 0, len = selNodes.length; i < len; i++) {
div.appendChild(selNodes[i].cloneNode(true));
}
dragData.ddel = div;
}
return dragData;
}
return false;
},
/** Specify to which ddGroup items in this DDView may be dragged. */
setDraggable: function(ddGroup) {
if (ddGroup instanceof Array) {
Ext.each(ddGroup, this.setDraggable, this);
return;
}
if (this.dragZone) {
this.dragZone.addToGroup(ddGroup);
} else {
this.dragZone = new Ext.dd.DragZone(this.getEl(), {
containerScroll: true,
ddGroup: ddGroup
});
// Draggability implies selection. DragZone's mousedown selects the element.
if (!this.multiSelect) { this.singleSelect = true; }
// Wire the DragZone's handlers up to methods in *this*
this.dragZone.getDragData = this.getDragData.createDelegate(this);
}
},
/** Specify from which ddGroup this DDView accepts drops. */
setDroppable: function(ddGroup) {
if (ddGroup instanceof Array) {
Ext.each(ddGroup, this.setDroppable, this);
return;
}
if (this.dropZone) {
this.dropZone.addToGroup(ddGroup);
} else {
this.dropZone = new Ext.dd.DropZone(this.getEl(), {
containerScroll: true,
ddGroup: ddGroup
});
// Wire the DropZone's handlers up to methods in *this*
this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
}
},
/** Decide whether to drop above or below a View node. */
getDropPoint : function(e, n, dd){
if (n == this.el.dom) { return "above"; }
var t = Ext.lib.Dom.getY(n), b = t + n.offsetHeight;
var c = t + (b - t) / 2;
var y = Ext.lib.Event.getPageY(e);
if(y <= c) {
return "above";
}else{
return "below";
}
},
onNodeEnter : function(n, dd, e, data){
return false;
},
onNodeOver : function(n, dd, e, data){
var pt = this.getDropPoint(e, n, dd);
// set the insert point style on the target node
var dragElClass = this.dropNotAllowed;
if (pt) {
var targetElClass;
if (pt == "above"){
dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
targetElClass = "x-view-drag-insert-above";
} else {
dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
targetElClass = "x-view-drag-insert-below";
}
if (this.lastInsertClass != targetElClass){
Ext.fly(n).replaceClass(this.lastInsertClass, targetElClass);
this.lastInsertClass = targetElClass;
}
}
return dragElClass;
},
onNodeOut : function(n, dd, e, data){
this.removeDropIndicators(n);
},
onNodeDrop : function(n, dd, e, data){
if (this.fireEvent("drop", this, n, dd, e, data) === false) {
return false;
}
var pt = this.getDropPoint(e, n, dd);
var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
if (pt == "below") { insertAt++; }
for (var i = 0; i < data.records.length; i++) {
var r = data.records[i];
var dup = this.store.getById(r.id);
if (dup && (dd != this.dragZone)) {
Ext.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
} else {
if (data.copy) {
this.store.insert(insertAt++, r.copy());
} else {
data.source.isDirtyFlag = true;
r.store.remove(r);
this.store.insert(insertAt++, r);
}
this.isDirtyFlag = true;
}
}
this.dragZone.cachedTarget = null;
return true;
},
removeDropIndicators : function(n){
if(n){
Ext.fly(n).removeClass([
"x-view-drag-insert-above",
"x-view-drag-insert-below"]);
this.lastInsertClass = "_noclass";
}
},
/**
* Utility method. Add a delete option to the DDView's context menu.
* @param {String} imageUrl The URL of the "delete" icon image.
*/
setDeletable: function(imageUrl) {
if (!this.singleSelect && !this.multiSelect) {
this.singleSelect = true;
}
var c = this.getContextMenu();
this.contextMenu.on("itemclick", function(item) {
switch (item.id) {
case "delete":
this.remove(this.getSelectedIndexes());
break;
}
}, this);
this.contextMenu.add({
icon: imageUrl || AU.resolveUrl("/images/delete.gif"),
id: "delete",
text: AU.getMessage("deleteItem")
});
},
/** Return the context menu for this DDView. */
getContextMenu: function() {
if (!this.contextMenu) {
// Create the View's context menu
this.contextMenu = new Ext.menu.Menu({
id: this.id + "-contextmenu"
});
this.el.on("contextmenu", this.showContextMenu, this);
}
return this.contextMenu;
},
disableContextMenu: function() {
if (this.contextMenu) {
this.el.un("contextmenu", this.showContextMenu, this);
}
},
showContextMenu: function(e, item) {
item = this.findItemFromChild(e.getTarget());
if (item) {
e.stopEvent();
this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
this.contextMenu.showAt(e.getXY());
}
},
/**
* Remove {@link Ext.data.Record}s at the specified indices.
* @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
*/
remove: function(selectedIndices) {
selectedIndices = [].concat(selectedIndices);
for (var i = 0; i < selectedIndices.length; i++) {
var rec = this.store.getAt(selectedIndices[i]);
this.store.remove(rec);
}
},
/**
* Double click fires the event, but also, if this is draggable, and there is only one other
* related DropZone, it transfers the selected node.
*/
onDblClick : function(e){
var item = this.findItemFromChild(e.getTarget());
if(item){
if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
return false;
}
if (this.dragGroup) {
var targets = Ext.dd.DragDropMgr.getRelated(this.dragZone, true);
while (targets.contains(this.dropZone)) {
targets.remove(this.dropZone);
}
if (targets.length == 1) {
this.dragZone.cachedTarget = null;
var el = Ext.get(targets[0].getEl());
var box = el.getBox(true);
targets[0].onNodeDrop(el.dom, {
target: el.dom,
xy: [box.x, box.y + box.height - 1]
}, null, this.getDragData(e));
}
}
}
},
handleSelection: function(e) {
this.dragZone.cachedTarget = null;
var item = this.findItemFromChild(e.getTarget());
if (!item) {
this.clearSelections(true);
return;
}
if (item && (this.multiSelect || this.singleSelect)){
if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
}else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
this.unselect(item);
} else {
this.select(item, this.multiSelect && e.ctrlKey);
this.lastSelection = item;
}
}
},
onItemClick : function(item, index, e){
if(this.fireEvent("beforeclick", this, index, item, e) === false){
return false;
}
return true;
},
unselect : function(nodeInfo, suppressEvent){
var node = this.getNode(nodeInfo);
if(node && this.isSelected(node)){
if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
Ext.fly(node).removeClass(this.selectedClass);
this.selections.remove(node);
if(!suppressEvent){
this.fireEvent("selectionchange", this, this.selections);
}
}
}
}
});
// First View:
var collection=[
{'id':'1','imageUrl':'/images/gibier/20070731111110.jpg'},
{'id':'2','imageUrl':'/images/gibier/20070731111110.jpg'}
];
var rec=Ext.data.Record.create([
{name:'id'},
{name:'imageUrl'}
]);
var reader=new Ext.data.JsonReader({root:'collection',id:'id'},rec);
var ds=new Ext.data.Store({
proxy:new Ext.data.MemoryProxy({collection:collection}),
reader:reader
});
var view=new Ext.ux.DDView('topic-grid','<div id=\u0027subcomponent_{id}\u0027 class=\u0027Subcomponent\u0027><img align=\u0027top\u0027 height=\u002716px\u0027 width=\u002716px\u0027 src=\u0027{imageUrl}\u0027></div>',{
isFormField:true,
name:'subComponents',
dragGroup:'availableSubcomponents',
dropGroup:'availableSubcomponents',
selectedClass: 'asp-selected',
jsonRoot: 'collection',
store: ds
});
ds.load();
/*// Second View:
var collection=[];
var rec=Ext.data.Record.create([
{name:'id'},
{name:'imageUrl'}
]);
var reader=new Ext.data.JsonReader({root:'collection',id:'id'},rec);
var ds=new Ext.data.Store({
proxy:new Ext.data.MemoryProxy({collection:collection}),
reader:reader
});
var view=new Ext.ux.DDView('topic-grid','<div id=\u0027component_{id}\u0027 class=\u0027Component\u0027><img align=\u0027top\u0027 height=\u002716px\u0027 width=\u002716px\u0027 src=\u0027{imageUrl}\u0027></div>',{
isFormField:true,
multiSelect: true,
dragGroup:'availableSubcomponents',
dropGroup:'availableSubcomponents',
selectedClass: 'asp-selected',
jsonRoot: 'collection',
store: ds
});
ds.load();*/
</script>
<link rel="stylesheet" type="text/css" href="../examples/grid/grid-examples.css" />
<link rel="stylesheet" type="text/css" href="../examples/form/forms.css" />
<div id="container">
<div id="toolbar"></div>
<br>
<table align="center"><tr><td>
<div style="width:694px;">
<div style="width:694px;" class="x-box-blue">
<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>
<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc">
<h3 style="margin-bottom:5px;">Images</h3>
<div id="topic-grid" style="border:1px solid #99bbe8;overflow: hidden; width: 665px; height: 400px;"></div>
</div></div></div>
<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>
</div>
</div>
</td></tr></table>
</div>
but firebug return this :
this.el has no properties
View("topic-grid", Object, Object isFormField=true name=subComponents)ext-all.js (ligne 114)
DDView("topic-grid", "<img align='top' height='16px' width='16px' src='{imageUrl}'>", Object isFormField=true name=subComponents)images.php (ligne 32)
[Break on this error] Ext.View=function(_1,_2,_3){this.el=Ext.get(_1);if(typeof _2=="string"){_2=new E...
Animal
24 Aug 2007, 5:53 AM
So follow the error stacktrace back, and see what's happening...
http://www.mysmiley.net/imgs/smile/rolleye/rolleye0003.gif
Animal
24 Aug 2007, 6:00 AM
Use Ext.onReady - find it in the docs.
Use the template I gave you in the DDView constructor.
Animal
24 Aug 2007, 6:06 AM
??
<link rel="stylesheet" type="text/css" href="../resources/css/ext-all.css" />
<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../../ext-all-debug.js"></script>
<script language="javascript">
Ext.namespace("Ext.ux");
/**
* @class Ext.ux.DDView
* A DnD enabled version of Ext.View.
* @param {Element/String} container The Element in which to create the View.
* @param {String} tpl The template string used to create the markup for each element of the View
* @param {Object} config The configuration properties. These include all the config options of
* {@link Ext.View} plus some specific to this class.<br>
* <p>
* Drag/drop is implemented by adding {@link Ext.data.Record}s to the target DDView. If copying is
* not being performed, the original {@link Ext.data.Record} is removed from the source DDView.<br>
* <p>
* The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
.x-view-drag-insert-above {
border-top:1px dotted #3366cc;
}
.x-view-drag-insert-below {
border-bottom:1px dotted #3366cc;
}
</code></pre>
*
*/
Ext.ux.DDView = function(container, tpl, config) {
Ext.ux.DDView.superclass.constructor.apply(this, arguments);
this.getEl().setStyle("outline", "0px none");
this.getEl().unselectable();
if (this.dragGroup) {
this.setDraggable(this.dragGroup.split(","));
}
if (this.dropGroup) {
this.setDroppable(this.dropGroup.split(","));
}
if (this.deletable) {
this.setDeletable();
}
this.isDirtyFlag = false;
this.addEvents({
"drop" : true
});
};
Ext.extend(Ext.ux.DDView, Ext.View, {
/** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
/** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
/** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
/** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
isFormField: true,
reset: Ext.emptyFn,
clearInvalid: Ext.form.Field.prototype.clearInvalid,
validate: function() {
return true;
},
destroy: function() {
this.purgeListeners();
this.getEl.removeAllListeners();
this.getEl().remove();
if (this.dragZone) {
if (this.dragZone.destroy) {
this.dragZone.destroy();
}
}
if (this.dropZone) {
if (this.dropZone.destroy) {
this.dropZone.destroy();
}
}
},
/** Allows this class to be an Ext.form.Field so it can be found using {@link Ext.form.BasicForm#findField}. */
getName: function() {
return this.name;
},
/** Loads the View from a JSON string representing the Records to put into the Store. */
setValue: function(v) {
if (!this.store) {
throw "DDView.setValue(). DDView must be constructed with a valid Store";
}
var data = {};
data[this.store.reader.meta.root] = v ? [].concat(v) : [];
this.store.proxy = new Ext.data.MemoryProxy(data);
this.store.load();
},
/** @return {String} a parenthesised list of the ids of the Records in the View. */
getValue: function() {
var result = '(';
this.store.each(function(rec) {
result += rec.id + ',';
});
return result.substr(0, result.length - 1) + ')';
},
getIds: function() {
var i = 0, result = new Array(this.store.getCount());
this.store.each(function(rec) {
result[i++] = rec.id;
});
return result;
},
isDirty: function() {
return this.isDirtyFlag;
},
/**
* Part of the Ext.dd.DropZone interface. If no target node is found, the
* whole Element becomes the target, and this causes the drop gesture to append.
*/
getTargetFromEvent : function(e) {
var target = e.getTarget();
while ((target !== null) && (target.parentNode != this.el.dom)) {
target = target.parentNode;
}
if (!target) {
target = this.el.dom.lastChild || this.el.dom;
}
return target;
},
/**
* Create the drag data which consists of an object which has the property "ddel" as
* the drag proxy element.
*/
getDragData : function(e) {
var target = this.findItemFromChild(e.getTarget());
if(target) {
this.handleSelection(e);
var selNodes = this.getSelectedNodes();
var dragData = {
source: this,
copy: this.copy || (this.allowCopy && e.ctrlKey),
nodes: selNodes,
records: []
};
var selectedIndices = this.getSelectedIndexes();
for (var i = 0; i < selectedIndices.length; i++) {
dragData.records.push(this.store.getAt(selectedIndices[i]));
}
if (selNodes.length == 1) {
dragData.ddel = target.cloneNode(true); // the div element
} else {
var div = document.createElement('div'); // create the multi element drag "ghost"
div.className = 'multi-proxy';
for (var i = 0, len = selNodes.length; i < len; i++) {
div.appendChild(selNodes[i].cloneNode(true));
}
dragData.ddel = div;
}
return dragData;
}
return false;
},
/** Specify to which ddGroup items in this DDView may be dragged. */
setDraggable: function(ddGroup) {
if (ddGroup instanceof Array) {
Ext.each(ddGroup, this.setDraggable, this);
return;
}
if (this.dragZone) {
this.dragZone.addToGroup(ddGroup);
} else {
this.dragZone = new Ext.dd.DragZone(this.getEl(), {
containerScroll: true,
ddGroup: ddGroup
});
// Draggability implies selection. DragZone's mousedown selects the element.
if (!this.multiSelect) { this.singleSelect = true; }
// Wire the DragZone's handlers up to methods in *this*
this.dragZone.getDragData = this.getDragData.createDelegate(this);
}
},
/** Specify from which ddGroup this DDView accepts drops. */
setDroppable: function(ddGroup) {
if (ddGroup instanceof Array) {
Ext.each(ddGroup, this.setDroppable, this);
return;
}
if (this.dropZone) {
this.dropZone.addToGroup(ddGroup);
} else {
this.dropZone = new Ext.dd.DropZone(this.getEl(), {
containerScroll: true,
ddGroup: ddGroup
});
// Wire the DropZone's handlers up to methods in *this*
this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
}
},
/** Decide whether to drop above or below a View node. */
getDropPoint : function(e, n, dd){
if (n == this.el.dom) { return "above"; }
var t = Ext.lib.Dom.getY(n), b = t + n.offsetHeight;
var c = t + (b - t) / 2;
var y = Ext.lib.Event.getPageY(e);
if(y <= c) {
return "above";
}else{
return "below";
}
},
onNodeEnter : function(n, dd, e, data){
return false;
},
onNodeOver : function(n, dd, e, data){
var pt = this.getDropPoint(e, n, dd);
// set the insert point style on the target node
var dragElClass = this.dropNotAllowed;
if (pt) {
var targetElClass;
if (pt == "above"){
dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
targetElClass = "x-view-drag-insert-above";
} else {
dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
targetElClass = "x-view-drag-insert-below";
}
if (this.lastInsertClass != targetElClass){
Ext.fly(n).replaceClass(this.lastInsertClass, targetElClass);
this.lastInsertClass = targetElClass;
}
}
return dragElClass;
},
onNodeOut : function(n, dd, e, data){
this.removeDropIndicators(n);
},
onNodeDrop : function(n, dd, e, data){
if (this.fireEvent("drop", this, n, dd, e, data) === false) {
return false;
}
var pt = this.getDropPoint(e, n, dd);
var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
if (pt == "below") { insertAt++; }
for (var i = 0; i < data.records.length; i++) {
var r = data.records[i];
var dup = this.store.getById(r.id);
if (dup && (dd != this.dragZone)) {
Ext.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
} else {
if (data.copy) {
this.store.insert(insertAt++, r.copy());
} else {
data.source.isDirtyFlag = true;
r.store.remove(r);
this.store.insert(insertAt++, r);
}
this.isDirtyFlag = true;
}
}
this.dragZone.cachedTarget = null;
return true;
},
removeDropIndicators : function(n){
if(n){
Ext.fly(n).removeClass([
"x-view-drag-insert-above",
"x-view-drag-insert-below"]);
this.lastInsertClass = "_noclass";
}
},
/**
* Utility method. Add a delete option to the DDView's context menu.
* @param {String} imageUrl The URL of the "delete" icon image.
*/
setDeletable: function(imageUrl) {
if (!this.singleSelect && !this.multiSelect) {
this.singleSelect = true;
}
var c = this.getContextMenu();
this.contextMenu.on("itemclick", function(item) {
switch (item.id) {
case "delete":
this.remove(this.getSelectedIndexes());
break;
}
}, this);
this.contextMenu.add({
icon: imageUrl || AU.resolveUrl("/images/delete.gif"),
id: "delete",
text: AU.getMessage("deleteItem")
});
},
/** Return the context menu for this DDView. */
getContextMenu: function() {
if (!this.contextMenu) {
// Create the View's context menu
this.contextMenu = new Ext.menu.Menu({
id: this.id + "-contextmenu"
});
this.el.on("contextmenu", this.showContextMenu, this);
}
return this.contextMenu;
},
disableContextMenu: function() {
if (this.contextMenu) {
this.el.un("contextmenu", this.showContextMenu, this);
}
},
showContextMenu: function(e, item) {
item = this.findItemFromChild(e.getTarget());
if (item) {
e.stopEvent();
this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
this.contextMenu.showAt(e.getXY());
}
},
/**
* Remove {@link Ext.data.Record}s at the specified indices.
* @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
*/
remove: function(selectedIndices) {
selectedIndices = [].concat(selectedIndices);
for (var i = 0; i < selectedIndices.length; i++) {
var rec = this.store.getAt(selectedIndices[i]);
this.store.remove(rec);
}
},
/**
* Double click fires the event, but also, if this is draggable, and there is only one other
* related DropZone, it transfers the selected node.
*/
onDblClick : function(e){
var item = this.findItemFromChild(e.getTarget());
if(item){
if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
return false;
}
if (this.dragGroup) {
var targets = Ext.dd.DragDropMgr.getRelated(this.dragZone, true);
while (targets.contains(this.dropZone)) {
targets.remove(this.dropZone);
}
if (targets.length == 1) {
this.dragZone.cachedTarget = null;
var el = Ext.get(targets[0].getEl());
var box = el.getBox(true);
targets[0].onNodeDrop(el.dom, {
target: el.dom,
xy: [box.x, box.y + box.height - 1]
}, null, this.getDragData(e));
}
}
}
},
handleSelection: function(e) {
this.dragZone.cachedTarget = null;
var item = this.findItemFromChild(e.getTarget());
if (!item) {
this.clearSelections(true);
return;
}
if (item && (this.multiSelect || this.singleSelect)){
if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
}else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
this.unselect(item);
} else {
this.select(item, this.multiSelect && e.ctrlKey);
this.lastSelection = item;
}
}
},
onItemClick : function(item, index, e){
if(this.fireEvent("beforeclick", this, index, item, e) === false){
return false;
}
return true;
},
unselect : function(nodeInfo, suppressEvent){
var node = this.getNode(nodeInfo);
if(node && this.isSelected(node)){
if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
Ext.fly(node).removeClass(this.selectedClass);
this.selections.remove(node);
if(!suppressEvent){
this.fireEvent("selectionchange", this, this.selections);
}
}
}
}
});
Ext.onReady(function() {
// First View:
var collection=[
{'id':'1','imageUrl':'/images/gibier/20070731111110.jpg'},
{'id':'2','imageUrl':'/images/gibier/20070731111110.jpg'}
];
var rec=Ext.data.Record.create([
{name:'id'},
{name:'imageUrl'}
]);
var reader=new Ext.data.JsonReader({root:'collection',id:'id'},rec);
var ds=new Ext.data.Store({
proxy:new Ext.data.MemoryProxy({collection:collection}),
reader:reader
});
var view=new Ext.ux.DDView('topic-grid','<div id="pic{id}"><img src="{imageUrl}"></div>',{
isFormField:true,
name:'subComponents',
dragGroup:'availableSubcomponents',
dropGroup:'availableSubcomponents',
selectedClass: 'asp-selected',
jsonRoot: 'collection',
store: ds
});
ds.load();
});
</script>
<link rel="stylesheet" type="text/css" href="../examples/grid/grid-examples.css" />
<link rel="stylesheet" type="text/css" href="../examples/form/forms.css" />
<div id="container">
<div id="toolbar"></div>
<br>
<table align="center"><tr><td>
<div style="width:694px;">
<div style="width:694px;" class="x-box-blue">
<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>
<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc">
<h3 style="margin-bottom:5px;">Images</h3>
<div id="topic-grid" style="border:1px solid #99bbe8;overflow: hidden; width: 665px; height: 400px;"></div>
</div></div></div>
<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>
</div>
</div>
</td></tr></table>
</div>
krycek
25 Oct 2007, 6:08 AM
I've tested your code, Animal. It works fine with Ext 1.1 but not with 2.0.
Since I'm using 2.0, I'm working with the new DataView so I dont need extend the View class, right?
But there is no example of how to create a DnD with DataView.
Could you show some piece of code that demostrates DnD with DataView?
Thank You
Powered by vBulletin® Version 4.1.5 Copyright © 2012 vBulletin Solutions, Inc. All rights reserved.