// ========================================================================== // Project: SproutCore - JavaScript Application Framework // Copyright: ©2006-2009 Sprout Systems, Inc. and contributors. // Portions ©2008-2009 Apple Inc. All rights reserved. // License: Licened under MIT license (see license.js) // ========================================================================== /** @namespace A Collection View Delegate is consulted by a SC.CollectionView's to make policy decisions about certain behaviors such as selection control and drag and drop. If you need to control other aspects of your data, you may also want to add the SC.CollectionContent mixin. To act as a Collection Delegate, just apply this mixin to your class. You must then set the "delegate" property on the CollectionView to your object. Alternatively, if no delegate is set on a CollectionView, but the content implements this mixin, the content object will be used as the delegate instead. If you set an ArrayController or its arrangedObjects property as the content of a CollectionView, the ArrayController will automatically act as the delegate for the view. @since SproutCore 1.0 */ SC.CollectionViewDelegate = { /** Used to detect the mixin by SC.CollectionView */ isCollectionViewDelegate: YES, // .......................................................... // SELECTION // /** This method will be called anytime the collection view is about to change the selection in response to user mouse clicks or keyboard events. You can use this method to adjust the proposed selection, eliminating any selected objects that cannot be selected. The default implementation of this method simply returns the proposed selection. @param {SC.CollectionView} view the collection view @param {SC.IndexSet} sel Proposed array of selected objects. @returns {SC.IndexSet} Actual allow selection index set */ collectionViewSelectionForProposedSelection: function(view, sel) { return sel ; }, /** Called by the collection when attempting to select an item. Return the actual indexes you want to allow to be selected. Return null to disallow the change. The default allows all selection. @param {SC.CollectionView} view the view collection view @param {SC.IndexSet} indexes the indexes to be selected @param {Boolean} extend YES if the indexes will extend existing sel @returns {SC.IndexSet} allowed index set */ collectionViewShouldSelectIndexes: function (view, indexes, extend) { return indexes; }, /** Called by the collection when attempting to deselect an item. Return the actual indexes you want to allow to be deselected. Return null to disallow the change. The default allows all selection. Note that you should not modify the passed in IndexSet. clone it instead. @param {SC.CollectionView} view the view collection view @param {SC.IndexSet} indexes the indexes to be selected @returns {SC.IndexSet} allowed index set */ collectionViewShouldDeselectIndexes: function (view, indexes) { return indexes; }, // .......................................................... // EDIT OPERATIONS // /** Called by the collection view whenever the deleteSelection() method is called. You can implement this method to get fine-grained control over which items can be deleted. To prevent deletion, return null. This method is only called if canDeleteContent is YES on the collection view. @param {SC.CollectionView} view the collection view @param {SC.IndexSet} indexes proposed index set of items to delete. @returns {SC.IndexSet} index set allowed to delete or null. */ collectionViewShouldDeleteIndexes: function(view, indexes) { return indexes; }, /** Called by the collection view to actually delete the selected items. The default behavior will use standard array operators to delete the indexes from the array. You can implement this method to provide your own deletion method. If you simply want to control the items to be deleted, you should instead implement collectionViewShouldDeleteItems(). This method will only be called if canDeleteContent is YES and collectionViewShouldDeleteIndexes() returns a non-empty index set @param {SC.CollectionView} view collection view @param {SC.IndexSet} indexes the items to delete @returns {Boolean} YES if the deletion was a success. */ collectionViewDeleteContent: function(view, content, indexes) { if (!content) return NO ; if (SC.typeOf(content.destroyAt) === SC.T_FUNCTION) { content.destroyAt(indexes); return YES ; } else if (SC.typeOf(content.removeAt) === SC.T_FUNCTION) { content.removeAt(indexes); return YES; } else return NO ; }, // .......................................................... // DRAGGING // /** Called by the collection view just before it starts a drag to give you an opportunity to decide if the drag should be allowed. You can use this method to implement fine-grained control over when a drag will be allowed and when it will not be allowed. For example, you may enable content reordering but then implement this method to prevent reordering of certain items in the view. The default implementation always returns YES. @param view {SC.CollectionView} the collection view @returns {Boolean} YES to alow, NO to prevent it */ collectionViewShouldBeginDrag: function(view) { return YES; }, /** Called by the collection view just before it starts a drag so that you can provide the data types you would like to support in the data. You can implement this method to return an array of the data types you will provide for the drag data. If you return null or an empty array, can you have set canReorderContent to YES on the CollectionView, then the drag will go ahead but only reordering will be allowed. If canReorderContent is NO, then the drag will not be allowed to start. If you simply want to control whether a drag is allowed or not, you should instead implement collectionViewShouldBeginDrag(). The default returns an empty array. @param view {SC.CollectionView} the collection view to begin dragging. @returns {Array} array of supported data types. */ collectionViewDragDataTypes: function(view) { return []; }, /** Called by a collection view when a drag concludes to give you the option to provide the drag data for the drop. This method should be implemented essentially as you would implement the dragDataForType() if you were a drag data source. You will never be asked to provide drag data for a reorder event, only for other types of data. The default implementation returns null. @param view {SC.CollectionView} the collection view that initiated the drag @param dataType {String} the data type to provide @param drag {SC.Drag} the drag object @returns {Object} the data object or null if the data could not be provided. */ collectionViewDragDataForType: function(view, drag, dataType) { return null ; }, /** Called once during a drag the first time view is entered. Return all possible drag operations OR'd together. @param {SC.CollectionView} view the collection view that initiated the drag @param {SC.Drag} drag the drag object @param {Number} proposedDragOperations proposed logical OR of allowed drag operations. @returns {Number} the allowed drag operations. Defaults to op */ collectionViewComputeDragOperations: function(view, drag, proposedDragOperations) { return proposedDragOperations ; }, /** Called by the collection view during a drag to let you determine the kind and location of a drop you might want to accept. You can override this method to implement fine-grained control over how and when a dragged item is allowed to be dropped into a collection view. This method will be called by the collection view both to determine in general which operations you might support and specifically the operations you would support if the user dropped an item over a specific location. If the proposedDropOperaration parameter is SC.DROP_ON or SC.DROP_BEFORE, then the proposedInsertionPoint will be a non-negative value and you should determine the specific operations you will support if the user dropped the drag item at that point. If you do not like the proposed drop operation or insertion point, you can override these properties as well by setting the proposedDropOperation and proposedInsertionIndex properties on the collection view during this method. These properties are ignored all other times. @param view {SC.CollectionView} the collection view @param drag {SC.Drag} the current drag object @param op {Number} proposed logical OR of allowed drag operations. @param proposedInsertionIndex {Number} an index into the content array representing the proposed insertion point. @param proposedDropOperation {String} the proposed drop operation. Will be one of SC.DROP_ON, SC.DROP_BEFORE, or SC.DROP_ANY. @returns the allowed drag operation. Defaults to op */ collectionViewValidateDragOperation: function(view, drag, op, proposedInsertionIndex, proposedDropOperaration) { return (op & SC.DROP_ON) ? SC.DRAG_NONE : op ; }, /** Called by the collection view to actually accept a drop. This method will only be invoked AFTER your validateDrop method has been called to determine if you want to even allow the drag operation to go through. You should actually make changes to the data model if needed here and then return the actual drag operation that was performed. If you return SC.DRAG_NONE and the dragOperation was SC.DRAG_REORDER, then the default reorder behavior will be provided by the collection view. @param view {SC.CollectionView} @param drag {SC.Drag} the current drag object @param op {Number} proposed logical OR of allowed drag operations. @param proposedInsertionIndex {Number} an index into the content array representing the proposed insertion point. @param proposedDropOperation {String} the proposed drop operation. Will be one of SC.DROP_ON, SC.DROP_BEFORE, or SC.DROP_ANY. @returns the allowed drag operation. Defaults to proposedDragOperation */ collectionViewPerformDragOperation: function(view, drag, op, proposedInsertionIndex, proposedDropOperaration) { return SC.DRAG_NONE ; }, /** Renders a drag view for the passed content indexes. If you return null from this, then a default drag view will be generated for you. @param {SC.CollectionView} view @param {SC.IndexSet} dragContent @returns {SC.View} view or null */ collectionViewDragViewFor: function(view, dragContent) { return null; } };