From 8ec7b039062e5cf5ec805d5c7114698d6c8c9f9c Mon Sep 17 00:00:00 2001 From: Tom Yam Date: Thu, 26 Mar 2015 17:00:49 +0200 Subject: [PATCH 1/2] feat(sortable): allow extra element before/after ng-repeat Fixes #41, Fixed #177, Fixed #98 and Fixes #207 --- src/sortable.js | 26 +- test/sortable.e2e.extraElements.spec.js | 716 ++++++++++++++++++++++++ test/sortable.spec.js | 89 +++ test/sortable.test-helper.js | 2 +- 4 files changed, 828 insertions(+), 5 deletions(-) create mode 100644 test/sortable.e2e.extraElements.spec.js diff --git a/src/sortable.js b/src/sortable.js index 94077dc..ffc27ea 100644 --- a/src/sortable.js +++ b/src/sortable.js @@ -63,7 +63,20 @@ angular.module('ui.sortable', []) ui.item.sortable._destroy(); } - var opts = {}; + // return the index of ui.item among the items + // we can't just do ui.item.index() because there it might have siblings + // which are not items + function getItemIndex(ui) { + return ui.item.parent().find('> [ng-repeat],> [data-ng-repeat],> [x-ng-repeat]') + .index(ui.item); + } + + var opts = { + // the default for jquery-ui sortable is "> *", we need to restrict this to + // ng-repeat items + // if the user uses + items: '> [ng-repeat],> [data-ng-repeat],> [x-ng-repeat]' + }; // directive specific options var directiveOpts = { @@ -114,9 +127,10 @@ angular.module('ui.sortable', []) } // Save the starting position of dragged item + var index = getItemIndex(ui); ui.item.sortable = { - model: ngModel.$modelValue[ui.item.index()], - index: ui.item.index(), + model: ngModel.$modelValue[index], + index: index, source: ui.item.parent(), sourceModel: ngModel.$modelValue, cancel: function () { @@ -184,7 +198,7 @@ angular.module('ui.sortable', []) // update that happens when moving between lists because then // the value will be overwritten with the old value if(!ui.item.sortable.received) { - ui.item.sortable.dropindex = ui.item.index(); + ui.item.sortable.dropindex = getItemIndex(ui); var droptarget = ui.item.parent(); ui.item.sortable.droptarget = droptarget; @@ -325,6 +339,10 @@ angular.module('ui.sortable', []) value = wrappers[key](value); } + if (key === 'items' && !value) { + value = '> [ng-repeat],> [data-ng-repeat],> [x-ng-repeat]'; + } + opts[key] = value; element.sortable('option', key, value); }); diff --git a/test/sortable.e2e.extraElements.spec.js b/test/sortable.e2e.extraElements.spec.js new file mode 100644 index 0000000..3e36421 --- /dev/null +++ b/test/sortable.e2e.extraElements.spec.js @@ -0,0 +1,716 @@ +'use strict'; + +describe('uiSortable', function() { + + beforeEach(module(function($compileProvider) { + if (typeof $compileProvider.debugInfoEnabled === 'function') { + $compileProvider.debugInfoEnabled(false); + } + })); + + // Ensure the sortable angular module is loaded + beforeEach(module('ui.sortable')); + beforeEach(module('ui.sortable.testHelper')); + + var EXTRA_DY_PERCENTAGE, listContent, listInnerContent; + + beforeEach(inject(function (sortableTestHelper) { + EXTRA_DY_PERCENTAGE = sortableTestHelper.EXTRA_DY_PERCENTAGE; + listContent = sortableTestHelper.listContent; + listInnerContent = sortableTestHelper.listInnerContent; + })); + + describe('Drag & Drop simulation, when there are extra elements', function() { + + var host; + + beforeEach(inject(function() { + host = $('
'); + $('body').append(host); + })); + + afterEach(function() { + host.remove(); + host = null; + }); + + it('should update model when order changes', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find(':eq(2)'); + var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Three', 'Two']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = -(1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Three', 'One', 'Two']); + expect($rootScope.items).toEqual(listContent(element)); + + $(element).remove(); + }); + }); + + it('should not allow sorting of "locked" nodes', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + items:'> .sortable' + }; + $rootScope.items = [ + { text: 'One', sortable: true }, + { text: 'Two', sortable: true }, + { text: 'Three', sortable: false }, + { text: 'Four', sortable: true } + ]; + }); + + host.append(element); + + var li = element.find(':eq(3)'); + var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items.map(function(x){ return x.text; })).toEqual(['One', 'Two', 'Three', 'Four']); + expect($rootScope.items.map(function(x){ return x.text; })).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items.map(function(x){ return x.text; })).toEqual(['One', 'Three', 'Four', 'Two']); + expect($rootScope.items.map(function(x){ return x.text; })).toEqual(listContent(element)); + + li = element.find(':eq(3)'); + dy = -(2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items.map(function(x){ return x.text; })).toEqual(['Four', 'One', 'Three', 'Two']); + expect($rootScope.items.map(function(x){ return x.text; })).toEqual(listContent(element)); + + li = element.find(':eq(4)'); + dy = -(2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items.map(function(x){ return x.text; })).toEqual(['Four', 'Two', 'One', 'Three']); + expect($rootScope.items.map(function(x){ return x.text; })).toEqual(listContent(element)); + + // also placing right above the locked node seems a bit harder !?!? + + $(element).remove(); + }); + }); + + it('should work when "placeholder" option is used', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + placeholder: 'sortable-item-placeholder' + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find(':eq(2)'); + var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Three', 'Two']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = -(1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Three', 'One', 'Two']); + expect($rootScope.items).toEqual(listContent(element)); + + $(element).remove(); + }); + }); + + it('should work when "placeholder" option equals the class of items', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + placeholder: 'sortable-item' + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find(':eq(2)'); + var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Three', 'Two']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = -(1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Three', 'One', 'Two']); + expect($rootScope.items).toEqual(listContent(element)); + + $(element).remove(); + }); + }); + + it('should work when "placeholder" option equals the class of items [data-ng-repeat]', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + placeholder: 'sortable-item' + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find(':eq(2)'); + var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Three', 'Two']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = -(1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Three', 'One', 'Two']); + expect($rootScope.items).toEqual(listContent(element)); + + $(element).remove(); + }); + }); + + it('should continue to work after a drag is reverted', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + placeholder: 'sortable-item' + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find(':eq(1)'); + var dy = (2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('dragAndRevert', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Two', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(1)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'One', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'Three', 'One']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'One', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + $(element).remove(); + }); + }); + + it('should work when "handle" option is used', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + handle: '.handle' + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find('li:eq(1)'); + var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.find('.handle').simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Three', 'Two']); + expect($rootScope.items).toEqual(listInnerContent(element)); + + li = element.find('li:eq(1)'); + dy = -(1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.find('.handle').simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Three', 'One', 'Two']); + expect($rootScope.items).toEqual(listInnerContent(element)); + + $(element).remove(); + }); + }); + + it('should properly remove elements after a sorting', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + handle: '.handle' + }; + $rootScope.items = ['One', 'Two', 'Three']; + + $rootScope.remove = function (item, itemIndex) { + $rootScope.items.splice(itemIndex, 1); + }; + }); + + host.append(element); + + var li = element.find('li:eq(1)'); + var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.find('.handle').simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Three', 'Two']); + expect($rootScope.items).toEqual(listInnerContent(element)); + + li = element.find('li:eq(1)'); + li.find('.removeButton').click(); + expect($rootScope.items).toEqual(['One', 'Two']); + expect($rootScope.items).toEqual(listInnerContent(element)); + + li = element.find('li:eq(0)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.find('.handle').simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'One']); + expect($rootScope.items).toEqual(listInnerContent(element)); + + li = element.find('li:eq(0)'); + li.find('.removeButton').click(); + expect($rootScope.items).toEqual(['One']); + expect($rootScope.items).toEqual(listInnerContent(element)); + + $(element).remove(); + }); + }); + + it('should properly remove elements after a drag is reverted', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + handle: '.handle' + }; + $rootScope.items = ['One', 'Two', 'Three']; + + $rootScope.remove = function (item, itemIndex) { + $rootScope.items.splice(itemIndex, 1); + }; + }); + + host.append(element); + + var li = element.find('li:eq(0)'); + var dy = (2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.find('.handle').simulate('dragAndRevert', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Two', 'Three']); + expect($rootScope.items).toEqual(listInnerContent(element)); + + li = element.find('li:eq(0)'); + li.find('.removeButton').click(); + expect($rootScope.items).toEqual(['Two', 'Three']); + expect($rootScope.items).toEqual(listInnerContent(element)); + + li = element.find('li:eq(0)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.find('.handle').simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Three', 'Two']); + expect($rootScope.items).toEqual(listInnerContent(element)); + + $(element).remove(); + }); + }); + + it('should work when "helper: clone" option is used', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + helper: 'clone' + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find(':eq(2)'); + var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Three', 'Two']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = -(1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Three', 'One', 'Two']); + expect($rootScope.items).toEqual(listContent(element)); + + $(element).remove(); + }); + }); + + it('should work when "helper: clone" option is used and a drag is reverted', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + helper: 'clone' + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find(':eq(1)'); + var dy = (2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('dragAndRevert', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Two', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(1)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'One', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'Three', 'One']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'One', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + $(element).remove(); + }); + }); + + it('should work when "helper: clone" and "appendTo" options are used together', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + helper: 'clone', + appendTo: 'body' + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find(':eq(2)'); + var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Three', 'Two']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(3)'); + 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)); + + $(element).remove(); + }); + }); + + it('should work when "helper: clone" and "placeholder" options are used together.', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + helper: 'clone', + placeholder: 'sortable-item' + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find(':eq(1)'); + var dy = (2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('dragAndRevert', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Two', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(1)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'One', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'Three', 'One']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('dragAndRevert', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'Three', 'One']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'One', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + $(element).remove(); + }); + }); + + it('should work when "helper: function" option is used', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + helper: function (e, item) { + return item.clone().text('helper'); + } + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find(':eq(2)'); + var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Three', 'Two']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = -(1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Three', 'One', 'Two']); + expect($rootScope.items).toEqual(listContent(element)); + + $(element).remove(); + }); + }); + + it('should work when "helper: function" option is used and a drag is reverted', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + helper: function (e, item) { + return item.clone().text('helper'); + } + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find(':eq(1)'); + var dy = (2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('dragAndRevert', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Two', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(1)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'One', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'Three', 'One']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'One', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + $(element).remove(); + }); + }); + + it('should work when "helper: function" and "placeholder" options are used together.', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + helper: function (e, item) { + return item.clone().text('helper'); + }, + placeholder: 'sortable-item' + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find(':eq(1)'); + var dy = (2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('dragAndRevert', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Two', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(1)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'One', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'Three', 'One']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('dragAndRevert', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'Three', 'One']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'One', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + $(element).remove(); + }); + }); + + it('should work when "helper: function" that returns a list element is used', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + helper: function (e, item) { + return item; + } + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find(':eq(1)'); + var dy = (2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('dragAndRevert', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Two', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(1)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'One', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'Three', 'One']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'One', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + $(element).remove(); + }); + }); + + it('should work when "helper: function" that returns a list element and "placeholder" options are used together.', function() { + inject(function($compile, $rootScope) { + var element; + element = $compile('')($rootScope); + $rootScope.$apply(function() { + $rootScope.opts = { + helper: function (e, item) { + return item; + }, + placeholder: 'sortable-item' + }; + $rootScope.items = ['One', 'Two', 'Three']; + }); + + host.append(element); + + var li = element.find(':eq(1)'); + var dy = (2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('dragAndRevert', { dy: dy }); + expect($rootScope.items).toEqual(['One', 'Two', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(1)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'One', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'Three', 'One']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('dragAndRevert', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'Three', 'One']); + expect($rootScope.items).toEqual(listContent(element)); + + li = element.find(':eq(2)'); + dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); + li.simulate('drag', { dy: dy }); + expect($rootScope.items).toEqual(['Two', 'One', 'Three']); + expect($rootScope.items).toEqual(listContent(element)); + + $(element).remove(); + }); + }); + + }); + +}); diff --git a/test/sortable.spec.js b/test/sortable.spec.js index fd664bd..3ce0348 100644 --- a/test/sortable.spec.js +++ b/test/sortable.spec.js @@ -179,6 +179,95 @@ describe('uiSortable', function() { }); }); + describe('items option', function() { + + it('should use a default items that is restricted to ng-repeat items', function() { + + inject(function($compile, $rootScope, $timeout) { + var element; + var childScope = $rootScope.$new(); + element = $compile('
')(childScope); + + $rootScope.$digest(); + + expect(element.find('ul').sortable('option', 'items')).toBe('> [ng-repeat],> [data-ng-repeat],> [x-ng-repeat]'); + + element.remove(element.firstChild); + + expect(function() { + $timeout.flush(); + }).not.toThrow(); + + }); + + }); + + it('should not change items option if given', function() { + + inject(function($compile, $rootScope, $timeout) { + var element; + var childScope = $rootScope.$new(); + childScope.opts = { + items: '> .class' + }; + + element = $compile('
')(childScope); + + $rootScope.$digest(); + + expect(element.find('ul').sortable('option', 'items')).toBe('> .class'); + + element.remove(element.firstChild); + + expect(function() { + $timeout.flush(); + }).not.toThrow(); + + }); + + }); + + it('should restrict to ng-items if items is removed after initialization', function() { + + inject(function($compile, $rootScope, $timeout) { + var element; + var childScope = $rootScope.$new(); + childScope.opts = { + items: '> .class' + }; + + element = $compile('
')(childScope); + + $rootScope.$digest(); + + $rootScope.$apply(function() { + childScope.opts = { items: null }; + }); + + expect(element.find('ul').sortable('option', 'items')).toBe('> [ng-repeat],> [data-ng-repeat],> [x-ng-repeat]'); + + element.remove(element.firstChild); + + expect(function() { + $timeout.flush(); + }).not.toThrow(); + + }); + + }); + + + + + + + + }); + + + + + }); }); diff --git a/test/sortable.test-helper.js b/test/sortable.test-helper.js index 5728d49..8cae026 100644 --- a/test/sortable.test-helper.js +++ b/test/sortable.test-helper.js @@ -6,7 +6,7 @@ angular.module('ui.sortable.testHelper', []) function listContent (list) { if (list && list.length) { - return list.children().map(function(){ return this.innerHTML; }).toArray(); + return list.children('[ng-repeat], [data-ng-repeat], [x-ng-repeat]').map(function(){ return this.innerHTML; }).toArray(); } return []; } From 58c6c7bbf27d41b93fd0fcacc0bba2cae447bc7b Mon Sep 17 00:00:00 2001 From: Tom Yam Date: Sat, 4 Apr 2015 18:56:53 +0300 Subject: [PATCH 2/2] test(sortable): use li elements instead of div elements for testing extra element before/after ng-repeat --- test/sortable.e2e.extraElements.spec.js | 54 ++++++++++++------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/test/sortable.e2e.extraElements.spec.js b/test/sortable.e2e.extraElements.spec.js index 3e36421..1589c5b 100644 --- a/test/sortable.e2e.extraElements.spec.js +++ b/test/sortable.e2e.extraElements.spec.js @@ -37,7 +37,7 @@ describe('uiSortable', function() { it('should update model when order changes', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.items = ['One', 'Two', 'Three']; }); @@ -63,7 +63,7 @@ describe('uiSortable', function() { it('should not allow sorting of "locked" nodes', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { items:'> .sortable' @@ -111,7 +111,7 @@ describe('uiSortable', function() { it('should work when "placeholder" option is used', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { placeholder: 'sortable-item-placeholder' @@ -140,7 +140,7 @@ describe('uiSortable', function() { it('should work when "placeholder" option equals the class of items', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { placeholder: 'sortable-item' @@ -169,7 +169,7 @@ describe('uiSortable', function() { it('should work when "placeholder" option equals the class of items [data-ng-repeat]', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { placeholder: 'sortable-item' @@ -198,7 +198,7 @@ describe('uiSortable', function() { it('should continue to work after a drag is reverted', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { placeholder: 'sortable-item' @@ -239,7 +239,7 @@ describe('uiSortable', function() { it('should work when "handle" option is used', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { handle: '.handle' @@ -249,13 +249,13 @@ describe('uiSortable', function() { host.append(element); - var li = element.find('li:eq(1)'); + var li = element.find('li:eq(2)'); var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); li.find('.handle').simulate('drag', { dy: dy }); expect($rootScope.items).toEqual(['One', 'Three', 'Two']); expect($rootScope.items).toEqual(listInnerContent(element)); - li = element.find('li:eq(1)'); + li = element.find('li:eq(2)'); dy = -(1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); li.find('.handle').simulate('drag', { dy: dy }); expect($rootScope.items).toEqual(['Three', 'One', 'Two']); @@ -268,7 +268,7 @@ describe('uiSortable', function() { it('should properly remove elements after a sorting', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { handle: '.handle' @@ -282,24 +282,24 @@ describe('uiSortable', function() { host.append(element); - var li = element.find('li:eq(1)'); + var li = element.find('li:eq(2)'); var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); li.find('.handle').simulate('drag', { dy: dy }); expect($rootScope.items).toEqual(['One', 'Three', 'Two']); expect($rootScope.items).toEqual(listInnerContent(element)); - li = element.find('li:eq(1)'); + li = element.find('li:eq(2)'); li.find('.removeButton').click(); expect($rootScope.items).toEqual(['One', 'Two']); expect($rootScope.items).toEqual(listInnerContent(element)); - li = element.find('li:eq(0)'); + li = element.find('li:eq(1)'); dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); li.find('.handle').simulate('drag', { dy: dy }); expect($rootScope.items).toEqual(['Two', 'One']); expect($rootScope.items).toEqual(listInnerContent(element)); - li = element.find('li:eq(0)'); + li = element.find('li:eq(1)'); li.find('.removeButton').click(); expect($rootScope.items).toEqual(['One']); expect($rootScope.items).toEqual(listInnerContent(element)); @@ -311,7 +311,7 @@ describe('uiSortable', function() { it('should properly remove elements after a drag is reverted', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { handle: '.handle' @@ -325,18 +325,18 @@ describe('uiSortable', function() { host.append(element); - var li = element.find('li:eq(0)'); + var li = element.find('li:eq(1)'); var dy = (2 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); li.find('.handle').simulate('dragAndRevert', { dy: dy }); expect($rootScope.items).toEqual(['One', 'Two', 'Three']); expect($rootScope.items).toEqual(listInnerContent(element)); - li = element.find('li:eq(0)'); + li = element.find('li:eq(1)'); li.find('.removeButton').click(); expect($rootScope.items).toEqual(['Two', 'Three']); expect($rootScope.items).toEqual(listInnerContent(element)); - li = element.find('li:eq(0)'); + li = element.find('li:eq(1)'); dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight(); li.find('.handle').simulate('drag', { dy: dy }); expect($rootScope.items).toEqual(['Three', 'Two']); @@ -349,7 +349,7 @@ describe('uiSortable', function() { it('should work when "helper: clone" option is used', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { helper: 'clone' @@ -378,7 +378,7 @@ describe('uiSortable', function() { it('should work when "helper: clone" option is used and a drag is reverted', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { helper: 'clone' @@ -419,7 +419,7 @@ describe('uiSortable', function() { it('should work when "helper: clone" and "appendTo" options are used together', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { helper: 'clone', @@ -449,7 +449,7 @@ describe('uiSortable', function() { it('should work when "helper: clone" and "placeholder" options are used together.', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { helper: 'clone', @@ -497,7 +497,7 @@ describe('uiSortable', function() { it('should work when "helper: function" option is used', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { helper: function (e, item) { @@ -528,7 +528,7 @@ describe('uiSortable', function() { it('should work when "helper: function" option is used and a drag is reverted', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { helper: function (e, item) { @@ -571,7 +571,7 @@ describe('uiSortable', function() { it('should work when "helper: function" and "placeholder" options are used together.', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { helper: function (e, item) { @@ -621,7 +621,7 @@ describe('uiSortable', function() { it('should work when "helper: function" that returns a list element is used', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { helper: function (e, item) { @@ -664,7 +664,7 @@ describe('uiSortable', function() { it('should work when "helper: function" that returns a list element and "placeholder" options are used together.', function() { inject(function($compile, $rootScope) { var element; - element = $compile('')($rootScope); + element = $compile('')($rootScope); $rootScope.$apply(function() { $rootScope.opts = { helper: function (e, item) {