PDA

View Full Version : Ext.ux.grid.DataDrop



VinylFox
3 Sep 2009, 12:55 PM
This is a plugin for the Grid that allows dropping of rows from spreadsheets directly into the grid. More details along with a screencast are on my blog post.



Blog Post: DataDrop - Drag Grid Data in From a Spreadsheet (http://www.vinylfox.com/datadrop-drag-grid-data-from-spreadsheet/)
Blog Post: DataDrop - Forwarding Mouse Events Through Layers (http://www.vinylfox.com/forwarding-mouse-events-through-layers/)
Google Code Repo (http://code.google.com/p/ext-ux-datadrop/) (outdated, see Github instead)
DataDrop code on Github (https://github.com/VinylFox/ExtJS.ux.DataDrop/) (current code)
See it in action (ScreenCast) (http://screencast.com/t/4bZevAUwEuj)



Not sure what else to say...

Enjoy!

chemist458
3 Sep 2009, 4:20 PM
Wow, that looks like the hottest thing I have ever seen!!
Cant wait to try it out, incredible work, thanks!

VinylFox
4 Sep 2009, 4:41 AM
Thanks chemist458.

Im hoping to get some feedback on the implementation, as im not sure how it will work with different makes/versions of spreadsheet programs.

I have been playing with dragging data from programs other than spreadsheets, and just a word of warning, DO NOT drag emails from Thunderbird into Firefox, as it will peg the cpu for both apps.

chemist458
4 Sep 2009, 3:52 PM
I told everyone in my office, and they nearly wet themselves!!
Hopefully this week I will implement it and give a good try
George

VinylFox
7 Sep 2009, 6:42 AM
@chemist458 - Excellent, that was my intention - to get people to urinate on themselves. Good to hear :)

Be sure to get the most recent version from my SVN repo on Google code. Both Nige (Animal) and I have made some major changes since the initial version was thrown together.

mystix
7 Sep 2009, 9:52 AM
@chemist458 - Excellent, that was my intention - to get people to urinate on themselves. Good to hear :)
.

good job raising a stink >:)

mystix
7 Sep 2009, 9:54 AM
p.s. i really like @nige's singleton plugin pattern!

Animal
14 Sep 2009, 10:28 AM
I've been delving deep into the W3 Events API (And the crappy IE one)...

You can actually have the textarea that recieves the drop events covering 100% of the data area of the grid, but being transparent, so that you can drop directly over the grids rows.

You retain mouse control by forwarding mouse events from the textarea into te underlying elements. So we now have completely transparent Dragging from external apps into GridPanels.

Below shows how. Hopefully, Shea and I will be able to get this posted to Google code:

*UPDATE*
Now posted on Google Code (http://code.google.com/p/ext-ux-datadrop/source/browse/trunk/src/Override.js)

Scorpie
15 Sep 2009, 6:37 AM
Holy , is there anything you guys can`t do?

VinylFox
30 Sep 2009, 7:32 AM
Updated the DataDrop code and integrated Animals override that allowed event forwarding through masking layers. Pretty cool stuff. My blog post explains more about it...

Forwarding Mouse Events Through Layers (http://www.vinylfox.com/forwarding-mouse-events-through-layers/)

Took a new ScreenCast of it in action (http://screencast.com/t/4bZevAUwEuj)

First post updated.

jay@moduscreate.com
2 Oct 2009, 4:02 AM
Kick ass, Shea!!

VinylFox
2 Oct 2009, 4:35 AM
Nigel and my work on this plugin got picked up by Ajaxian.

Hide and Seek via Mouse (http://ajaxian.com/archives/hide-and-seek-via-mouse)

They have summarized it well.

jay@moduscreate.com
2 Oct 2009, 4:44 AM
Huge!!! Congrats dude.

crp_spaeth
2 Oct 2009, 5:50 AM
Wow! very impressive!

I will defenitly give it a try in one of our apps...

Combine it with my Copy&Paste Plugin (https://www.extjs.com/forum/showthread.php?t=64477) and you will have a seamless Integration of an Web-app into the Desktop.

VinylFox
2 Oct 2009, 5:53 AM
@crp_spaeth - I think you might have linked to the wrong post.

How about this: https://www.extjs.com/forum/showthread.php?t=64477

Ill give it a look.

crp_spaeth
2 Oct 2009, 5:59 AM
Wher did that link come from? :) Jeah your right...

hendricd
2 Oct 2009, 7:36 AM
Nice work, guys! =D>

I was playing with the example, and noticed that the mousewheel is ineffective (scrolling the grid). It does work when over the scroller.

Can you somehow pass those events down too?

Animal
2 Oct 2009, 10:27 AM
I'm working on this at home.

Right now, it's just IE that is holding things up. I'll post an update here, and to Shea when I get it working.

aw1zard2
2 Oct 2009, 11:47 AM
Excellent work guys. I have been toying with drag and drop for file uploading on mozilla 3.6 alpha. Using the File API. Anyone know if IE has started any work for file uploading like the other browsers have? I haven't found too much talk about it.

http://dev.w3.org/2006/webapi/FileUpload/publish/FileAPI.html

=D>

Thomas Triplet
5 Oct 2009, 10:46 AM
=D> =D> Woww look great!

Works nicely, but I'm getting an error message (just added plugins: [Ext.ux.grid.DataDrop] in the grid config)

Uncaught TypeError: Cannot read property '0' of null at ext-base-debug.js:3482


The data does appear in the grid, but the data isn't sent to the server (added newRec.markDirty(); in function dataDropped() before adding to the store. The dirty marks do appear as well, but data is still not sent (getting data to be sent using getModifiedRecords) =/

VinylFox
5 Oct 2009, 12:43 PM
Works nicely, but I'm getting an error message (just added plugins: [Ext.ux.grid.DataDrop] in the grid config)

Uncaught TypeError: Cannot read property '0' of null at ext-base-debug.js:3482

The data does appear in the grid, but the data isn't sent to the server (added newRec.markDirty(); in function dataDropped() before adding to the store. The dirty marks do appear as well, but data is still not sent (getting data to be sent using getModifiedRecords) =/

You sure your using 3.x ? if so, what version exactly?

If you have an example page with this problem, that would help.

Thomas Triplet
6 Oct 2009, 7:17 AM
Yes, I am using version 3.0.0

I dont have the page online, but bellow are relevant pieces of code:



Passport.spreadsheet_panel = new Ext.grid.EditorGridPanel( {
id: 'spreadsheet_panel',
title:"Substrates",
iconCls: 'icon-grid',
store: Passport.spreadsheet_store,
cm: cmSubstrates,
bbar: pagingBar,
autoExpandColumn: 'substrates_name',
view: new Ext.grid.GroupingView( {
groupTextTpl: '{text} ({[values.rs.length]} {[values.rs.length > 1 ? "Items": "Item"]})'
}),
region: 'center',
layout: 'fit',
stripeRows: true,
loadMask: true,
plugins: filters,
autoResize: true,
autoScroll: true,
clicksToEdit: 1,
columnLines: true,

//plugins: [Ext.ux.grid.DataDrop],

bodyCfg: {
cls: 'x-panel-body x-panel-body-with-bbar'
}
});

Passport.Substrate = Ext.data.Record.create( [
{ name: 'substrate_id', type: 'int', allowBlank :false},
{ name: 'substrate_name', type: 'string', allowBlank :false},
{ name: 'comments', type: 'string' },
{ name: 'version', type: 'int' },
{ name: 'history', type: 'string' }
]);


var cmSubstrates = new Ext.grid.ColumnModel( [
{
header: 'Id',
width: 35,
fixed:true,
align: 'center',
menuDisabled:true,
sortable: true,
groupable: false,
editable: false,
id: 'numberID',
dataIndex: 'substrate_id',
editor: new Ext.form.NumberField( {
allowNegative: false,
allowBlank: false,
lazyRender: true
})

}, {
header: "Substrate Name",
sortable: false,
groupable: false,
width: 300,
id: 'substrates_name',
dataIndex: 'substrate_name',
editor: new Ext.form.TextField( {
allowBlank: false,
lazyRender: true
})

}, {
header: "Version",
sortable: false,
groupable: false,
menuDisabled:true,
editable: false,
width: 50,
fixed:true,
align: 'center',
id: 'substrates_version',
dataIndex: 'version'

}, {
header: "Comments",
sortable: false,
groupable: false,
width: 460,
id: 'substrates_comments',
dataIndex: 'comments',
editor: new Ext.form.HtmlEditor( {
height: 250,
enableFonts: true,
enableLists: false,
enableLinks: true,
enableAlignments: true,
enableColors: true,
allowBlank: true,
lazyRender: true
})

}
]);


Passport.spreadsheet_store = new Ext.data.GroupingStore( {
storeId: 'Passport.spreadsheet_store',
remoteGroup: true,
reader: new Ext.data.JsonReader( {
root: 'results',
idProperty: 'substrate_id',
totalProperty: 'number_records'
}, Passport.Substrate),
proxy: new Ext.data.HttpProxy({url:'php/jsoner/substrates.php'})
});


// save function, called from button in toolbar
function saveSubstrates() {
var modifiedRecords = Passport.spreadsheet_store.getModifiedRecords();
for (var n = 0;n < modifiedRecords.length;n++) {
//Ajax call for each modifiedRecords[n]
}
}


The data is very straight forward, just a spreadsheet with 5 columns, one for each of the fields defined in the Record

Thanks :)

Animal
6 Oct 2009, 9:38 PM
=D> =D> Woww look great!

Works nicely, but I'm getting an error message (just added plugins: [Ext.ux.grid.DataDrop] in the grid config)

Uncaught TypeError: Cannot read property '0' of null at ext-base-debug.js:3482


The data does appear in the grid, but the data isn't sent to the server (added newRec.markDirty(); in function dataDropped() before adding to the store. The dirty marks do appear as well, but data is still not sent (getting data to be sent using getModifiedRecords) =/

Set it to break on all errors, then see what it's doing there.

genio
27 Jan 2010, 3:38 AM
Hi guys,

I am seeing some strange behavious with the plugin (which is great by the way)

If I combine it with row editor, once I open up the editor I am unable to select another cell and the caret seems to dissapear to the top cornet of the grid.

So to reproduce this is what I am doing

- Double Click on cell to open Editor
- Cell is selected for edit as expected
- Move to different cell in the row and selection/focus does not respond
- I notice a sliglitly visible caret at the top left corner of the grid
- I am now unable to select any cell anymore... :(

Removing the DragDrop plugin will make IE behave as expected with RowEditor

This is only happening in IE, Firfox behaves as expected with BOTH PLUGINS and the ability to move between cells when the RowEdit is opened.

Any clues why this is happening? Is it the big layer in drag drop taht makes IE mess up?

Let me know

Animal
27 Jan 2010, 10:38 PM
I suspect some work will have to be done to hide the masking div on edit start and show it again on edit end.

genio
28 Jan 2010, 2:07 AM
does DragDrop have access to the grid itself to check this? Was wondering how difficult it is to patch... but only IE has this, Firefox behaves...

genio
18 Feb 2010, 2:54 AM
I have noticed a bug with this plugin!

When the textarea is generate on top of the grid, it actually covers and disables the scroll bars...

I have added the size of the scroll bar to the resize function; which fixes it fixes it. ~o)



Ext.ns('Ext.ux.grid');
/**
* @author Shea Frederick - http://www.vinylfox.com
* @contributor Nigel (Animal) White, Andrea Giammarchi & Florian Cargoet
* @class Ext.ux.grid.DataDrop
* @singleton
* <p>A plugin that allows data to be dragged into a grid from spreadsheet applications (tabular data).</p>
* <p>Requires the Override.js file which adds mouse event forwarding capability to ExtJS</p>
* <p>Sample Usage</p>
* <pre><code>
{
xtype: 'grid',
...,
plugins: [Ext.ux.grid.DataDrop],
...
}
* </code></pre>
*/
Ext.ux.grid.DataDrop = (function () {

var lineEndRE = /\r\n|\r|\n/,
sepRe = /\s*\t\s*/;

// After the GridView has been rendered, insert a static transparent textarea over it.


function onViewRender() {
var v = this.view;
if (v.mainBody) {
this.textEl = Ext.DomHelper.insertAfter(v.scroller, {
tag: 'textarea',
id: Ext.id(),
value: '',
style: {
'font-size': '1px',
border: '0px none',
overflow: 'hidden',
color: '#fff',
position: 'absolute',
top: v.mainHd.getHeight() + 'px',
left: '0px',
'background-color': '#fff',
margin: 0,
cursor: 'default'
}
},
true);
this.textEl.setOpacity(0.1);
this.textEl.forwardMouseEvents();
this.textEl.on({
mouseover: function () {
Ext.TaskMgr.start(this.changeValueTask);
},
mouseout: function () {
Ext.TaskMgr.stop(this.changeValueTask);
},
scope: this
});
resizeDropArea.call(this);
}
}

// on GridPanel resize, keep scroller height correct to accomodate textarea.


function resizeDropArea() {
if (this.textEl) {
var v = this.view,
sc = v.scroller,
scs = sc.getSize,
s = {
width: sc.dom.clientWidth - v.getScrollOffset() + 2 || (scs.width - v.getScrollOffset() + 2),
height: sc.dom.clientHeight - v.getScrollOffset() + 2 || scs.height
};
this.textEl.setSize(s);
}
}

// on change of data in textarea, create a Record from the tab-delimited contents.


function dataDropped(e, el) {
var nv = el.value;
el.blur();
if (nv !== '') {
var store = this.getStore(),
Record = store.recordType;
el.value = '';
var rows = nv.split(lineEndRE),
cols = this.getColumnModel().getColumnsBy(function (c) {
return !c.hidden;
}),
fields = Record.prototype.fields;
if (cols.length && rows.length) {
for (var i = 0; i < rows.length; i++) {
var vals = rows[i].split(sepRe),
data = {};
if (vals.join('').replace(' ', '') !== '') {
for (var k = 0; k < vals.length && k < fields.keys.length; k++) {
// var fldName = cols[k].dataIndex;
// Change sfunction to support ALL columns rather then just visible ones
var fldName = fields.keys[k];
var fld = fields.item(fldName);
data[fldName] = fld ? fld.convert(vals[k]) : vals[k];
}
var newRec = new Record(data);
newRec.markDirty();
store.add(newRec);
var idx = store.indexOf(newRec);
this.view.focusRow(idx);
Ext.get(this.view.getRow(idx)).highlight();
}
}
resizeDropArea.call(this);
}
}
}

return {
init: function (cmp) {
Ext.apply(cmp, {
changeValueTask: {
run: function () {
dataDropped.call(this, null, this.textEl.dom);
},
interval: 100,
scope: cmp
},
onResize: cmp.onResize.createSequence(resizeDropArea)
});
cmp.getView().afterRender = cmp.getView().afterRender.createSequence(onViewRender, cmp);
}
};
})();

mnask79
23 Feb 2010, 12:22 AM
its really great job =D>

gillou01
23 Feb 2010, 5:15 AM
Hi Guys
I m trying to forward also the contextmenu event to my underlying grid.
So i have added the event in Animal's override :


forwardMouseEvents: function(evt) {
var me = this,
xy, t, lastT,
evts = [ 'mousemove', 'mousedown', 'mouseup', 'dblclick', 'mousewheel','contextmenu' ];


So the event gets forwarded, but it also triggers the browser context menu to be displayed.
Anybody know how to prevent that?

Cheers

Animal
23 Feb 2010, 5:26 AM
You have to stop the event (underlying method on the browser event is "preventDefault").

gillou01
23 Feb 2010, 9:32 AM
Thanks!!

loiane
4 Mar 2010, 9:33 AM
Congrats for the great work you guys did on this plugin. I'm a huge fan already!

scblue
4 Mar 2010, 11:22 PM
I have a simple form with xtype grid to test this plugin.
However, I can't manage to drop the data onto the grid.




/*!
* Ext JS Library 3.1.1
* Copyright(c) 2006-2010 Ext JS, LLC
* licensing@extjs.com
* http://www.extjs.com/license
*/
Ext.onReady(function(){

Ext.QuickTips.init();

var data = [
['abc'],
['def'],
['ghi']
];

teststore = new Ext.data.SimpleStore({
fields: [
{name: 'a'}
]
});

teststore.loadData(data);

var simple = new Ext.FormPanel({
labelWidth: 75, // label settings here cascade unless overridden
url:'save-form.php',
frame:true,
title: 'Csv Form',
bodyStyle:'padding:5px 5px 0',
height: 300,
width: 350,
//defaults: {width: 230},
//defaultType: 'textfield',
items: [{
xtype: 'grid',
height: 300,
plugins: [Ext.ux.grid.DataDrop],
editable: true,
store: teststore,
columns: [
{ id: 'a', header: 'A', sortable: true, dataIndex: 'a'}
//{ id: 'b', header: 'B', sortable: true },
//{ id: 'c', header: 'C', sortable: true }
]
}],

buttons: [{
text: 'Save'
},{
text: 'Cancel'
}]
});

simple.render(document.body);

});
Is there something that I am missing?
There are no errors on firebug, the data's just not dropping.

Thanks!

VinylFox
5 Mar 2010, 4:48 AM
Have you included the Override.js file as well?

issameddine
14 Apr 2010, 1:56 AM
HEllo, great job
I have one question, can I use it with Ext2.x
Thanks

issameddine
14 Apr 2010, 2:34 AM
\:D/ I resolved the problem.
I added this snippet to define "Ext.isFunction"


Ext.isFunction = function(fn){
return (typeof fn == 'function');
};

the problem now, it when the number of columns selected in the file is greater than those of the grid. why they should be equal.
Thanks

hallikpapa
14 May 2010, 7:42 PM
Will this work in a window? I am trying to drag to a test grid I put in a window, and it only seems to hit the override class when I drop in a specific spot, but then I get a lastT is undefined.



me.hide();
t = Ext.get(document.elementFromPoint(x, y));
me.show();
if (!t) {
lastT.fireEvent('mouseout'); ///UNDEFINED HERE


I am guessing cause t is undefined, where it can't get the window element from the x/y points? But again it's a guess. I am going to do more testing to try and see what's going on. I have only been able to hit a breakpoint twice, every other time I drag into the grid, it forwards to google doing a search with the highlighted excel contents.

<edit> Yes, I tested successfully with a grid rendered to the document body, but when trying to drop on the same grid in a Ext.Window, it doesn't capture the text, it pastes whatever text I am copying into the url bar and does a google search for that text...Weird, because from what I read about document.elementFromPoint on your blog, it should be detecting the window...I will keep looking.

<edit2> I maximized the window, and did a drop, and it worked great! I will try and figure out how it was missing my drop even though I was doing it in the center of the grid. This is the greatest plugin. Impressive work guys.

michael melsen
29 Sep 2010, 1:22 AM
Hi VinylFox,

great plugin! Thanks for it.

I'm trying to embed it in my grid and it works great. However I'm trying to add events to it so I can listen when the data is dropped so I can add a modal window that shows the differences between the original records in the store and the possibly different records from the excel file.

As the plugin is seen as an object that does not extend observable or anything else, I can't listen for events on it. Do you have an idea about how to extend the datadrop plugin in order to be notified when the data is dropped to perform popup a modal window?

kind regards,

Michael

imran
14 Dec 2010, 8:27 AM
Cool plugin!

BTW, when dropping a large number of rows I noticed that each Record was being added, focused upon, then highlighted - becoming uber slow, esp when used with BufferView.

As an improvement, I slightly modified the dataDropped function to add an array of Records to the store, outside the for loop -vs- adding incrementally for each row:



// on change of data in textarea, create a Record from the tab-delimited contents.
function dataDropped(e, el){
var nv = el.value;
el.blur();
if (nv !== '') {
var store = this.getStore(), Record = store.recordType;
el.value = '';
var rows = nv.split(lineEndRE), cols = this.getColumnModel().getColumnsBy(function(c){
return !c.hidden;
}), fields = Record.prototype.fields;
if (cols.length && rows.length) {
var recs = new Array();
for (var i = 0; i < rows.length; i++) {
var vals = rows[i].split(sepRe), data = {};
if (vals.join('').replace(' ', '') !== '') {
for (var k = 0; k < vals.length; k++) {
var fldName = cols[k].dataIndex;
var fld = fields.item(fldName);
data[fldName] = fld ? fld.convert(vals[k]) : vals[k];
}
var newRec = new Record(data);
recs.push(newRec);
}
}

store.add(recs);
var idx = store.data.length-1;
this.view.focusRow(idx);
Ext.get(this.view.getRow(idx)).highlight();

resizeDropArea.call(this);
}
}
}


- Imran

imran
15 Dec 2010, 8:31 AM
This fix should definitely make its way into the Google Code repo. I encountered the same problem


I have noticed a bug with this plugin!

When the textarea is generate on top of the grid, it actually covers and disables the scroll bars...

I have added the size of the scroll bar to the resize function; which fixes it fixes it. ~o)



Ext.ns('Ext.ux.grid');
/**
* @author Shea Frederick - http://www.vinylfox.com
* @contributor Nigel (Animal) White, Andrea Giammarchi & Florian Cargoet
* @class Ext.ux.grid.DataDrop
* @singleton
* <p>A plugin that allows data to be dragged into a grid from spreadsheet applications (tabular data).</p>
* <p>Requires the Override.js file which adds mouse event forwarding capability to ExtJS</p>
* <p>Sample Usage</p>
* <pre><code>
{
xtype: 'grid',
...,
plugins: [Ext.ux.grid.DataDrop],
...
}
* </code></pre>
*/
Ext.ux.grid.DataDrop = (function () {

var lineEndRE = /\r\n|\r|\n/,
sepRe = /\s*\t\s*/;

// After the GridView has been rendered, insert a static transparent textarea over it.


function onViewRender() {
var v = this.view;
if (v.mainBody) {
this.textEl = Ext.DomHelper.insertAfter(v.scroller, {
tag: 'textarea',
id: Ext.id(),
value: '',
style: {
'font-size': '1px',
border: '0px none',
overflow: 'hidden',
color: '#fff',
position: 'absolute',
top: v.mainHd.getHeight() + 'px',
left: '0px',
'background-color': '#fff',
margin: 0,
cursor: 'default'
}
},
true);
this.textEl.setOpacity(0.1);
this.textEl.forwardMouseEvents();
this.textEl.on({
mouseover: function () {
Ext.TaskMgr.start(this.changeValueTask);
},
mouseout: function () {
Ext.TaskMgr.stop(this.changeValueTask);
},
scope: this
});
resizeDropArea.call(this);
}
}

// on GridPanel resize, keep scroller height correct to accomodate textarea.


function resizeDropArea() {
if (this.textEl) {
var v = this.view,
sc = v.scroller,
scs = sc.getSize,
s = {
width: sc.dom.clientWidth - v.getScrollOffset() + 2 || (scs.width - v.getScrollOffset() + 2),
height: sc.dom.clientHeight - v.getScrollOffset() + 2 || scs.height
};
this.textEl.setSize(s);
}
}

// on change of data in textarea, create a Record from the tab-delimited contents.


function dataDropped(e, el) {
var nv = el.value;
el.blur();
if (nv !== '') {
var store = this.getStore(),
Record = store.recordType;
el.value = '';
var rows = nv.split(lineEndRE),
cols = this.getColumnModel().getColumnsBy(function (c) {
return !c.hidden;
}),
fields = Record.prototype.fields;
if (cols.length && rows.length) {
for (var i = 0; i < rows.length; i++) {
var vals = rows[i].split(sepRe),
data = {};
if (vals.join('').replace(' ', '') !== '') {
for (var k = 0; k < vals.length && k < fields.keys.length; k++) {
// var fldName = cols[k].dataIndex;
// Change sfunction to support ALL columns rather then just visible ones
var fldName = fields.keys[k];
var fld = fields.item(fldName);
data[fldName] = fld ? fld.convert(vals[k]) : vals[k];
}
var newRec = new Record(data);
newRec.markDirty();
store.add(newRec);
var idx = store.indexOf(newRec);
this.view.focusRow(idx);
Ext.get(this.view.getRow(idx)).highlight();
}
}
resizeDropArea.call(this);
}
}
}

return {
init: function (cmp) {
Ext.apply(cmp, {
changeValueTask: {
run: function () {
dataDropped.call(this, null, this.textEl.dom);
},
interval: 100,
scope: cmp
},
onResize: cmp.onResize.createSequence(resizeDropArea)
});
cmp.getView().afterRender = cmp.getView().afterRender.createSequence(onViewRender, cmp);
}
};
})();

VinylFox
31 Dec 2010, 7:01 AM
This fix should definitely make its way into the Google Code repo. I encountered the same problem

I am not experiencing the same problem as you and genio. Please provide more information, such as what version of ExtJS you are using and a test case.

VinylFox
31 Dec 2010, 8:43 AM
I have implemented the suggested changes by imran and michael melsen.

https://github.com/VinylFox/ExtJS.ux.DataDrop/commit/9ae1a1fab05feee419a421f234cf13bd3baf3776

@imran - There is now a setting for addBulk, which does what you suggested.

@michael melsen - I added three events to the grid that the plugin is initialized on, for beforedatadrop, datadrop and afterdatadrop. The beforedatadrop event can return false to cancel the processing of the dropped data.

imran
31 Dec 2010, 10:32 AM
I am not experiencing the same problem as you and genio. Please provide more information, such as what version of ExtJS you are using and a test case.

I am using version 3.3.1 and had seen the issue in IE8 only. It would, however, work after an event (expand/collapse etc.) would trigger a doLayout, but otherwise the scrollBar was not clickable - although visible. I'll look to create a simple example to illustrate this.

imran
31 Dec 2010, 10:32 AM
I have implemented the suggested changes by imran and michael melsen.

https://github.com/VinylFox/ExtJS.ux.DataDrop/commit/9ae1a1fab05feee419a421f234cf13bd3baf3776

@imran - There is now a setting for addBulk, which does what you suggested.

@michael melsen - I added three events to the grid that the plugin is initialized on, for beforedatadrop, datadrop and afterdatadrop. The beforedatadrop event can return false to cancel the processing of the dropped data.

Very cool, I'll give it a go

Thanks!
Imran

imran
3 Feb 2011, 1:33 PM
Hi Shea,

I made some updates to make DataDrop a bit more configurable. I had a requirement where, say I dragged a 2 column spreadsheet onto the grid, but it was to be pasted in my GridPanel's columns 1 and 5.

I added an *optional* dataDropPluginCfg property obj for this, which accepts addBulk, highlightNewRows, and an xlsColMapper:

Usage (grid config snippet):


colModel: new Ext.grid.ColumnModel([
{header:"&nbsp;", width:35, dataIndex:'rowNum', sortable:false, renderer:this.rowNumRenderer}
,{header:"User", dataIndex:'userId', sortable:false, editor:new Ext.form.TextField()}
,{header:"Age", dataIndex:'age', sortable:false, editor:new Ext.form.NumberField({allowNegative:false,allowDecimals:false})}
])
,dataDropPluginCfg:{addBulk:true, highlightNewRows:true, xlsColMapper:["userId","age"]}
,plugins: [Ext.ux.grid.DataDrop]



DataDrop.js


Ext.ns('Ext.ux.grid');
/**
* @author Shea Frederick - http://www.vinylfox.com
* @contributor Nigel (Animal) White, Andrea Giammarchi & Florian Cargoet
* @class Ext.ux.grid.DataDrop
* @singleton
* <p>A plugin that allows data to be dragged into a grid from spreadsheet applications (tabular data).</p>
* <p>Requires the Override.js file which adds mouse event forwarding capability to ExtJS</p>
* <p>Sample Usage</p>
* <pre><code>
{
xtype: 'grid',
...,
plugins: [Ext.ux.grid.DataDrop],
...
}
* </code></pre>
*/
Ext.ux.grid.DataDrop = (function(){

var lineEndRE = /\r\n|\r|\n/,
sepRe = /\s*\t\s*/;

// After the GridView has been rendered, insert a static transparent textarea over it.
function onViewRender(){
var v = this.view;
if (v.mainBody) {
this.textEl = Ext.DomHelper.insertAfter(v.scroller, {
tag: 'textarea',
id: Ext.id(),
value: '',
style: {
'font-size': '1px',
border: '0px none',
overflow: 'hidden',
color: '#fff',
position: 'absolute',
top: v.mainHd.getHeight() + 'px',
left: '0px',
'background-color': '#fff',
margin: 0,
cursor: 'default'
}
}, true);
this.textEl.setOpacity(0.1);
this.textEl.forwardMouseEvents();
this.textEl.on({
mouseover: function(){
Ext.TaskMgr.start(this.changeValueTask);
},
mouseout: function(){
Ext.TaskMgr.stop(this.changeValueTask);
},
scope: this
});
resizeDropArea.call(this);
}
}

// on GridPanel resize, keep scroller height correct to accomodate textarea.
function resizeDropArea(){
if (this.textEl) {
var v = this.view,
sc = v.scroller,
scs = sc.getSize,
s = {
width: sc.dom.clientWidth - v.getScrollOffset() + 2 || (scs.width - v.getScrollOffset() + 2),
height: sc.dom.clientHeight - v.getScrollOffset() + 2 || scs.height
};
this.textEl.setSize(s);
}
}

// on change of data in textarea, create a Record from the tab-delimited contents.
function dataDropped(e, el){
var nv = el.value;
el.blur();
if (nv !== '') {
if (this.fireEvent('beforedatadrop',this,nv,el)){
var store = this.getStore(), Record = store.recordType;
el.value = '';
var rows = nv.split(lineEndRE), cols = this.getColumnModel().getColumnsBy(function(c){
return !c.hidden;
}), fields = Record.prototype.fields, recs = [];
this.fireEvent('datadrop',this,rows);
if (cols.length && rows.length) {
for (var i = 0; i < rows.length; i++) {
var vals = rows[i].split(sepRe), data = {};
if (vals.join('').replace(' ', '') !== '') {
for (var k = 0; k < vals.length; k++) {
var fldName = '';
if(!this.dataDropPluginCfg.xlsColMapper) {
fldName = cols[k].dataIndex;
}
else {
fldName = this.dataDropPluginCfg.xlsColMapper[k];
}

if(!Ext.isEmpty(fldName)) {
var fld = fields.item(fldName);
data[fldName] = fld ? fld.convert(vals[k]) : vals[k];
}
}

if(!Ext.isEmpty(data)) {
var newRec = new Record(data);
recs.push(newRec);
if (!this.dataDropPluginCfg.addBulk){
store.add(newRec);
if (this.dataDropPluginCfg.highlightNewRows){
var idx = store.indexOf(newRec);
this.view.focusRow(idx);
Ext.get(this.view.getRow(idx)).highlight();
}
}
}
}
}

if (this.dataDropPluginCfg.addBulk && recs && recs.length){
store.add(recs);
if (this.dataDropPluginCfg.highlightNewRows){
var idx = store.data.length-1;
this.view.focusRow(idx);
Ext.get(this.view.getRow(idx)).highlight();
}
}
this.fireEvent('afterdatadrop',this,recs);
resizeDropArea.call(this);
}
}else{
el.value = '';
}
}
}

return {
init: function(cmp){
cmp.addEvents({
'beforedatadrop': true,
'datadrop': true,
'afterdatadrop': true
});

cmp.dataDropPluginCfg = Ext.apply({addBulk:true,highlightNewRows:true}, cmp.dataDropPluginCfg);

Ext.apply(cmp, {
changeValueTask: {
run: function(){
dataDropped.call(this, null, this.textEl.dom);
},
interval: 100,
scope: cmp
},
onResize: cmp.onResize.createSequence(resizeDropArea)
});
cmp.getView().afterRender = cmp.getView().afterRender.createSequence(onViewRender, cmp);
}
};
})();

/**
* @cfg dataDropPluginCfg config object with following properties:
* addBulk: boolean, highlightNewRows: boolean, xlsColMapper: Array of dataIndex keys to correspond to excel column index.
*/

Robert82
6 Mar 2011, 1:45 PM
Great plugin =D>

Could I use this approach for a ext.panel?
If it possible, should I also use a textarea?

Regards,
Robert

ozlemsimsek
29 Jun 2012, 6:15 AM
Is there a way to use this plugin in GXT?
or is there a gwt version?
I want to copy data from excel spreadsheet and paste into grid by ext gwt.
Thanks
Ozlem

devlev01
12 Nov 2012, 4:15 AM
Hello,

I successfully drop and drag to datagrid (ext 3.4.0). But i couldn't save datagrid.

My working code like this (Not work after dragging)



handler: function () {


var arr = Grid.gridSummarize.store.getModifiedRecords();


var str = '[';


for (var i = 0; i < arr.length; i++) {
if (arr[i].data.ID == -1) {
str += Ext.util.JSON.encode(arr[i].data) + ',';
}
}


str = str.substring(0, str.length - 1);
str += ']';

frankbolviken
27 Dec 2012, 1:57 AM
I've been trying out this plugin on 4.1.3, and I can't get it to work properly.
When trying to drag rows into the grid, I get this message:

I've added the MouseEventForwarding.js override file, but is there something else I ahve to do to get this override registered, or should this happen automatically? (probably a newbie question).

Frank

frank.bolviken
28 Dec 2012, 4:38 AM
Okay, i got the plugin working.
I have another question though... have you considering also the possibilities of pasting? Like if you don't want row 1 to 5, you want row 1,3,5. To achieve this, you have to select the rows, and copy.
So the possibility to paste it in would be cool.

Frank B

Joyfulbob
18 Mar 2013, 9:25 AM
This is a dumb question, and I'll probably go, Duh!" when I read the reply, but how do you get Excel to allow dragging of rows?

When I selected some rows and clicked on one to drag, Excel de-selected the area and selected the row I clicked. CTRL+, SHIFT+, and ALT+ did not work.

Thanks in advance!

frankbolviken
18 Mar 2013, 9:31 AM
This is why I love excel :P
You have to click and hold on the edge of the selection (the dotted line), if you don't hit that one you will loose your selection :P

Frank

Joyfulbob
18 Mar 2013, 9:44 AM
Thanks, Frank!

At least I don't feel quite so dumb! ;)

Joyfulbob
19 Mar 2013, 6:35 AM
I got it working and it is an awesome extension! Thanks!

A question though, if you have a blank Excel cell it doesn't import that blank cell; it moves all cells to the right of the blank one to the blank grid column. Shouldn't it allow blank cells to keep each Excel cell in it's corresponding grid column?

Thanks again!