// ========================================================================== // Project: SproutCore
- JavaScript Application Framework // Copyright: ©2006-2011 Apple Inc. and contributors. // License: Licensed under MIT license (see license.js) // ==========================================================================
/*global module, test, equals, same */
// .….….….….….….….….….….….….….….. // viewDidResize() // module(“SC.View#viewDidResize”);
test(“invokes parentViewDidResize on all child views”, function() {
var callCount = 0 ; var ChildView = SC.View.extend({ parentViewDidResize: function() { callCount++; } }); var view = SC.View.create({ childViews: [ChildView, ChildView, ChildView] }); // now test... SC.run(function() { view.viewDidResize(); }); equals(callCount, 3, 'should invoke parentViewDidResize() on all children');
});
test(“parentViewDidResize should only be called when the parent's layout property changes in a manner that may affect child views.”, function() {
var callCount = 0 ; var view = SC.View.create({ // use the callback below to detect when viewDidResize is icalled. childViews: [SC.View.extend({ parentViewDidResize: function() { callCount++; } })] }); SC.run(function () { view.set('layout', { top: 10, left: 20, height: 50, width: 40 }); }); equals(callCount, 1, 'parentViewDidResize should invoke once'); SC.run(function () { view.adjust('top', 0); }); equals(callCount, 1, 'parentViewDidResize should invoke once'); SC.run(function () { view.adjust('height', 60); }); equals(callCount, 2, 'parentViewDidResize should invoke twice'); // This is tricky, if the height increases, but the same size border is added, the effective height/width is unchanged. /* Testing for this type of change on every call to adjust isn't worth the computation cost. Essentially, what we lose is that parentViewDidResize will get called still if a view happens to adjust its border and size at the same time, such that its frame doesn't change, which has a very small chance of occurring and isn't critical if it does occur. */ // SC.run(function () { view.adjust({'height': 70, 'borderTop': 10 }); }); // equals(callCount, 2, 'parentViewDidResize should invoke twice');
});
test(“The view's frame should only notify changes when its layout changes if the effective size or position actually change.”, function () {
var view2 = SC.View.create({ frameCallCount: 0, frameDidChange: function() { this.frameCallCount++; }.observes('frame'), viewDidResize: CoreTest.stub('viewDidResize', SC.View.prototype.viewDidResize) }), view1 = SC.View.create({ childViews: [view2], layout: { width: 200, height: 200 } }); // Because the view is created independently and then added to a parent, it's frame should change // once when added to the parent. equals(view2.get('frameCallCount'), 1, 'frame should have notified changing once.'); SC.run(function () { view2.set('layout', { height: 50, width: 50 }); }); equals(view2.get('frameCallCount'), 2, 'frame should have notified changing twice.'); SC.run(function () { view2.adjust('top', 0); }); equals(view2.get('frameCallCount'), 3, 'frame should have notified changing thrice.'); SC.run(function () { view2.adjust('height', 100); }); equals(view2.get('frameCallCount'), 4, 'frame should have notified changing four times.'); // Tricky. SC.run(function () { view2.adjust({ 'height': 110, 'borderTop': 10, 'top': -10 }); }); equals(view2.get('frameCallCount'), 5, 'frame should have notified changing five times.'); SC.run(function () { view2.adjust('width', null); }); equals(view2.get('frameCallCount'), 6, 'frame should have notified changing six times.'); // Tricky. SC.run(function () { view2.adjust('width', 200); }); equals(view2.get('frameCallCount'), 7, 'frame should have notified changing seven times.');
});
test(“making sure that the frame value is correct inside viewDidResize()”, function() {
// We want to test to be sure that when the view's viewDidResize() method is // called, its frame has been updated. But rather than run the test inside // the method itself, we'll cache a global reference to the then-current // value and test it later. var cachedFrame; var view = SC.View.create({ layout: { left:0, top:0, width:400, height:400 }, viewDidResize: function() { sc_super(); // Set a global reference to my frame at this point so that we can // test for the correct value later. cachedFrame = this.get('frame'); } }); // Access the frame once before resizing the view, to make sure that the // previous value was cached. That way, when we ask for the frame again // after the resize, we can verify that the cache invalidation logic is // working correctly. var originalFrame = view.get('frame'); SC.RunLoop.begin(); view.adjust('height', 314); SC.RunLoop.end(); // Now that we've adjusted the view, the cached view (as it was inside its // viewDidResize() method) should be the same value, because the cached // 'frame' value should have been invalidated by that point. same(view.get('frame').height, cachedFrame.height, 'height');
});
// .….….….….….….….….….….….….….….. // parentViewDidResize() // module(“SC.View#parentViewDidResize”);
test(“When parentViewDidResize is called on a view, it should only notify on frame and cascade the call to child views if it will be affected by the parent's resize.”, function() {
var view = SC.View.create({ // instrument... frameCallCount: 0, frameDidChange: function() { this.frameCallCount++; }.observes('frame'), viewDidResize: CoreTest.stub('viewDidResize', SC.View.prototype.viewDidResize) }), parentView = SC.View.create({ childViews: [view], layout: { height: 100, width: 100 } }); // try with fixed layout SC.run(function () { view.set('layout', { top: 10, left: 10, height: 10, width: 10 }); view.viewDidResize.reset(); view.frameCallCount = 0; parentView.adjust({ width: 90, height: 90 }); }); view.viewDidResize.expect(0, "Should not notify view resize with fixed position and fixed size"); equals(view.frameCallCount, 0, 'Should not notify frame changed with fixed position and fixed size.'); // Try with flexible height SC.run(function () { view.set('layout', { top: 10, left: 10, bottom: 10, width: 10 }); // Adjust height. view.viewDidResize.reset(); view.frameCallCount = 0; parentView.adjust({ height: 80 }); }); view.viewDidResize.expect(1, "View with fixed width and flexible height SHOULD resize when parent's height is adjusted"); equals(view.frameCallCount, 1, "Adjusting parent's height SHOULD notify frame with fixed position, fixed width and flexible height"); // Adjust width. view.viewDidResize.reset(); view.frameCallCount = 0; SC.run(function () { parentView.adjust({ width: 80 }); }); view.viewDidResize.expect(0, "View with fixed width and flexible height should NOT resize when parent's width is adjusted"); equals(view.frameCallCount, 0, "Adjusting parent's width should NOT notify frame with fixed position, fixed width and flexible height"); // Adjust both. view.viewDidResize.reset(); view.frameCallCount = 0; SC.run(function () { parentView.adjust({ width: 90, height: 90 }); }); view.viewDidResize.expect(1, "View with fixed width and flexible height SHOULD resize when parent's height and width are adjusted"); equals(view.frameCallCount, 1, "Adjusting parent's height and width SHOULD notify frame with fixed position, fixed width and flexible height"); // try with flexible width SC.run(function () { view.set('layout', { top: 10, left: 10, height: 10, right: 10 }); // Adjust height. view.viewDidResize.reset(); view.frameCallCount = 0; parentView.adjust({ height: 80 }); }); view.viewDidResize.expect(0, "View with flexible width and fixed height should NOT resize when parent's height is adjusted"); equals(view.frameCallCount, 0, "Adjusting parent's height should NOT notify frame with fixed position, flexible width and fixed height"); // Adjust width. view.viewDidResize.reset(); view.frameCallCount = 0; SC.run(function () { parentView.adjust({ width: 80 }); }); view.viewDidResize.expect(1, "View with flexible width and fixed height SHOULD resize when parent's width is adjusted"); equals(view.frameCallCount, 1, "Adjusting parent's width SHOULD notify frame with fixed position, flexible width and fixed height"); // Adjust both. view.viewDidResize.reset(); view.frameCallCount = 0; SC.run(function () { parentView.adjust({ width: 90, height: 90 }); }); view.viewDidResize.expect(1, "View with flexible width and fixed height SHOULD resize when parent's height and width are adjusted"); equals(view.frameCallCount, 1, "Adjusting parent's height and width SHOULD notify frame with fixed position, flexible width and fixed height"); // try with right align SC.run(function () { view.set('layout', { top: 10, right: 10, height: 10, width: 10 }); view.viewDidResize.reset(); view.frameCallCount = 0; parentView.adjust({ width: 60, height: 60 }); }); view.viewDidResize.expect(0); equals(view.frameCallCount, 1, 'right align: should notify frame changed when isFixedPosition: %@ and isFixedSize: %@'.fmt(view.get('isFixedPosition'), view.get('isFixedSize'))); // try with bottom align SC.run(function () { view.set('layout', { left: 10, bottom: 10, height: 10, width: 10 }); view.viewDidResize.reset(); view.frameCallCount = 0; parentView.adjust({ width: 50, height: 50 }); }); view.viewDidResize.expect(0); equals(view.frameCallCount, 1, 'bottom align: should notify frame changed when isFixedPosition: %@ and isFixedSize: %@'.fmt(view.get('isFixedPosition'), view.get('isFixedSize'))); // try with center horizontal align SC.run(function () { view.set('layout', { centerX: 10, top: 10, height: 10, width: 10 }); view.viewDidResize.reset(); view.frameCallCount = 0; parentView.adjust({ width: 40, height: 40 }); }); view.viewDidResize.expect(0); equals(view.frameCallCount, 1, 'centerX: should notify frame changed when isFixedPosition: %@ and isFixedSize: %@'.fmt(view.get('isFixedPosition'), view.get('isFixedSize'))); // try with center vertical align SC.run(function () { view.set('layout', { left: 10, centerY: 10, height: 10, width: 10 }); view.viewDidResize.reset(); view.frameCallCount = 0; parentView.adjust({ width: 30, height: 30 }); }); view.viewDidResize.expect(0); equals(view.frameCallCount, 1, 'centerY: should notify frame changed when isFixedPosition: %@ and isFixedSize: %@'.fmt(view.get('isFixedPosition'), view.get('isFixedSize')));
});
// .….….….….….….….….….….….….….….. // beginLiveResize() // module(“SC.View#beginLiveResize”);
test(“invokes willBeginLiveResize on receiver and any child views that implement it”, function() {
var callCount = 0; var ChildView = SC.View.extend({ willBeginLiveResize: function() { callCount++ ;} }); var view = ChildView.create({ // <-- has callback childViews: [SC.View.extend({ // <-- this does not implement callback childViews: [ChildView] // <-- has callback })] }); callCount = 0 ; view.beginLiveResize(); equals(callCount, 2, 'should invoke willBeginLiveResize when implemented');
});
test(“returns receiver”, function() {
var view = SC.View.create(); equals(view.beginLiveResize(), view, 'returns receiver');
});
// .….….….….….….….….….….….….….….. // endLiveResize() // module(“SC.View#endLiveResize”);
test(“invokes didEndLiveResize on receiver and any child views that implement it”, function() {
var callCount = 0; var ChildView = SC.View.extend({ didEndLiveResize: function() { callCount++; } }); var view = ChildView.create({ // <-- has callback childViews: [SC.View.extend({ // <-- this does not implement callback childViews: [ChildView] // <-- has callback })] }); callCount = 0 ; view.endLiveResize(); equals(callCount, 2, 'should invoke didEndLiveResize when implemented');
});
test(“returns receiver”, function() {
var view = SC.View.create(); equals(view.endLiveResize(), view, 'returns receiver');
});