From 1d180297e6927096e35a99b8951b1096caa3ee2d Mon Sep 17 00:00:00 2001 From: Thodoris Greasidis Date: Sun, 31 Aug 2014 22:30:32 +0300 Subject: [PATCH 1/5] fix(sortable): clear ui.item.sortable properties after drag stop --- src/sortable.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/sortable.js b/src/sortable.js index 3353f9d..1a22667 100644 --- a/src/sortable.js +++ b/src/sortable.js @@ -33,6 +33,10 @@ angular.module('ui.sortable', []) return (/left|right/).test(item.css('float')) || (/inline|table-cell/).test(item.css('display')); } + function afterStop(e, ui) { + ui.item.sortable._destroy(); + } + var opts = {}; // directive specific options @@ -95,7 +99,14 @@ angular.module('ui.sortable', []) return !!ui.item.sortable._isCustomHelperUsed; }, _isCanceled: false, - _isCustomHelperUsed: ui.item.sortable._isCustomHelperUsed + _isCustomHelperUsed: ui.item.sortable._isCustomHelperUsed, + _destroy: function () { + for (var key in ui.item.sortable) { + if (ui.item.sortable.hasOwnProperty(key)) { + ui.item.sortable[key] = undefined; + } + } + } }; }; @@ -262,6 +273,8 @@ angular.module('ui.sortable', []) // call apply after stop value = combineCallbacks( value, function() { scope.$apply(); }); + + value = combineCallbacks(value, afterStop); } // wrap the callback value = combineCallbacks(callbacks[key], value); @@ -277,6 +290,9 @@ angular.module('ui.sortable', []) angular.forEach(callbacks, function(value, key) { opts[key] = combineCallbacks(value, opts[key]); + if( key === 'stop' ){ + opts[key] = combineCallbacks(opts[key], afterStop); + } }); } else { From 14ae8da4ab984e5f9e4e970feec8e61ce3f8a302 Mon Sep 17 00:00:00 2001 From: Thodoris Greasidis Date: Sun, 31 Aug 2014 23:22:17 +0300 Subject: [PATCH 2/5] test(sortable): add tests for ui.item.sortable proper destruction --- test/sortable.e2e.callbacks.spec.js | 58 ++++++++++++++++++++- test/sortable.e2e.multi.spec.js | 80 ++++++++++++++++++++++++++++- test/sortable.test-helper.js | 12 ++++- 3 files changed, 147 insertions(+), 3 deletions(-) diff --git a/test/sortable.e2e.callbacks.spec.js b/test/sortable.e2e.callbacks.spec.js index 3902792..ec49f62 100644 --- a/test/sortable.e2e.callbacks.spec.js +++ b/test/sortable.e2e.callbacks.spec.js @@ -6,11 +6,12 @@ describe('uiSortable', function() { beforeEach(module('ui.sortable')); beforeEach(module('ui.sortable.testHelper')); - var EXTRA_DY_PERCENTAGE, listContent; + var EXTRA_DY_PERCENTAGE, listContent, hasUndefinedProperties; beforeEach(inject(function (sortableTestHelper) { EXTRA_DY_PERCENTAGE = sortableTestHelper.EXTRA_DY_PERCENTAGE; listContent = sortableTestHelper.listContent; + hasUndefinedProperties = sortableTestHelper.hasUndefinedProperties; })); describe('Callbacks related', function() { @@ -188,6 +189,61 @@ describe('uiSortable', function() { }); }); + it('should properly free ui.item.sortable object', function() { + inject(function($compile, $rootScope) { + var element, uiItem, uiItemSortable_Destroy; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + start: function (e, ui) { + uiItem = ui.item; + spyOn(ui.item.sortable, '_destroy').andCallThrough(); + uiItemSortable_Destroy = ui.item.sortable._destroy; + }, + update: function(e, ui) { + if (ui.item.scope().item === 'Two') { + ui.item.sortable.cancel(); + } + } + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find(':eq(1)'); + var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Two', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + expect(uiItemSortable_Destroy).toHaveBeenCalled(); + expect(hasUndefinedProperties(uiItem.sortable)).toBe(true); + uiItem = uiItemSortable_Destroy = undefined; + + + li = element.find(':eq(0)'); + dy = (2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'Three', 'One']); + expect($rootScope.items).toEqual(listContent(element)); + expect(uiItemSortable_Destroy).toHaveBeenCalled(); + expect(hasUndefinedProperties(uiItem.sortable)).toBe(true); + uiItem = uiItemSortable_Destroy = undefined; + + + li = element.find(':eq(2)'); + dy = -(2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Two', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + expect(uiItemSortable_Destroy).toHaveBeenCalled(); + expect(hasUndefinedProperties(uiItem.sortable)).toBe(true); + uiItem = uiItemSortable_Destroy = undefined; + + $(element).remove(); + }); + }); + }); }); \ No newline at end of file diff --git a/test/sortable.e2e.multi.spec.js b/test/sortable.e2e.multi.spec.js index 860d349..7343276 100644 --- a/test/sortable.e2e.multi.spec.js +++ b/test/sortable.e2e.multi.spec.js @@ -6,13 +6,14 @@ describe('uiSortable', function() { beforeEach(module('ui.sortable')); beforeEach(module('ui.sortable.testHelper')); - var EXTRA_DY_PERCENTAGE, listContent, listInnerContent, simulateElementDrag; + var EXTRA_DY_PERCENTAGE, listContent, listInnerContent, simulateElementDrag, hasUndefinedProperties; beforeEach(inject(function (sortableTestHelper) { EXTRA_DY_PERCENTAGE = sortableTestHelper.EXTRA_DY_PERCENTAGE; listContent = sortableTestHelper.listContent; listInnerContent = sortableTestHelper.listInnerContent; simulateElementDrag = sortableTestHelper.simulateElementDrag; + hasUndefinedProperties = sortableTestHelper.hasUndefinedProperties; })); describe('Multiple sortables related', function() { @@ -470,6 +471,83 @@ describe('uiSortable', function() { }); }); + it('should properly free ui.item.sortable object', function() { + inject(function($compile, $rootScope) { + var elementTop, elementBottom, uiItem, uiItemSortable_Destroy; + elementTop = $compile('')($rootScope); + elementBottom = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.itemsTop = ['Top One', 'Top Two', 'Top Three']; + $rootScope.itemsBottom = ['Bottom One', 'Bottom Two', 'Bottom Three']; + $rootScope.opts = { + connectWith: '.cross-sortable', + start: function (e, ui) { + uiItem = ui.item; + spyOn(ui.item.sortable, '_destroy').andCallThrough(); + uiItemSortable_Destroy = ui.item.sortable._destroy; + }, + update: function(e, ui) { + uiItem.sortable = ui.item.sortable; + if (ui.item.scope() && + (typeof ui.item.scope().item === 'string') && + ui.item.scope().item.indexOf('Two') >= 0) { + ui.item.sortable.cancel(); + } + } + }; + }); + + host.append(elementTop).append(elementBottom).append('
'); + + var li1 = elementTop.find(':eq(1)'); + var li2 = elementBottom.find(':eq(0)'); + simulateElementDrag(li1, li2, 'below'); + expect($rootScope.itemsTop).toEqual(['Top One', 'Top Two', 'Top Three']); + expect($rootScope.itemsBottom).toEqual(['Bottom One', 'Bottom Two', 'Bottom Three']); + expect($rootScope.itemsTop).toEqual(listContent(elementTop)); + expect($rootScope.itemsBottom).toEqual(listContent(elementBottom)); + expect(uiItemSortable_Destroy).toHaveBeenCalled(); + expect(hasUndefinedProperties(uiItem.sortable)).toBe(true); + uiItem = uiItemSortable_Destroy = undefined; + + li1 = elementBottom.find(':eq(1)'); + li2 = elementTop.find(':eq(1)'); + simulateElementDrag(li1, li2, { place: 'above', extradx: -20, extrady: -10 }); + expect($rootScope.itemsTop).toEqual(['Top One', 'Top Two', 'Top Three']); + expect($rootScope.itemsBottom).toEqual(['Bottom One', 'Bottom Two', 'Bottom Three']); + expect($rootScope.itemsTop).toEqual(listContent(elementTop)); + expect($rootScope.itemsBottom).toEqual(listContent(elementBottom)); + expect(uiItemSortable_Destroy).toHaveBeenCalled(); + expect(hasUndefinedProperties(uiItem.sortable)).toBe(true); + uiItem = uiItemSortable_Destroy = undefined; + + li1 = elementTop.find(':eq(0)'); + li2 = elementBottom.find(':eq(0)'); + simulateElementDrag(li1, li2, 'below'); + expect($rootScope.itemsTop).toEqual(['Top Two', 'Top Three']); + expect($rootScope.itemsBottom).toEqual(['Bottom One', 'Top One', 'Bottom Two', 'Bottom Three']); + expect($rootScope.itemsTop).toEqual(listContent(elementTop)); + expect($rootScope.itemsBottom).toEqual(listContent(elementBottom)); + expect(uiItemSortable_Destroy).toHaveBeenCalled(); + expect(hasUndefinedProperties(uiItem.sortable)).toBe(true); + uiItem = uiItemSortable_Destroy = undefined; + + li1 = elementBottom.find(':eq(1)'); + li2 = elementTop.find(':eq(1)'); + simulateElementDrag(li1, li2, { place: 'above', extradx: -20, extrady: -10 }); + expect($rootScope.itemsTop).toEqual(['Top Two', 'Top One', 'Top Three']); + expect($rootScope.itemsBottom).toEqual(['Bottom One', 'Bottom Two', 'Bottom Three']); + expect($rootScope.itemsTop).toEqual(listContent(elementTop)); + expect($rootScope.itemsBottom).toEqual(listContent(elementBottom)); + expect(uiItemSortable_Destroy).toHaveBeenCalled(); + expect(hasUndefinedProperties(uiItem.sortable)).toBe(true); + uiItem = uiItemSortable_Destroy = undefined; + + $(elementTop).remove(); + $(elementBottom).remove(); + }); + }); + }); }); \ No newline at end of file diff --git a/test/sortable.test-helper.js b/test/sortable.test-helper.js index 2b5bf90..4da4d45 100644 --- a/test/sortable.test-helper.js +++ b/test/sortable.test-helper.js @@ -62,10 +62,20 @@ angular.module('ui.sortable.testHelper', []) draggedElement.simulate('drag', dragOptions); } + function hasUndefinedProperties(testObject) { + return testObject && Object.keys(testObject) + .filter(function(key) { + return testObject.hasOwnProperty(key) && + testObject[key] !== undefined; + }) + .length === 0; + } + return { EXTRA_DY_PERCENTAGE: EXTRA_DY_PERCENTAGE, listContent: listContent, listInnerContent: listInnerContent, - simulateElementDrag: simulateElementDrag + simulateElementDrag: simulateElementDrag, + hasUndefinedProperties: hasUndefinedProperties }; }); From d777fef79f39fbd00672523a2d5aa69e663b26b6 Mon Sep 17 00:00:00 2001 From: Thodoris Greasidis Date: Thu, 4 Sep 2014 00:59:52 +0300 Subject: [PATCH 3/5] refactor(sortable): replace for-in-hasOwnProperty with angular.forEach This also brings code coverage back to 100%. --- src/sortable.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sortable.js b/src/sortable.js index 1a22667..cc42504 100644 --- a/src/sortable.js +++ b/src/sortable.js @@ -101,11 +101,9 @@ angular.module('ui.sortable', []) _isCanceled: false, _isCustomHelperUsed: ui.item.sortable._isCustomHelperUsed, _destroy: function () { - for (var key in ui.item.sortable) { - if (ui.item.sortable.hasOwnProperty(key)) { - ui.item.sortable[key] = undefined; - } - } + angular.forEach(ui.item.sortable, function(value, key) { + ui.item.sortable[key] = undefined; + }); } }; }; From ff25513446f0fee6adfe85e7d3a2d794eb0e5f33 Mon Sep 17 00:00:00 2001 From: Thodoris Greasidis Date: Thu, 4 Sep 2014 01:38:03 +0300 Subject: [PATCH 4/5] feat(sortable): add extra properties to ui.item.sortable --- src/sortable.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/sortable.js b/src/sortable.js index cc42504..7eb5e39 100644 --- a/src/sortable.js +++ b/src/sortable.js @@ -88,7 +88,10 @@ angular.module('ui.sortable', []) // Save the starting position of dragged item ui.item.sortable = { + model: ngModel.$modelValue[ui.item.index()], index: ui.item.index(), + source: ui.item.parent(), + sourceModel: ngModel.$modelValue, cancel: function () { ui.item.sortable._isCanceled = true; }, @@ -145,7 +148,9 @@ angular.module('ui.sortable', []) // the value will be overwritten with the old value if(!ui.item.sortable.received) { ui.item.sortable.dropindex = ui.item.index(); - ui.item.sortable.droptarget = ui.item.parent(); + var droptarget = ui.item.parent(); + ui.item.sortable.droptarget = droptarget; + ui.item.sortable.droptargetModel = droptarget.scope().$eval(droptarget.attr('ng-model')); // Cancel the sort (let ng-repeat do the sort for us) // Don't cancel if this is the received list because it has From 3a845c53ad2502fd6935db1be0b8ad4e1b236c21 Mon Sep 17 00:00:00 2001 From: Thodoris Greasidis Date: Fri, 5 Sep 2014 00:10:09 +0300 Subject: [PATCH 5/5] tests(sortable): add tests for the properties of ui.item.sortable --- test/sortable.e2e.callbacks.spec.js | 72 ++++++++++++++ test/sortable.e2e.multi.spec.js | 139 ++++++++++++++++++++++++++++ 2 files changed, 211 insertions(+) diff --git a/test/sortable.e2e.callbacks.spec.js b/test/sortable.e2e.callbacks.spec.js index ec49f62..5be87d7 100644 --- a/test/sortable.e2e.callbacks.spec.js +++ b/test/sortable.e2e.callbacks.spec.js @@ -189,6 +189,78 @@ describe('uiSortable', function() { }); }); + it('should properly set ui.item.sortable properties', function() { + inject(function($compile, $rootScope) { + var element, updateCallbackExpectations; + element = $compile('
  • {{ item }}
')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + update: function(e, ui) { + if (ui.item.scope().item === 'Two') { + ui.item.sortable.cancel(); + } + updateCallbackExpectations(ui.item.sortable); + } + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + $rootScope.$apply(function() { + }); + var li = element.find(':eq(1)'); + var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + updateCallbackExpectations = function(uiItemSortable) { + expect(uiItemSortable.model).toEqual('Two'); + expect(uiItemSortable.index).toEqual(1); + expect(uiItemSortable.source.length).toEqual(1); + expect(uiItemSortable.source[0]).toBe(host.children()[0]); + expect(uiItemSortable.sourceModel).toBe($rootScope.items); + expect(uiItemSortable.isCanceled()).toBe(true); + expect(uiItemSortable.isCustomHelperUsed()).toBe(false); + }; + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Two', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + updateCallbackExpectations = undefined; + + li = element.find(':eq(0)'); + dy = (2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + updateCallbackExpectations = function(uiItemSortable) { + expect(uiItemSortable.model).toEqual('One'); + expect(uiItemSortable.index).toEqual(0); + expect(uiItemSortable.source.length).toEqual(1); + expect(uiItemSortable.source[0]).toBe(host.children()[0]); + expect(uiItemSortable.sourceModel).toBe($rootScope.items); + expect(uiItemSortable.isCanceled()).toBe(false); + expect(uiItemSortable.isCustomHelperUsed()).toBe(false); + }; + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'Three', 'One']); + expect($rootScope.items).toEqual(listContent(element)); + updateCallbackExpectations = undefined; + + li = element.find(':eq(2)'); + dy = -(2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + updateCallbackExpectations = function(uiItemSortable) { + expect(uiItemSortable.model).toEqual('One'); + expect(uiItemSortable.index).toEqual(2); + expect(uiItemSortable.source.length).toEqual(1); + expect(uiItemSortable.source[0]).toBe(host.children()[0]); + expect(uiItemSortable.sourceModel).toBe($rootScope.items); + expect(uiItemSortable.isCanceled()).toBe(false); + expect(uiItemSortable.isCustomHelperUsed()).toBe(false); + }; + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Two', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + updateCallbackExpectations = undefined; + + $(element).remove(); + }); + }); + it('should properly free ui.item.sortable object', function() { inject(function($compile, $rootScope) { var element, uiItem, uiItemSortable_Destroy; diff --git a/test/sortable.e2e.multi.spec.js b/test/sortable.e2e.multi.spec.js index 7343276..a9cebae 100644 --- a/test/sortable.e2e.multi.spec.js +++ b/test/sortable.e2e.multi.spec.js @@ -471,6 +471,145 @@ describe('uiSortable', function() { }); }); + it('should properly set ui.item.sortable properties', function() { + inject(function($compile, $rootScope) { + var elementTop, elementBottom, updateCallbackExpectations, stopCallbackExpectations; + elementTop = $compile('
  • {{ item }}
')($rootScope); + elementBottom = $compile('
  • {{ item }}
')($rootScope); + $rootScope.$apply(function() { + $rootScope.itemsTop = ['Top One', 'Top Two', 'Top Three']; + $rootScope.itemsBottom = ['Bottom One', 'Bottom Two', 'Bottom Three']; + $rootScope.opts = { + connectWith: '.cross-sortable', + update: function(e, ui) { + if (ui.item.scope() && + (typeof ui.item.scope().item === 'string') && + ui.item.scope().item.indexOf('Two') >= 0) { + ui.item.sortable.cancel(); + } + updateCallbackExpectations(ui.item.sortable); + }, + stop: function(e, ui) { + stopCallbackExpectations(ui.item.sortable); + } + }; + }); + + host.append(elementTop).append(elementBottom).append('
'); + + var li1 = elementTop.find(':eq(1)'); + var li2 = elementBottom.find(':eq(0)'); + updateCallbackExpectations = function(uiItemSortable) { + expect(uiItemSortable.model).toEqual('Top Two'); + expect(uiItemSortable.index).toEqual(1); + expect(uiItemSortable.source.length).toEqual(1); + expect(uiItemSortable.source[0]).toBe(host.children()[0]); + expect(uiItemSortable.sourceModel).toBe($rootScope.itemsTop); + expect(uiItemSortable.isCanceled()).toBe(true); + expect(uiItemSortable.isCustomHelperUsed()).toBe(false); + + expect(uiItemSortable.dropindex).toEqual(1); + expect(uiItemSortable.droptarget.length).toBe(1); + expect(uiItemSortable.droptarget[0]).toBe(host.children()[1]); + expect(uiItemSortable.droptargetModel).toBe($rootScope.itemsBottom); + }; + stopCallbackExpectations = function(uiItemSortable) { + expect(uiItemSortable.received).toBe(true); + expect(uiItemSortable.moved).toBe(undefined); + }; + simulateElementDrag(li1, li2, { place: 'below', extradx: -20, extrady: -10 }); + expect($rootScope.itemsTop).toEqual(['Top One', 'Top Two', 'Top Three']); + expect($rootScope.itemsBottom).toEqual(['Bottom One', 'Bottom Two', 'Bottom Three']); + expect($rootScope.itemsTop).toEqual(listContent(elementTop)); + expect($rootScope.itemsBottom).toEqual(listContent(elementBottom)); + updateCallbackExpectations = stopCallbackExpectations = undefined; + + li1 = elementBottom.find(':eq(1)'); + li2 = elementTop.find(':eq(1)'); + updateCallbackExpectations = function(uiItemSortable) { + expect(uiItemSortable.model).toEqual('Bottom Two'); + expect(uiItemSortable.index).toEqual(1); + expect(uiItemSortable.source.length).toEqual(1); + expect(uiItemSortable.source[0]).toBe(host.children()[1]); + expect(uiItemSortable.sourceModel).toBe($rootScope.itemsBottom); + expect(uiItemSortable.isCanceled()).toBe(true); + expect(uiItemSortable.isCustomHelperUsed()).toBe(false); + + expect(uiItemSortable.dropindex).toEqual(1); + expect(uiItemSortable.droptarget.length).toBe(1); + expect(uiItemSortable.droptarget[0]).toBe(host.children()[0]); + expect(uiItemSortable.droptargetModel).toBe($rootScope.itemsTop); + }; + stopCallbackExpectations = function(uiItemSortable) { + expect(uiItemSortable.received).toBe(true); + expect(uiItemSortable.moved).toBe(undefined); + }; + simulateElementDrag(li1, li2, { place: 'above', extradx: -20, extrady: -10 }); + expect($rootScope.itemsTop).toEqual(['Top One', 'Top Two', 'Top Three']); + expect($rootScope.itemsBottom).toEqual(['Bottom One', 'Bottom Two', 'Bottom Three']); + expect($rootScope.itemsTop).toEqual(listContent(elementTop)); + expect($rootScope.itemsBottom).toEqual(listContent(elementBottom)); + updateCallbackExpectations = stopCallbackExpectations = undefined; + + li1 = elementTop.find(':eq(0)'); + li2 = elementBottom.find(':eq(0)'); + updateCallbackExpectations = function(uiItemSortable) { + expect(uiItemSortable.model).toEqual('Top One'); + expect(uiItemSortable.index).toEqual(0); + expect(uiItemSortable.source.length).toEqual(1); + expect(uiItemSortable.source[0]).toBe(host.children()[0]); + expect(uiItemSortable.sourceModel).toBe($rootScope.itemsTop); + expect(uiItemSortable.isCanceled()).toBe(false); + expect(uiItemSortable.isCustomHelperUsed()).toBe(false); + + expect(uiItemSortable.dropindex).toEqual(1); + expect(uiItemSortable.droptarget.length).toBe(1); + expect(uiItemSortable.droptarget[0]).toBe(host.children()[1]); + expect(uiItemSortable.droptargetModel).toBe($rootScope.itemsBottom); + }; + stopCallbackExpectations = function(uiItemSortable) { + expect(uiItemSortable.received).toBe(true); + expect(uiItemSortable.moved).toBe('Top One'); + }; + simulateElementDrag(li1, li2, 'below'); + expect($rootScope.itemsTop).toEqual(['Top Two', 'Top Three']); + expect($rootScope.itemsBottom).toEqual(['Bottom One', 'Top One', 'Bottom Two', 'Bottom Three']); + expect($rootScope.itemsTop).toEqual(listContent(elementTop)); + expect($rootScope.itemsBottom).toEqual(listContent(elementBottom)); + updateCallbackExpectations = stopCallbackExpectations = undefined; + + li1 = elementBottom.find(':eq(1)'); + li2 = elementTop.find(':eq(1)'); + updateCallbackExpectations = function(uiItemSortable) { + expect(uiItemSortable.model).toEqual('Top One'); + expect(uiItemSortable.index).toEqual(1); + expect(uiItemSortable.source.length).toEqual(1); + expect(uiItemSortable.source[0]).toBe(host.children()[1]); + expect(uiItemSortable.sourceModel).toBe($rootScope.itemsBottom); + expect(uiItemSortable.isCanceled()).toBe(false); + expect(uiItemSortable.isCustomHelperUsed()).toBe(false); + + expect(uiItemSortable.dropindex).toEqual(1); + expect(uiItemSortable.droptarget.length).toBe(1); + expect(uiItemSortable.droptarget[0]).toBe(host.children()[0]); + expect(uiItemSortable.droptargetModel).toBe($rootScope.itemsTop); + }; + stopCallbackExpectations = function(uiItemSortable) { + expect(uiItemSortable.received).toBe(true); + expect(uiItemSortable.moved).toBe('Top One'); + }; + simulateElementDrag(li1, li2, { place: 'above', extradx: -20, extrady: -10 }); + expect($rootScope.itemsTop).toEqual(['Top Two', 'Top One', 'Top Three']); + expect($rootScope.itemsBottom).toEqual(['Bottom One', 'Bottom Two', 'Bottom Three']); + expect($rootScope.itemsTop).toEqual(listContent(elementTop)); + expect($rootScope.itemsBottom).toEqual(listContent(elementBottom)); + updateCallbackExpectations = stopCallbackExpectations = undefined; + + $(elementTop).remove(); + $(elementBottom).remove(); + }); + }); + it('should properly free ui.item.sortable object', function() { inject(function($compile, $rootScope) { var elementTop, elementBottom, uiItem, uiItemSortable_Destroy;