www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | Submodules | README | LICENSE

commit e417d8e690b33be6cae789abd02df28abf42a4cb
parent f635ee7788f5fdff89a79d54f5f77c3c4d2be5c7
Author: David Norton <david@nortoncrew.com>
Date:   Thu, 15 Jun 2006 22:35:48 +0000

[interface] Although commented out, code in place to accept URL drags into collections (waiting on an Ingester.scrapeURL function)
[interface] Multi-notes functionality (waiting on data layer)
[docs] Major internal documentation written for itemTreeView.js and collectionTreeView.js (this actually does work ;-))

Diffstat:
Mchrome/chromeFiles/content/scholar/collectionTreeView.js | 129++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Mchrome/chromeFiles/content/scholar/itemPane.js | 125+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Mchrome/chromeFiles/content/scholar/itemPane.xul | 12++++++++++--
Mchrome/chromeFiles/content/scholar/itemTreeView.js | 110++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
4 files changed, 324 insertions(+), 52 deletions(-)

diff --git a/chrome/chromeFiles/content/scholar/collectionTreeView.js b/chrome/chromeFiles/content/scholar/collectionTreeView.js @@ -1,3 +1,14 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// CollectionTreeView +/// -- handles the link between an individual tree and the data layer +/// -- displays only collections, in a hierarchy (no items) +/// +//////////////////////////////////////////////////////////////////////////////// + +/* + * Constructor the the CollectionTreeView object + */ Scholar.CollectionTreeView = function() { this._treebox = null; @@ -6,6 +17,9 @@ Scholar.CollectionTreeView = function() this._unregisterID = Scholar.Notifier.registerColumnTree(this); } +/* + * Called by the tree itself + */ Scholar.CollectionTreeView.prototype.setTree = function(treebox) { if(this._treebox) @@ -13,6 +27,10 @@ Scholar.CollectionTreeView.prototype.setTree = function(treebox) this._treebox = treebox; } +/* + * Reload the rows from the data access methods + * (doesn't call the tree.invalidate methods, etc.) + */ Scholar.CollectionTreeView.prototype.refresh = function() { this._dataItems = new Array(); @@ -27,7 +45,7 @@ Scholar.CollectionTreeView.prototype.refresh = function() } /* - * Is called by Scholar.Notifier on any changes to the data layer + * Called by Scholar.Notifier on any changes to collections in the data layer */ Scholar.CollectionTreeView.prototype.notify = function(action, type, ids) { @@ -102,13 +120,20 @@ Scholar.CollectionTreeView.prototype.notify = function(action, type, ids) } /* - * Unregisters itself from Scholar.Notifier (called on window close) + * Unregisters view from Scholar.Notifier (called on window close) */ Scholar.CollectionTreeView.prototype.unregister = function() { Scholar.Notifier.unregisterColumnTree(this._unregisterID); } +//////////////////////////////////////////////////////////////////////////////// +/// +/// nsITreeView functions +/// http://www.xulplanet.com/references/xpcomref/ifaces/nsITreeView.html +/// +//////////////////////////////////////////////////////////////////////////////// + Scholar.CollectionTreeView.prototype.getCellText = function(row, column) { var obj = this._getItemAtRow(row); @@ -137,6 +162,8 @@ Scholar.CollectionTreeView.prototype.isContainerOpen = function(row) Scholar.CollectionTreeView.prototype.isContainerEmpty = function(row) { + //NOTE: this returns true if the collection has no child collections + var itemGroup = this._getItemAtRow(row); if(itemGroup.isCollection()) return !itemGroup.ref.hasChildCollections(); @@ -170,6 +197,9 @@ Scholar.CollectionTreeView.prototype.hasNextSibling = function(row, afterIndex) } } +/* + * Opens/closes the specified row + */ Scholar.CollectionTreeView.prototype.toggleOpenState = function(row) { var count = 0; //used to tell the tree how many rows were added/removed @@ -202,6 +232,15 @@ Scholar.CollectionTreeView.prototype.toggleOpenState = function(row) this._refreshHashMap(); } +//////////////////////////////////////////////////////////////////////////////// +/// +/// Additional functions for managing data in the tree +/// +//////////////////////////////////////////////////////////////////////////////// + +/* + * Delete the selection + */ Scholar.CollectionTreeView.prototype.deleteSelection = function() { if(this.selection.count == 0) @@ -240,23 +279,37 @@ Scholar.CollectionTreeView.prototype.deleteSelection = function() this.selection.select(this.rowCount-1); } -Scholar.CollectionTreeView.prototype._showItem = function(item, level, beforeRow) +/* + * Called by various view functions to show a row + * + * itemGroup: reference to the ItemGroup + * level: the indent level of the row + * beforeRow: row index to insert new row before + */ +Scholar.CollectionTreeView.prototype._showItem = function(itemGroup, level, beforeRow) { - this._dataItems.splice(beforeRow, 0, [item, false, level]); this.rowCount++; + this._dataItems.splice(beforeRow, 0, [itemGroup, false, level]); this.rowCount++; } +/* + * Called by view to hide specified row + */ Scholar.CollectionTreeView.prototype._hideItem = function(row) { this._dataItems.splice(row,1); this.rowCount--; } +/* + * Returns a reference to the collection at row (see Scholar.Collection in data_access.js) + */ Scholar.CollectionTreeView.prototype._getItemAtRow = function(row) { return this._dataItems[row][0]; } /* - * Create hash map of collection ids to row indexes + * Creates hash map of collection ids to row indexes + * e.g., var rowForID = this._collectionRowMap[] */ Scholar.CollectionTreeView.prototype._refreshHashMap = function() { @@ -268,8 +321,17 @@ Scholar.CollectionTreeView.prototype._refreshHashMap = function() } -/* DRAG AND DROP FUNCTIONS */ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Drag-and-drop functions: +/// canDrop() and drop() are for nsITreeView +/// onDragStart(), getSupportedFlavours(), and onDrop() for nsDragAndDrop.js + nsTransferable.js +/// +//////////////////////////////////////////////////////////////////////////////// +/* + * Called while a drag is over the tree. + */ Scholar.CollectionTreeView.prototype.canDrop = function(row, orient) { if(typeof row == 'object') //workaround... two different services call canDrop (nsDragAndDrop, and the tree) @@ -288,23 +350,28 @@ Scholar.CollectionTreeView.prototype.canDrop = function(row, orient) } var data = dataSet.first.first; var dataType = data.flavour.contentType; - var rowCollection = this._getItemAtRow(row).ref; - //Check to make sure that the highlighting is done right - if(orient == 1 && row == 0 && dataType == 'scholar/collection') + + //Highlight the rows correctly on drag: + if(orient == 1 && row == 0 && dataType == 'scholar/collection') //for dropping collections into root level { return true; } - else if(orient == 0) + else if(orient == 0) //directly on a row... { + var rowCollection = this._getItemAtRow(row).ref; //the collection we are dragging over + if(dataType == 'scholar/item' || dataType == "text/x-moz-url") - return true; + return true; //items can be dropped on anything else if(dataType='scholar/collection' && data.data != rowCollection.getID() && !Scholar.Collections.get(data.data).hasDescendent('collection',rowCollection.getID()) ) - return true; + return true; //collections cannot be dropped on themselves, nor in their children } return false; } +/* + * Called when something's been dropped on or next to a row + */ Scholar.CollectionTreeView.prototype.drop = function(row, orient) { var dataSet = nsTransferable.get(this.getSupportedFlavours(),nsDragAndDrop.getDragData, true); @@ -340,19 +407,31 @@ Scholar.CollectionTreeView.prototype.drop = function(row, orient) } else if(dataType == 'text/x-moz-url' && this.canDrop(row, orient)) { - alert(data.data); - var targetCollection = this._getItemAtRow(row).ref; - /*for(var i = 0; i<ids.length; i++) - targetCollection.addItem(ids[i]); */ + var url = data.data.split("\n")[0]; + + /* WAITING FOR INGESTER SUPPORT + var newItem = Scholar.Ingester.scrapeURL(url); + + if(newItem) + this._getItemAtRow(row).ref.addItem(newItem.getID()); + */ } } +/* + * Begin a drag + */ Scholar.CollectionTreeView.prototype.onDragStart = function(evt,transferData,action) { transferData.data=new TransferData(); + + //attach ID transferData.data.addDataForFlavour("scholar/collection",this._getItemAtRow(this.selection.currentIndex).ref.getID()); } +/* + * Returns the supported drag flavors + */ Scholar.CollectionTreeView.prototype.getSupportedFlavours = function () { var flavors = new FlavourSet(); @@ -362,9 +441,16 @@ Scholar.CollectionTreeView.prototype.getSupportedFlavours = function () return flavors; } +/* + * Called by nsDragAndDrop.js for any sort of drop on the tree + */ Scholar.CollectionTreeView.prototype.onDrop = function (evt,dropdata,session) { } -/* MORE TREEVIEW FUNCTIONS THAT HAVE TO BE HERE */ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Functions for nsITreeView that we have to stub out. +/// +//////////////////////////////////////////////////////////////////////////////// Scholar.CollectionTreeView.prototype.isSorted = function() { return false; } Scholar.CollectionTreeView.prototype.isSeparator = function(row) { return false; } @@ -377,9 +463,12 @@ Scholar.CollectionTreeView.prototype.performActionOnCell = function(action, row, Scholar.CollectionTreeView.prototype.getProgressMode = function(row, col) { } Scholar.CollectionTreeView.prototype.cycleHeader = function(column) { } -// -// SCHOLAR ITEMGROUP -// +//////////////////////////////////////////////////////////////////////////////// +/// +/// Scholar ItemGroup -- a sort of "super class" for Collection, library, +/// and eventually smartSearch +/// +//////////////////////////////////////////////////////////////////////////////// Scholar.ItemGroup = function(type, ref) { diff --git a/chrome/chromeFiles/content/scholar/itemPane.js b/chrome/chromeFiles/content/scholar/itemPane.js @@ -3,7 +3,9 @@ ScholarItemPane = new function() var _dynamicFields; var _creatorTypeMenu; var _beforeRow; - var _notesPane; + var _notesMenu; + var _notesField; + var _notesLabel; var _creatorCount; @@ -17,12 +19,18 @@ ScholarItemPane = new function() this.hideEditor = hideEditor; this.modifyField = modifyField; this.modifyCreator = modifyCreator; + this.modifySelectedNote = modifySelectedNote; + this.removeSelectedNote = removeSelectedNote; + this.addNote = addNote; + this.onNoteSelected = onNoteSelected; function onLoad() { _dynamicFields = document.getElementById('editpane-dynamic-fields'); _creatorTypeMenu = document.getElementById('creatorTypeMenu'); - _notesPane = document.getElementById('scholar-notes'); + _notesMenu = document.getElementById('scholar-notes-menu'); + _notesField = document.getElementById('scholar-notes-field'); + _notesLabel = document.getElementById('scholar-notes-label'); var creatorTypes = Scholar.CreatorTypes.getTypes(); for(var i = 0; i < creatorTypes.length; i++) @@ -60,24 +68,18 @@ ScholarItemPane = new function() for(var i = 0; i<fieldNames.length; i++) { - if(fieldNames[i] != 'notes') - { - var editable = (!_itemBeingEdited.isPrimaryField(fieldNames[i]) || _itemBeingEdited.isEditableField(fieldNames[i])); - - var valueElement = createValueElement(_itemBeingEdited.getField(fieldNames[i]), editable ? fieldNames[i] : null); - - var label = document.createElement("label"); - label.setAttribute("value",Scholar.getString("itemFields."+fieldNames[i])+":"); - label.setAttribute("onclick","this.nextSibling.blur();"); - - addDynamicRow(label,valueElement); - } - else - { - _notesPane.value = _itemBeingEdited.getField(fieldNames[i]); - } + var editable = (!_itemBeingEdited.isPrimaryField(fieldNames[i]) || _itemBeingEdited.isEditableField(fieldNames[i])); + + var valueElement = createValueElement(_itemBeingEdited.getField(fieldNames[i]), editable ? fieldNames[i] : null); + + var label = document.createElement("label"); + label.setAttribute("value",Scholar.getString("itemFields."+fieldNames[i])+":"); + label.setAttribute("onclick","this.nextSibling.blur();"); + + addDynamicRow(label,valueElement); } + //CREATORS: _beforeRow = _dynamicFields.firstChild.nextSibling; _creatorCount = 0; if(_itemBeingEdited.numCreators() > 0) @@ -92,6 +94,19 @@ ScholarItemPane = new function() { addCreatorRow('', '', 1); } + + //NOTES: + _notesMenu.removeAllItems(); + + var notes = _itemBeingEdited.getNotes(); + if(notes.length) + for(var i = 0; i < notes.length; i++) + _notesMenu.appendItem(_noteToTitle(_itemBeingEdited.getNote(notes[i])),notes[i]); + else + addNote(); + + _updateNoteCount(); + _notesMenu.selectedIndex = 0; } function addDynamicRow(label, value, beforeElement) @@ -248,6 +263,80 @@ ScholarItemPane = new function() _itemBeingEdited.setCreator(index, firstName, lastName, typeID); _itemBeingEdited.save(); } + + function modifySelectedNote() + { + if(_notesMenu.selectedIndex == -1) + return; + + var id = _notesMenu.selectedItem.value; + if(id) + { + _itemBeingEdited.updateNote(id,_notesField.value); + } + else //new note + { + id = _itemBeingEdited.addNote(_notesField.value); + _notesMenu.selectedItem.value = id; + } + var label = _notesField.value; + + _notesMenu.selectedItem.label = _noteToTitle(_notesField.value); + } + + function removeSelectedNote() + { + var id = _notesMenu.selectedItem.value; + if(id) + { + _itemBeingEdited.removeNote(id); + } + _notesMenu.removeitemAt(_notesMenu.selectedIndex); + + if(_notesMenu.firstChild.childNodes.length == 0) + addNote(); + + _updateNoteCount(); + } + + function addNote() + { + modifySelectedNote(); + _notesMenu.appendItem('Untitled Note'); + _notesMenu.selectedIndex = _notesMenu.firstChild.childNodes.length-1; + + _updateNoteCount(); + } + + function onNoteSelected() + { + var id = _notesMenu.selectedItem.value; + if(id) + _notesField.value = _itemBeingEdited.getNote(id); + else + _notesField.value = ""; + } + + function _noteToTitle(text) + { + var t = text.substring(0, Math.min(text.indexOf("\n"), 30) ); + + if(t == "") + { + return "Untitled Note"; + } + else + { + return t; + } + } + + function _updateNoteCount() + { + var c = _notesMenu.firstChild.childNodes.length; + + _notesLabel.value = c + " note" + (c != 1 ? "s" : "") + ":"; + } } addEventListener("load", function(e) { ScholarItemPane.onLoad(e); }, false); diff --git a/chrome/chromeFiles/content/scholar/itemPane.xul b/chrome/chromeFiles/content/scholar/itemPane.xul @@ -12,8 +12,16 @@ </tabs> <tabpanels flex="1"> <vbox> - <textbox id="scholar-notes" - type="timed" timeout="1000" oncommand="ScholarItemPane.modifyField('notes',this.value);" + <hbox align="center"> + <label id="scholar-notes-label"/> + <menulist flex="1" id="scholar-notes-menu" onselect="ScholarItemPane.onNoteSelected();"> + <menupopup/> + </menulist> + <toolbarbutton label="-" class="addremove" oncommand="ScholarItemPane.removeSelectedNote();"/> + <toolbarbutton label="+" class="addremove" oncommand="ScholarItemPane.addNote();"/> + </hbox> + <textbox id="scholar-notes-field" + type="timed" timeout="1000" oncommand="ScholarItemPane.modifySelectedNote();" multiline="true" flex="1" onblur="ScholarItemPane.modifyField('notes',this.value);"/> </vbox> diff --git a/chrome/chromeFiles/content/scholar/itemTreeView.js b/chrome/chromeFiles/content/scholar/itemTreeView.js @@ -1,3 +1,14 @@ +//////////////////////////////////////////////////////////////////////////////// +/// +/// ItemTreeView +/// -- handles the link between an individual tree and the data layer +/// -- displays only items (no collections, no hierarchy) +/// +//////////////////////////////////////////////////////////////////////////////// + +/* + * Constructor the the ItemTreeView object + */ Scholar.ItemTreeView = function(itemGroup) { this._itemGroup = itemGroup; @@ -9,6 +20,9 @@ Scholar.ItemTreeView = function(itemGroup) this._unregisterID = Scholar.Notifier.registerItemTree(this); } +/* + * Called by the tree itself + */ Scholar.ItemTreeView.prototype.setTree = function(treebox) { if(this._treebox) @@ -25,6 +39,10 @@ Scholar.ItemTreeView.prototype.setTree = function(treebox) } } +/* + * Reload the rows from the data access methods + * (doesn't call the tree.invalidate methods, etc.) + */ Scholar.ItemTreeView.prototype.refresh = function() { this._dataItems = new Array(); @@ -38,6 +56,9 @@ Scholar.ItemTreeView.prototype.refresh = function() this._refreshHashMap(); } +/* + * Called by Scholar.Notifier on any changes to items in the data layer + */ Scholar.ItemTreeView.prototype.notify = function(action, type, ids) { var madeChanges = false; @@ -112,11 +133,21 @@ Scholar.ItemTreeView.prototype.notify = function(action, type, ids) this.selection.selectEventsSuppressed = false; } +/* + * Unregisters view from Scholar.Notifier (called on window close) + */ Scholar.ItemTreeView.prototype.unregister = function() { Scholar.Notifier.unregisterItemTree(this._unregisterID); } +//////////////////////////////////////////////////////////////////////////////// +/// +/// nsITreeView functions +/// http://www.xulplanet.com/references/xpcomref/ifaces/nsITreeView.html +/// +//////////////////////////////////////////////////////////////////////////////// + Scholar.ItemTreeView.prototype.getCellText = function(row, column) { var obj = this._getItemAtRow(row); @@ -175,9 +206,12 @@ Scholar.ItemTreeView.prototype.cycleHeader = function(column) this._treebox.invalidate(); } +/* + * Sort the items by the currently sorted column. + * Simply uses Array.sort() function, and refreshes the hash map. + */ Scholar.ItemTreeView.prototype.sort = function() { - var column = this._treebox.columns.getSortedColumn() var order = column.element.getAttribute('sortDirection') == 'descending'; @@ -199,13 +233,13 @@ Scholar.ItemTreeView.prototype.sort = function() } } - function oppSort(a,b) + function oppositeSort(a,b) { return(columnSort(a,b) * -1); } if(order) - this._dataItems.sort(oppSort); + this._dataItems.sort(oppositeSort); else this._dataItems.sort(columnSort); @@ -213,6 +247,15 @@ Scholar.ItemTreeView.prototype.sort = function() } +//////////////////////////////////////////////////////////////////////////////// +/// +/// Additional functions for managing data in the tree +/// +//////////////////////////////////////////////////////////////////////////////// + +/* + * Delete the selection + */ Scholar.ItemTreeView.prototype.deleteSelection = function() { if(this.selection.count == 0) @@ -246,6 +289,9 @@ Scholar.ItemTreeView.prototype.deleteSelection = function() this._treebox.endUpdateBatch(); } +/* + * Set the search filter on the view + */ Scholar.ItemTreeView.prototype.searchText = function(search) { this.selection.selectEventsSuppressed = true; @@ -263,23 +309,35 @@ Scholar.ItemTreeView.prototype.searchText = function(search) this._treebox.invalidate(); } +/* + * Called by various view functions to show a row + * + * item: reference to the Item + * beforeRow: row index to insert new row before + */ Scholar.ItemTreeView.prototype._showItem = function(item, beforeRow) { this._dataItems.splice(beforeRow, 0, item); this.rowCount++; } +/* + * Called by view to hide specified row + */ Scholar.ItemTreeView.prototype._hideItem = function(row) { this._dataItems.splice(row,1); this.rowCount--; } +/* + * Returns a reference to the item at row (see Scholar.Item in data_access.js) + */ Scholar.ItemTreeView.prototype._getItemAtRow = function(row) { return this._dataItems[row]; } /* - * Create hash map of item ids to row indexes + * Create hash map of item ids to row indexes */ Scholar.ItemTreeView.prototype._refreshHashMap = function() { @@ -288,6 +346,9 @@ Scholar.ItemTreeView.prototype._refreshHashMap = function() this._itemRowMap[this._getItemAtRow(i).getID()] = i; } +/* + * Saves the ids of currently selected items for later + */ Scholar.ItemTreeView.prototype.saveSelection = function() { this._savedSelection = new Array(); @@ -302,6 +363,9 @@ Scholar.ItemTreeView.prototype.saveSelection = function() } } +/* + * Sets the selection based on saved selection ids (see above) + */ Scholar.ItemTreeView.prototype.rememberSelection = function() { this.selection.clearSelection(); @@ -312,15 +376,26 @@ Scholar.ItemTreeView.prototype.rememberSelection = function() } } -/* DRAG AND DROP FUNCTIONS */ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Drag-and-drop functions: +/// for nsDragAndDrop.js + nsTransferable.js +/// +//////////////////////////////////////////////////////////////////////////////// +/* + * Begin a drag + */ Scholar.ItemTreeView.prototype.onDragStart = function (evt,transferData,action) { transferData.data=new TransferData(); this.saveSelection(); transferData.data.addDataForFlavour("scholar/item",this._savedSelection); } - + +/* + * Called by nsDragAndDrop.js for any sort of drop on the tree + */ Scholar.ItemTreeView.prototype.getSupportedFlavours = function () { var flavors = new FlavourSet(); @@ -329,28 +404,39 @@ 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) { var dataType = data.flavour.contentType; - var ids = data.data.split(','); if(dataType == 'scholar/item') { + var ids = data.data.split(','); for(var i = 0; i<ids.length; i++) this._itemGroup.ref.addItem(ids[i]); } else if(dataType == 'text/x-moz-url') { - alert(data.data); - var targetCollection = this._itemGroup.ref; - /*for(var i = 0; i<ids.length; i++) - targetCollection.addItem(ids[i]); */ + var url = data.data.split("\n")[0]; + + /* WAITING FOR INGESTER SUPPORT + var newItem = Scholar.Ingester.scrapeURL(url); + + if(newItem) + this._itemGroup.ref.addItem(newItem.getID()); + */ } } Scholar.ItemTreeView.prototype.onDragOver = function (evt,dropdata,session) { } -/* MORE TREEVIEW FUNCTIONS THAT HAVE TO BE HERE */ +//////////////////////////////////////////////////////////////////////////////// +/// +/// Functions for nsITreeView that we have to stub out. +/// +//////////////////////////////////////////////////////////////////////////////// Scholar.ItemTreeView.prototype.isSeparator = function(row) { return false; } Scholar.ItemTreeView.prototype.isContainer = function(row) { return false; }