Closes #295, Dragging an independent file/note over an item should turn the file/note into a child item

Overhaul of the item drag and drop functionality, allowing dragging notes and attachments into and out of other items and addressing all the related issues that arise when that's possible.

Should also be generally smarter about deciding what can be dragged and dropped where and in what modes.

Let me know if something doesn't work as you expect.
This commit is contained in:
Dan Stillman 2006-09-29 20:35:19 +00:00
parent 4fcddf42ec
commit 7fed86b389
3 changed files with 271 additions and 28 deletions

View File

@ -473,10 +473,10 @@ Scholar.CollectionTreeView.prototype.canDrop = function(row, orient)
nsDragAndDrop.mDragSession = nsDragAndDrop.mDragService.getCurrentSession();
return false;
}
var data = dataSet.first.first;
var dataType = data.flavour.contentType;
//Highlight the rows correctly on drag:
if(orient == 1 && row == 0 && dataType == 'scholar/collection') //for dropping collections into root level
{
@ -487,7 +487,24 @@ Scholar.CollectionTreeView.prototype.canDrop = function(row, orient)
var rowCollection = this._getItemAtRow(row).ref; //the collection we are dragging over
if(dataType == 'scholar/item' || dataType == "text/x-moz-url")
return true; //items can be dropped on anything
{
var ids = data.data.split(',');
for each(var id in ids)
{
var item = Scholar.Items.get(id);
// Can only drag top-level items into collections
if (item.isRegularItem() || !item.getSource())
{
// Make sure there's at least one item that's not already
// in this collection
if (!rowCollection.hasItem(id))
{
return true;
}
}
}
return false;
}
else if(dataType='scholar/collection' && data.data != rowCollection.getID() && !Scholar.Collections.get(data.data).hasDescendent('collection',rowCollection.getID()) )
return true; //collections cannot be dropped on themselves, nor in their children
}
@ -527,8 +544,15 @@ Scholar.CollectionTreeView.prototype.drop = function(row, orient)
{
var ids = data.data.split(',');
var targetCollection = this._getItemAtRow(row).ref;
for(var i = 0; i<ids.length; i++)
targetCollection.addItem(ids[i]);
for each(var id in ids)
{
var item = Scholar.Items.get(id);
// Only accept top-level items
if (item.isRegularItem() || !item.getSource())
{
targetCollection.addItem(id);
}
}
}
else if(dataType == 'text/x-moz-url' && this.canDrop(row, orient))
{

View File

@ -927,9 +927,7 @@ Scholar.Item.prototype.setSource = function(sourceItemID){
throw ("Cannot set " + type + " source to invalid item " + sourceItemID);
}
// Get previous source item id
var sql = "SELECT sourceItemID FROM item" + Type + "s WHERE item=" + this.getID();
var oldSourceItemID = Scholar.DB.valueQuery(sql);
var oldSourceItemID = this.getSource();
if (oldSourceItemID==sourceItemID){
Scholar.debug(Type + " source hasn't changed", 4);
@ -943,6 +941,24 @@ Scholar.Item.prototype.setSource = function(sourceItemID){
+ "didn't exist in setSource()", 2);
}
// If this was an independent item, remove from any collections where it
// existed previously and add source instead if there is one
if (!oldSourceItemID){
var sql = "SELECT collectionID FROM collectionItems WHERE itemID=?";
var changedCollections = Scholar.DB.columnQuery(sql, this.getID());
if (changedCollections){
if (sourceItemID){
var sql = "UPDATE OR REPLACE collectionItems "
+ "SET itemID=? WHERE itemID=?";
Scholar.DB.query(sql, [sourceItemID, this.getID()]);
}
else {
var sql = "DELETE FROM collectionItems WHERE itemID=?";
Scholar.DB.query(sql, this.getID());
}
}
}
var sql = "UPDATE item" + Type + "s SET sourceItemID=? WHERE itemID=?";
var bindParams = [sourceItemID ? {int:sourceItemID} : null, this.getID()];
Scholar.DB.query(sql, bindParams);

View File

@ -127,28 +127,45 @@ Scholar.ItemTreeView.prototype.notify = function(action, type, ids)
for(var i=0, len=ids.length; i<len; i++)
{
var row = this._itemRowMap[ids[i]];
// Item already exists in this view
if( row != null)
{
if(this.isContainer(row) && this.isContainerOpen(row))
if (this.isContainer(row) && this.isContainerOpen(row))
{
this.toggleOpenState(row);
this.toggleOpenState(row);
}
else if(this.getParentIndex(row))
// If item moved from top-level to under another item,
// remove the old row
else if (!this.isContainer(row) && this.getParentIndex(row)==-1
&& this._getItemAtRow(row).ref.getSource())
{
Scholar.debug('row is here2');
this._hideItem(row);
this._treebox.rowCountChanged(row+1, -1)
}
// If
else if (!this.isContainer(row) && this.getParentIndex(row)!=-1
&& !this._getItemAtRow(row).ref.getSource())
{
var item = Scholar.Items.get(ids[i]);
this._showItem(new Scholar.ItemTreeView.TreeRow(item, 0, false), this.rowCount);
this._treebox.rowCountChanged(this.rowCount-1, 1);
}
else
{
Scholar.debug('row is here3');
this._treebox.invalidateRow(row);
}
madeChanges = true;
}
else if(this._itemGroup.isLibrary() || this._itemGroup.ref.hasItem(ids[i]))
//else if(this._itemGroup.isLibrary() || this._itemGroup.ref.hasItem(ids[i]))
else
{
var item = Scholar.Items.get(ids[i]);
if(!item.getSource())
if(item.isRegularItem() || !item.getSource())
{
//most likely, the note or attachment's parent was removed.
this._showItem(new Scholar.ItemTreeView.TreeRow(item,0,false),this.rowCount);
@ -175,9 +192,12 @@ Scholar.ItemTreeView.prototype.notify = function(action, type, ids)
for (var i in items)
{
if((this._itemGroup.isLibrary() || items[i].inCollection(this._itemGroup.ref.getID())) // if the item belongs in this collection
&& this._itemRowMap[items[i].getID()] == null // if we haven't already added it to our hash map
&& (items[i].isRegularItem() || !items[i].getSource())) // if it's stand-alone
// if the item belongs in this collection
if((this._itemGroup.isLibrary() || items[i].inCollection(this._itemGroup.ref.getID()))
// if we haven't already added it to our hash map
&& this._itemRowMap[items[i].getID()] == null
// Regular item or standalone note/attachment
&& (items[i].isRegularItem() || !items[i].getSource()))
{
this._showItem(new Scholar.ItemTreeView.TreeRow(items[i],0,false),this.rowCount);
this._treebox.rowCountChanged(this.rowCount-1,1);
@ -206,7 +226,8 @@ Scholar.ItemTreeView.prototype.notify = function(action, type, ids)
this.sort(); //this also refreshes the hash map
this._treebox.invalidate();
}
else if(action != 'modify') //no need to update this if we modified
//else if(action != 'modify') //no need to update this if we modified
else //no need to update this if we modified
{
this._refreshHashMap();
}
@ -326,8 +347,13 @@ Scholar.ItemTreeView.prototype.getLevel = function(row)
return this._getItemAtRow(row).level;
}
// Gets the index of the row's container, or -1 if none (container itself or top-level)
Scholar.ItemTreeView.prototype.getParentIndex = function(row)
{
if (row==-1)
{
return -1;
}
var thisLevel = this.getLevel(row);
if(thisLevel == 0) return -1;
for(var i = row - 1; i >= 0; i--)
@ -639,7 +665,7 @@ Scholar.ItemTreeView.prototype._refreshHashMap = function()
*/
Scholar.ItemTreeView.prototype.saveSelection = function()
{
savedSelection = new Array();
var savedSelection = new Array();
var start = new Object();
var end = new Object();
@ -713,7 +739,7 @@ Scholar.ItemTreeCommandController.prototype.onEvent = function(evt)
Scholar.ItemTreeView.prototype.onDragStart = function (evt,transferData,action)
{
transferData.data=new TransferData();
transferData.data.addDataForFlavour("scholar/item",this.saveSelection());
transferData.data.addDataForFlavour("scholar/item", this.saveSelection());
}
/*
@ -727,20 +753,192 @@ Scholar.ItemTreeView.prototype.getSupportedFlavours = function ()
return flavors;
}
/*
* Called by nsDragAndDrop.js for any sort of drop on the tree
*/
Scholar.ItemTreeView.prototype.onDrop = function (evt,data,session)
Scholar.ItemTreeView.prototype.canDrop = function(row, orient)
{
try
{
var dataSet = nsTransferable.get(this.getSupportedFlavours(),
nsDragAndDrop.getDragData, true);
}
catch (e)
{
// A work around a limitation in nsDragAndDrop.js -- the mDragSession
// is not set until the drag moves over another control.
// (This will only happen if the first drag is from the item list.)
nsDragAndDrop.mDragSession = nsDragAndDrop.mDragService.getCurrentSession();
return false;
}
var data = dataSet.first.first;
var dataType = data.flavour.contentType;
var ids = data.data.split(','); // ids of rows we are dragging in
if (row==-1 && orient==-1)
{
return true;
}
// workaround... two different services call canDrop
// (nsDragAndDrop, and the tree) -- this is for the former,
// used when dragging between windows
if (typeof row == 'object')
{
// If drag to different window
if (nsDragAndDrop.mDragSession.sourceNode!=row.target)
{
// Check if at least one item (or parent item for children) doesn't
// already exist in target
for each(var id in ids)
{
var item = Scholar.Items.get(id);
// Skip non-top-level items
if (!item.isRegularItem() && item.getSource())
{
continue;
}
// DISABLED: move parent on child drag
//var source = item.isRegularItem() ? false : item.getSource();
//if (!this._itemGroup.ref.hasItem(source ? source : id))
if (!this._itemGroup.ref.hasItem(id))
{
return true;
}
}
}
return false;
}
//Scholar.debug('row is ' + row);
//Scholar.debug('orient is ' + orient);
// Highlight the rows correctly on drag
var rowItem = this._getItemAtRow(row).ref; //the item we are dragging over
if (dataType == 'scholar/item')
{
// Directly on a row
if (orient == 0)
{
for each(var id in ids)
{
var item = Scholar.Items.get(id);
// Only allow dragging of notes and attachments
// that aren't already children of the item
if (!item.isRegularItem() && item.getSource()!=rowItem.getID())
{
return true;
}
}
}
// In library, allow children to be dragged out of parent
else if (this._itemGroup.isLibrary())
{
for each(var id in ids)
{
// Don't allow drag if any top-level items
var item = Scholar.Items.get(id);
if (item.isRegularItem() || !item.getSource())
{
return false;
}
}
return true;
}
return false;
}
/*
else if (dataType == "text/x-moz-url")
{
return true;
}
*/
return false;
}
/*
* Called when something's been dropped on or next to a row
*/
Scholar.ItemTreeView.prototype.drop = function(row, orient)
{
try
{
var dataSet = nsTransferable.get(this.getSupportedFlavours(),
nsDragAndDrop.getDragData, true);
}
catch (e)
{
// A work around a limitation in nsDragAndDrop.js -- the mDragSession
// is not set until the drag moves over another control.
// (This will only happen if the first drag is from the item list.)
nsDragAndDrop.mDragSession = nsDragAndDrop.mDragService.getCurrentSession();
var dataSet = nsTransferable.get(this.getSupportedFlavours(),
nsDragAndDrop.getDragData, true);
}
var data = dataSet.first.first;
var dataType = data.flavour.contentType;
if(dataType == 'scholar/item')
if (dataType == 'scholar/item' && this.canDrop(row, orient))
{
var ids = data.data.split(',');
for(var i = 0; i<ids.length; i++)
this._itemGroup.ref.addItem(ids[i]);
var ids = data.data.split(','); // ids of rows we are dragging in
// Dropped directly on a row
if (orient == 0)
{
// If item was a top-level item and it exists in a collection,
// replace it in collections with the parent item
rowItem = this._getItemAtRow(row).ref; // the item we are dragging over
for each(var id in ids)
{
var item = Scholar.Items.get(id);
item.setSource(rowItem.getID());
}
}
// Dropped outside of a row
else
{
// Remove from parent and make top-level
if (this._itemGroup.isLibrary())
{
for each(var id in ids)
{
var item = Scholar.Items.get(id);
if (!item.isRegularItem())
{
item.setSource();
}
}
}
// Add to collection
else
{
for each(var id in ids)
{
var item = Scholar.Items.get(id);
var source = item.isRegularItem() ? false : item.getSource();
// Top-level item
if (!source)
{
this._itemGroup.ref.addItem(id);
}
// Non-top-level item - currently unused
else
{
// TODO: Prompt before moving source item to collection
this._itemGroup.ref.addItem(source);
}
}
}
}
}
else if(dataType == 'text/x-moz-url')
else if (dataType == 'text/x-moz-url' && this.canDrop(row, orient))
{
var url = data.data.split("\n")[0];
@ -748,11 +946,16 @@ Scholar.ItemTreeView.prototype.onDrop = function (evt,data,session)
var newItem = Scholar.Ingester.scrapeURL(url);
if(newItem)
this._itemGroup.ref.addItem(newItem.getID());
this._getItemAtRow(row).ref.addItem(newItem.getID());
*/
}
}
/*
* Called by nsDragAndDrop.js for any sort of drop on the tree
*/
Scholar.ItemTreeView.prototype.onDrop = function (evt,dropdata,session){ }
Scholar.ItemTreeView.prototype.onDragOver = function (evt,dropdata,session) { }
////////////////////////////////////////////////////////////////////////////////