blossom
Version:
Modern, Cross-Platform Application Framework
301 lines (225 loc) • 10.6 kB
JavaScript
// ==========================================================================
// Project: SproutCore - JavaScript Application Framework
// Copyright: ©2006-2011 Strobe Inc. and contributors.
// portions copyright @2009 Apple Inc.
// License: Licensed under MIT license (see license.js)
// ==========================================================================
var view, del, content ;
suite("SC.CollectionView.itemViewForContentIndex", {
setup: function() {
content = "a b c".w().map(function(x) {
return SC.Object.create({ title: x });
});
del = {
fixture: {
isEnabled: true,
isSelected: true,
outlineLevel: 3,
disclosureState: SC.LEAF_NODE
},
contentIndexIsEnabled: function() {
return this.fixture.isEnabled;
},
contentIndexIsSelected: function() {
return this.fixture.isSelected;
},
contentIndexOutlineLevel: function() {
return this.fixture.outlineLevel;
},
contentIndexDisclosureState: function() {
return this.fixture.disclosureState ;
}
};
// NOTE: delegate methods above are added here.
view = SC.CollectionView.create(del, {
content: content,
layoutForContentIndex: function(contentIndex) {
return this.fixtureLayout ;
},
fixtureLayout: { left: 0, right: 0, top:0, bottom: 0 },
groupExampleView: SC.View.extend(), // custom for testing
exampleView: SC.View.extend(), // custom for testing
testAsGroup: false,
contentIndexIsGroup: function() { return this.testAsGroup; },
contentGroupIndexes: function() {
if (this.testAsGroup) {
return SC.IndexSet.create(0, this.get('length'));
} else return null ;
},
fixtureNowShowing: SC.IndexSet.create(0,3),
computeNowShowing: function() {
return this.fixtureNowShowing;
}
});
// add in delegate mixin
del = SC.mixin({}, SC.CollectionContent, del);
}
});
function shouldMatchFixture(itemView, fixture) {
var key;
for(key in fixture) {
if (!fixture.hasOwnProperty(key)) continue;
equals(itemView.get(key), fixture[key], 'itemView.%@ should match delegate value'.fmt(key));
}
}
test("creating basic item view", function() {
var itemView = view.itemViewForContentIndex(1);
// should use exampleView
ok(itemView, 'should return itemView');
ok(itemView.kindOf(view.exampleView), 'itemView %@ should be kindOf %@'.fmt(itemView, view.exampleView));
// set added properties
equals(itemView.get('content'), content.objectAt(1), 'itemView.content should be set to content item');
equals(itemView.get('contentIndex'), 1, 'itemView.contentIndex should be set');
equals(itemView.get('owner'), view, 'itemView.owner should be collection view');
equals(itemView.get('displayDelegate'), view, 'itemView.displayDelegate should be collection view');
equals(itemView.get('parentView'), view, 'itemView.parentView should be collection view');
// test data from delegate
shouldMatchFixture(itemView, view.fixture);
});
test("returning item from cache", function() {
var itemView1 = view.itemViewForContentIndex(1);
ok(itemView1, 'precond - first call returns an item view');
var itemView2 = view.itemViewForContentIndex(1);
equals(itemView2, itemView1, 'retrieving multiple times should same instance');
// Test internal case
var itemView3 = view.itemViewForContentIndex(1, true);
ok(itemView1 !== itemView3, 'itemViewForContentIndex(1, true) should return new item even if it is already cached actual :%@'.fmt(itemView3));
var itemView4 = view.itemViewForContentIndex(1, NO);
equals(itemView4, itemView3, 'itemViewForContentIndex(1) [no reload] should return newly cached item after recache');
});
// ..........................................................
// ALTERNATE WAYS TO GET AN EXAMPLE VIEW
//
test("contentExampleViewKey is set and content has property", function() {
var CustomView = SC.View.extend();
var obj = content.objectAt(1);
obj.set('foo', CustomView);
view.set('contentExampleViewKey', 'foo');
var itemView = view.itemViewForContentIndex(1);
ok(itemView, 'should return item view');
ok(itemView.kindOf(CustomView), 'itemView should be custom view specified on object. actual: %@'.fmt(itemView));
});
test("contentExampleViewKey is set and content is null", function() {
var CustomView = SC.View.extend();
view.set('contentExampleViewKey', 'foo');
content.replace(1,1,[null]);
var itemView = view.itemViewForContentIndex(1);
ok(itemView, 'should return item view');
equals(itemView.get('content'), null, 'itemView content should be null');
ok(itemView.kindOf(view.exampleView), 'itemView should be exampleView (%@). actual: %@'.fmt(view.exampleView, itemView));
});
test("contentExampleViewKey is set and content property is empty", function() {
var CustomView = SC.View.extend();
view.set('contentExampleViewKey', 'foo');
var itemView = view.itemViewForContentIndex(1);
ok(itemView, 'should return item view');
equals(itemView.get('content'), content.objectAt(1), 'itemView should have content');
ok(itemView.kindOf(view.exampleView), 'itemView should be exampleView (%@). actual: %@'.fmt(view.exampleView, itemView));
});
// ..........................................................
// GROUP EXAMPLE VIEW
//
test("delegate says content is group", function() {
view.testAsGroup = true ;
var itemView = view.itemViewForContentIndex(1);
ok(itemView, 'should return itemView');
ok(itemView.kindOf(view.groupExampleView), 'itemView should be groupExampleView (%@). actual: %@'.fmt(view.groupExampleView, itemView));
ok(itemView.isGroupView, 'itemView.isGroupView should be true');
});
test("contentGroupExampleViewKey is set and content has property", function() {
view.testAsGroup = true ;
var CustomView = SC.View.extend();
var obj = content.objectAt(1);
obj.set('foo', CustomView);
view.set('contentGroupExampleViewKey', 'foo');
var itemView = view.itemViewForContentIndex(1);
ok(itemView, 'should return item view');
ok(itemView.kindOf(CustomView), 'itemView should be custom view specified on object. actual: %@'.fmt(itemView));
ok(itemView.isGroupView, 'itemView.isGroupView should be true');
});
test("contentGroupExampleViewKey is set and content is null", function() {
view.testAsGroup = true ;
var CustomView = SC.View.extend();
view.set('contentGroupExampleViewKey', 'foo');
content.replace(1,1,[null]);
var itemView = view.itemViewForContentIndex(1);
ok(itemView, 'should return item view');
equals(itemView.get('content'), null, 'itemView content should be null');
ok(itemView.kindOf(view.groupExampleView), 'itemView should be exampleView (%@). actual: %@'.fmt(view.groupExampleView, itemView));
ok(itemView.isGroupView, 'itemView.isGroupView should be true');
});
test("contentGroupExampleViewKey is set and content property is empty", function() {
view.testAsGroup = true ;
var CustomView = SC.View.extend();
view.set('contentGroupExampleViewKey', 'foo');
var itemView = view.itemViewForContentIndex(1);
ok(itemView, 'should return item view');
equals(itemView.get('content'), content.objectAt(1), 'itemView should have content');
ok(itemView.kindOf(view.groupExampleView), 'itemView should be exampleView (%@). actual: %@'.fmt(view.groupExampleView, itemView));
ok(itemView.isGroupView, 'itemView.isGroupView should be true');
});
test("_contentGroupIndexes's cache should be properly invalidated", function() {
view.testAsGroup = true;
// force setup of range observers
view.updateContentRangeObserver();
ok(view.get('_contentGroupIndexes').isEqual(SC.IndexSet.create(0, 3)), "contentGroupIndexes should have correct initial value");
view.get('content').removeAt(2, 1);
ok(view.get('_contentGroupIndexes').isEqual(SC.IndexSet.create(0, 2)), "contentGroupIndexes should have updated value after deletion");
});
// ..........................................................
// DELEGATE SUPPORT
//
test("consults delegate if set", function() {
view.fixture = null; //break to make sure this is not used
view.delegate = del;
var itemView = view.itemViewForContentIndex(1);
ok(itemView, 'returns item view');
shouldMatchFixture(itemView, del.fixture);
});
test("consults content if implements mixin and delegate not set", function() {
view.fixture = null; //break to make sure this is not used
view.delegate = null;
SC.mixin(content, del) ; // add delegate methods to content
var itemView = view.itemViewForContentIndex(1);
ok(itemView, 'returns item view');
shouldMatchFixture(itemView, content.fixture);
});
test("prefers delegate over content if both implement mixin", function() {
view.fixture = null; //break to make sure this is not used
view.delegate = del;
SC.mixin(content, del) ; // add delegate methods to content
content.fixture = null ; //break
var itemView = view.itemViewForContentIndex(1);
ok(itemView, 'returns item view');
shouldMatchFixture(itemView, del.fixture);
});
// ..........................................................
// SPECIAL CASES
//
test("after making an item visible then invisible again", function() {
view.isVisibleInWindow = true ;
// STEP 1- setup with some nowShowing
SC.run(function() {
view.set('fixtureNowShowing', SC.IndexSet.create(1));
view.notifyPropertyChange('nowShowing');
});
equals(view.get('childViews').length, 1, 'precond - should have a child view');
var itemView = view.itemViewForContentIndex(1);
equals(itemView.get('parentView'), view, 'itemView has parent view');
// STEP 2- setup with NONE visible
SC.run(function() {
view.set('fixtureNowShowing', SC.IndexSet.create());
view.notifyPropertyChange('nowShowing');
});
equals(view.get('childViews').length, 0, 'precond - should have no childview');
itemView = view.itemViewForContentIndex(1);
equals(itemView.get('parentView'), view, 'itemView has parent view');
// STEP 3- go back to nowShowing
SC.run(function() {
view.set('fixtureNowShowing', SC.IndexSet.create(1));
view.notifyPropertyChange('nowShowing');
});
equals(view.get('childViews').length, 1, 'precond - should have a child view');
itemView = view.itemViewForContentIndex(1);
equals(itemView.get('parentView'), view, 'itemView has parent view');
});