Skip to content

Instantly share code, notes, and snippets.

Created July 29, 2009 00:31
Show Gist options
  • Select an option

  • Save anonymous/157780 to your computer and use it in GitHub Desktop.

Select an option

Save anonymous/157780 to your computer and use it in GitHub Desktop.
/*
example design of an expandable list view that expands selected items in place using alternate list item view
*/
tasksView: SC.ScrollView.design({
hasHorizontalScroller: NO,
layout: { top: 24, bottom: 0, left: 0, right: 0 },
backgroundColor: 'white',
contentView: Tasks.ExpandableListView.design({
contentBinding: 'Tasks.controller.arrangedObjects',
selectionBinding: 'Tasks.controller.selection',
selectedShowing: 'detailView',
exampleView: Tasks.ExpandableView.design({
nowShowing: 'summaryView',
summaryView: SC.View.design({
childViews: ...
}),
detailView: SC.View.design({
childViews: ...
})
})
})
})
/** @object
An expansion delegate automatically expands the
example view of the index which is selected.
*/
Tasks.expansionDelegate = SC.Object.create(SC.CollectionViewDelegate,
SC.CollectionRowDelegate,
/** @scope Tasks.ExpansionDelegate.prototype */ {
selectedIdx: null,
customRowHeightIndexes: SC.IndexSet.create(),
collectionViewSelectionForProposedSelection: function(view, sel) {
if (sel.sources().length) {
var idx = sel.indexSetForSource(sel.sources()[0]).min();
this.customRowHeightIndexes.remove(this.selectedIdx).add(idx);
this.selectedIdx = idx;
} else {
this.customRowHeightIndexes.remove(this.selectedIdx);
this.selectedIdx = null;
}
return sel;
},
contentIndexRowHeight: function(view, content, idx) {
if (this.selectedIdx === idx) {
// TODO I don't like this, but I don't know yet how to obtain a size estimate
return 1000;
} else {
return this.get('rowHeight');
}
},
toString: function() {
return "Tasks.ExpansionDelegate:%@<%@>".fmt(SC.guidFor(this), this.selectionIdx);
}
});
/** @class
Enables selected items to be automatically expanded in-place.
@extends SC.ListView
*/
Tasks.ExpandableListView = SC.ListView.extend({
delegate: Tasks.expansionDelegate,
/**
Since we expand the selection automatically,
multiple selection is not allowed
*/
allowsMultipleSelection: NO,
didReload: function() {
var sel = this.get('selection');
if (sel && sel.sources().length) {
var idx = sel.indexSetForSource(sel.sources()[0]).min();
var selectedView = this.childViews[idx];
if (!selectedView)
return;
var showing = this.get('selectedShowing');
selectedView.set('nowShowing', showing);
}
}
});
/** @class
Renders each work item as a member of a collection view.
@extends SC.ListItemView
*/
Tasks.ExpandableView = SC.ListItemView.extend(
/** @scope Tasks.WorkItemView.prototype */ {
classNames: ['expandable-item-view'],
/**
{SC.String}
Identifies the view that will be shown when the list
item is selected
*/
selectedShowing: null,
/**
{SC.String}
Identifies the view that will be shown when the list
item is not selected and when the item is just created
*/
nowShowing: null,
/**
Replaces any child views with the passed new content.
This method is automatically called whenever your contentView property
changes. You can override it if you want to provide some behavior other
than the default.
@param {SC.View} newContent the new content view or null.
*/
replaceContent: function(newContent) {
if (this.childViews.length)
this.replaceChild(newContent, this.childViews[0]) ;
else
this.appendChild(newContent);
},
/** @private */
createChildViews: function() {
// if contentView is defined, then create the content
var nowShowing = this.get('nowShowing') ;
if (nowShowing && nowShowing.length>0) this.nowShowingDidChange();
},
/**
Invoked whenever the nowShowing property changes. This will try to find
the new content if possible and set it. If you set nowShowing to an
empty string or null, then the current content will be cleared.
If you set the content manually, the nowShowing property will be set to
SC.CONTENT_SET_DIRECTLY
*/
nowShowingDidChange: function() {
var nowShowing = this.get('nowShowing') ;
var content = null;
//its a property path
if(SC.typeOf(nowShowing) === SC.T_STRING){
// if nowShowing was set because the content was set directly, then
// do nothing.
if (nowShowing === SC.CONTENT_SET_DIRECTLY) return ;
// otherwise, if nowShowing is a non-empty string, try to find it...
if (nowShowing && nowShowing.length>0) {
content = this.get(nowShowing).create();
}
}else{ //its a view
content = nowShowing;
}
// only allow views
if (content && !(content instanceof SC.View)) content = null;
// set content
this.set('contentView', content) ;
}.observes('nowShowing'),
/**
Invoked whenever the content property changes. This method will simply
call replaceContent. Override replaceContent to change how the view is
swapped out.
*/
contentViewDidChange: function() {
this.replaceContent(this.get('contentView'));
}.observes('contentView'),
render: function(context, firstTime) {
var content = this.get('content'),
del = this.displayDelegate,
level = this.get('outlineLevel'),
indent = this.get('outlineIndent'),
key, working ;
// outline level wrapper
working = context.begin("div").addClass("sc-outline");
if (level>=0 && indent>0) working.addStyle("left", indent*(level+1));
this.renderChildViews(working, true);
// handle action
key = this.getDelegateProperty('listItemActionProperty', del) ;
value = (key && content) ? (content.get ? content.get(key) : content[key]) : null ;
if (value) {
this.renderAction(working, value);
context.addClass('has-action');
}
context = working.end();
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment