// ========================================================================== // Project: SproutCore
- JavaScript Application Framework // Copyright: ©2006-2011 Strobe Inc. and contributors. // portions copyright @2011 Apple Inc. // License: Licensed under MIT license (see license.js) // ========================================================================== /*global ok, test, equals, module */
var view, del, content ;
module(“SC.CollectionView.itemViewForContentIndex”, {
setup: function() { content = "a b c".w().map(function(x) { return SC.Object.create({ title: x }); }); del = { fixture: { isEnabled: YES, isSelected: YES, 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. SC.run(function () { 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({ isReusable: false }), // custom for testing testAsGroup: NO, 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(“isLast property”, function () {
view.isVisibleInWindow = true; var itemView = view.itemViewForContentIndex(1); equals(itemView.get('isLast'), false, 'itemView.isLast should be false'); itemView = view.itemViewForContentIndex(2); equals(itemView.get('isLast'), true, 'itemView.isLast should be true'); SC.run(function () { view.beginPropertyChanges(); view.get('content').pushObject(SC.Object.create({ title: 'd' })); view.set('fixtureNowShowing', SC.IndexSet.create(0, 4)); view.endPropertyChanges(); }); itemView = view.itemViewForContentIndex(3); equals(itemView.get('isLast'), true, 'itemView.isLast should be true'); itemView = view.itemViewForContentIndex(2); equals(itemView.get('isLast'), false, 'itemView.isLast for previous last item should be false');
});
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, YES); ok(itemView1 !== itemView3, 'itemViewForContentIndex(1, YES) 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');
});
// Tests support for the addition of designModes to SC
.Pane and SC
.View. Since // SC
.CollectionView doesn't use child views and thus doesn't call // SC
.View:insertBefore, it needs to pass the designMode down to its item views // itself. test(“set designMode on item views”, function() {
var itemView, updateDesignModeCount = 0; view.set('exampleView', SC.View.extend({ updateDesignMode: function () { updateDesignModeCount++; sc_super(); } })); // Initial designMode before creating the item view. view.set('designMode', 'small'); itemView = view.itemViewForContentIndex(1); equals(itemView.get('designMode'), 'small', "itemView.designMode should be set to match the current value of the collection"); equals(updateDesignModeCount, 1, "updateDesignMode should have been called once on the itemView"); // Changes to designMode after creating the item view. view.updateDesignMode('small', 'large'); equals(itemView.get('designMode'), 'large', "itemView.designMode should be set to match the current value of the collection"); equals(updateDesignModeCount, 2, "updateDesignMode should have been called once more on each itemView");
});
// .….….….….….….….….….….….….….….. // 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() {
view.set('contentExampleViewKey', 'foo'); SC.run(function () { 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() {
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 = YES ; 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 YES');
});
test(“contentGroupExampleViewKey is set and content has property”, function() {
view.testAsGroup = YES ; 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 YES');
});
test(“contentGroupExampleViewKey is set and content is null”, function() {
view.testAsGroup = YES ; view.set('contentGroupExampleViewKey', 'foo'); SC.run(function () { 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 YES');
});
test(“contentGroupExampleViewKey is set and content property is empty”, function() {
view.testAsGroup = YES ; 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 YES');
});
test(“_contentGroupIndexes's cache should be properly invalidated”, function() {
view.testAsGroup = YES; // force setup of range observers view.updateContentRangeObserver(); ok(view.get('_contentGroupIndexes').isEqual(SC.IndexSet.create(0, 3)), "contentGroupIndexes should have correct initial value"); SC.run(function () { 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(“attempt to retrieve invalid indexes returns null”, function () {
var itemView; itemView = view.itemViewForContentIndex(null); equals(itemView, null, 'Using index null should not return an item view'); itemView = view.itemViewForContentIndex(undefined); equals(itemView, null, 'Using index undefined should not return an item view'); itemView = view.itemViewForContentIndex(-1); equals(itemView, null, 'Using index -1 should not return an item view'); itemView = view.itemViewForContentIndex(view.get('length')); equals(itemView, null, 'Using index %@ (length of content is %@) should not return an item view'.fmt(view.get('length'), view.get('length')));
});
test(“after making an item visible then invisible again”, function() {
view.isVisibleInWindow = YES ; // 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 after some nowShowing'); // 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 after none visible'); // 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 after back to some nowShowing');
});
// Editable Item Views.
test(“canDeleteContent sets isDeletable on the item views so they can visually indicate it”, function () {
var itemView; view.set('canDeleteContent', true); itemView = view.itemViewForContentIndex(1); equals(itemView.get('isDeletable'), true, 'itemView has isDeletable'); view.isVisibleInWindow = YES; SC.run(function () { view.set('isEditable', false); }); view.set('isEditable', false); itemView = view.itemViewForContentIndex(1); equals(itemView.get('isDeletable'), false, 'itemView has isDeletable');
});
test(“canEditContent sets isEditable on the item views so they can visually indicate it”, function () {
var itemView; view.set('canEditContent', true); itemView = view.itemViewForContentIndex(1); equals(itemView.get('isEditable'), true, 'itemView has isEditable'); view.isVisibleInWindow = YES; SC.run(function () { view.set('isEditable', false); }); itemView = view.itemViewForContentIndex(1); equals(itemView.get('isEditable'), false, 'itemView has isEditable');
});
test(“canReorderContent sets isReorderable on the item views so they can visually indicate it”, function () {
var itemView; view.set('canReorderContent', true); itemView = view.itemViewForContentIndex(1); equals(itemView.get('isReorderable'), true, 'itemView has isReorderable'); view.isVisibleInWindow = YES; SC.run(function () { view.set('isEditable', false); }); view.set('isEditable', false); itemView = view.itemViewForContentIndex(1); equals(itemView.get('isReorderable'), false, 'itemView has isReorderable');
});
test(“itemViewForContentObject”, function() {
equals(view.itemViewForContentObject(content[0]).getPath('content.title'), 'a', "itemViewForContentObject returns 0th itemView for the 0th content object"); equals(view.itemViewForContentObject(SC.Object.create()), null, "itemViewForContentObject returns null for a object that is not in in its content"); var emptyContentCollection; SC.run(function() { emptyContentCollection = SC.CollectionView.create(); }); equals(emptyContentCollection.itemViewForContentObject(content[0]), null, "itemViewForContentObject returns null (without erroring) when it has no content.");
});