Skip to content
This repository was archived by the owner on Sep 8, 2020. It is now read-only.

Commit 728c724

Browse files
committed
Merge pull request #445 from thgreasi/uiModelItems
feat(sortable): add ui-model-item option
2 parents 15de356 + 3aa9450 commit 728c724

File tree

3 files changed

+192
-24
lines changed

3 files changed

+192
-24
lines changed

src/sortable.js

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,13 @@ angular.module('ui.sortable', [])
6161
value = wrappers[key](value);
6262
}
6363

64-
if (key === 'items' && !value) {
65-
value = uiSortableConfig.items;
64+
// patch the options that need to have values set
65+
if (!value) {
66+
if (key === 'items') {
67+
value = uiSortableConfig.items;
68+
} else if (key === 'ui-model-items') {
69+
value = uiSortableConfig.items;
70+
}
6671
}
6772

6873
return value;
@@ -89,7 +94,11 @@ angular.module('ui.sortable', [])
8994
angular.forEach(oldVal, function(oldValue, key) {
9095
if (!newVal || !(key in newVal)) {
9196
if (key in directiveOpts) {
92-
opts[key] = 'auto';
97+
if (key === 'ui-floating') {
98+
opts[key] = 'auto';
99+
} else {
100+
opts[key] = patchSortableOption(key, undefined);
101+
}
93102
return;
94103
}
95104

@@ -117,7 +126,7 @@ angular.module('ui.sortable', [])
117126
sortableWidgetInstance.floating = value;
118127
}
119128

120-
opts[key] = value;
129+
opts[key] = patchSortableOption(key, value);
121130
return;
122131
}
123132

@@ -154,8 +163,9 @@ angular.module('ui.sortable', [])
154163
function getPlaceholderExcludesludes (element, placeholder) {
155164
// exact match with the placeholder's class attribute to handle
156165
// the case that multiple connected sortables exist and
157-
// the placehoilder option equals the class of sortable items
158-
var excludes = element.find('[class="' + placeholder.attr('class') + '"]:not([ng-repeat], [data-ng-repeat])');
166+
// the placeholder option equals the class of sortable items
167+
var notCssSelector = opts['ui-model-items'].replace(/[^,]*>/g, '');
168+
var excludes = element.find('[class="' + placeholder.attr('class') + '"]:not(' + notCssSelector + ')');
159169
return excludes;
160170
}
161171

@@ -200,23 +210,25 @@ angular.module('ui.sortable', [])
200210
// we can't just do ui.item.index() because there it might have siblings
201211
// which are not items
202212
function getItemIndex(ui) {
203-
return ui.item.parent().find(uiSortableConfig.items)
213+
return ui.item.parent()
214+
.find(opts['ui-model-items'])
204215
.index(ui.item);
205216
}
206217

207218
var opts = {};
208219

209220
// directive specific options
210221
var directiveOpts = {
211-
'ui-floating': undefined
222+
'ui-floating': undefined,
223+
'ui-model-items': uiSortableConfig.items
212224
};
213225

214226
var callbacks = {
215227
receive: null,
216-
remove:null,
217-
start:null,
218-
stop:null,
219-
update:null
228+
remove: null,
229+
start: null,
230+
stop: null,
231+
update: null
220232
};
221233

222234
var wrappers = {
@@ -383,7 +395,6 @@ angular.module('ui.sortable', [])
383395
savedNodes = savedNodes.not(sortingHelper);
384396
}
385397
savedNodes.appendTo(element);
386-
savedNodes.appendTo(element);
387398
}
388399
}
389400

test/sortable.e2e.directiveoptions.spec.js

Lines changed: 162 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,9 @@ describe('uiSortable', function() {
8585
var element;
8686
element = $compile(''.concat(
8787
'<ul ui-sortable="opts" ng-model="items">',
88-
beforeEach,
89-
'<li class="floatleft" ng-repeat="item in items" id="s-{{$index}}" class="sortable-item">{{ item }}</li>',
90-
afterLiElement,
88+
beforeLiElement.replace('<li>', '<li class="floatleft">'),
89+
'<li ng-repeat="item in items" id="s-{{$index}}" class="sortable-item floatleft">{{ item }}</li>',
90+
afterLiElement.replace('<li>', '<li class="floatleft">'),
9191
'</ul>'))($rootScope);
9292
$rootScope.$apply(function() {
9393
$rootScope.opts = {
@@ -125,9 +125,9 @@ describe('uiSortable', function() {
125125
var element;
126126
element = $compile(''.concat(
127127
'<ul ui-sortable="opts" ng-model="items">',
128-
beforeEach,
129-
'<li class="floatleft" ng-repeat="item in items" id="s-{{$index}}" class="sortable-item">{{ item }}</li>',
130-
afterLiElement,
128+
beforeLiElement.replace('<li>', '<li class="floatleft">'),
129+
'<li ng-repeat="item in items" id="s-{{$index}}" class="sortable-item floatleft">{{ item }}</li>',
130+
afterLiElement.replace('<li>', '<li class="floatleft">'),
131131
'</ul>'))($rootScope);
132132
$rootScope.$apply(function() {
133133
$rootScope.opts = {
@@ -166,7 +166,7 @@ describe('uiSortable', function() {
166166
element = $compile(''.concat(
167167
'<ul ui-sortable="opts" ng-model="items">',
168168
beforeLiElement.replace('<li>', '<li class="inline-block">'),
169-
'<li class="inline-block" ng-repeat="item in items" id="s-{{$index}}" class="sortable-item">{{ item }}</li>',
169+
'<li ng-repeat="item in items" id="s-{{$index}}" class="sortable-item inline-block">{{ item }}</li>',
170170
afterLiElement.replace('<li>', '<li class="inline-block">'),
171171
'</ul>'))($rootScope);
172172
$rootScope.$apply(function() {
@@ -206,12 +206,13 @@ describe('uiSortable', function() {
206206
element = $compile(''.concat(
207207
'<ul ui-sortable="opts" ng-model="items">',
208208
beforeLiElement,
209-
'<li ng-repeat="item in items" id="s-{{$index}}">{{ item }}</li>',
209+
'<li ng-repeat="item in items" id="s-{{$index}}" sortable-item>{{ item }}</li>',
210210
afterLiElement +
211211
'</ul>'))($rootScope);
212212
$rootScope.$apply(function() {
213213
$rootScope.opts = {
214-
'ui-floating': true
214+
'ui-floating': true,
215+
'ui-model-items': '> [sortable-item]'
215216
};
216217
$rootScope.items = ['One', 'Two', 'Three'];
217218
});
@@ -240,6 +241,158 @@ describe('uiSortable', function() {
240241
});
241242
});
242243

244+
it('should work when custom "ui-model-items" option is used with an attribute selector', function() {
245+
inject(function($compile, $rootScope) {
246+
var element;
247+
element = $compile(''.concat(
248+
'<ul ui-sortable="opts" ng-model="items">',
249+
beforeLiElement,
250+
'<li ng-repeat="item in items" id="s-{{$index}}" class="sortable-item" ui-sortable-item>{{ item }}</li>',
251+
afterLiElement,
252+
'</ul>'))($rootScope);
253+
254+
var itemsSelector = '[ui-sortable-item]';
255+
$rootScope.$apply(function() {
256+
$rootScope.opts = {
257+
items: '> ' + itemsSelector,
258+
'ui-model-items': '> ' + itemsSelector
259+
};
260+
$rootScope.items = ['One', 'Two', 'Three'];
261+
});
262+
263+
host.append(element).append('<div class="clear"></div>');
264+
265+
var li = element.find(itemsSelector + ':eq(1)');
266+
var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight();
267+
li.simulate('drag', { dy: dy });
268+
expect($rootScope.items).toEqual(['One', 'Three', 'Two']);
269+
expect($rootScope.items).toEqual(listContent(element));
270+
271+
li = element.find(itemsSelector + ':eq(1)');
272+
dy = -(1 + EXTRA_DY_PERCENTAGE) * li.outerHeight();
273+
li.simulate('drag', { dy: dy });
274+
expect($rootScope.items).toEqual(['Three', 'One', 'Two']);
275+
expect($rootScope.items).toEqual(listContent(element));
276+
277+
$(element).remove();
278+
});
279+
});
280+
281+
it('should work when custom "ui-model-items" option is used with a class selector', function() {
282+
inject(function($compile, $rootScope) {
283+
var element;
284+
element = $compile(''.concat(
285+
'<ul ui-sortable="opts" ng-model="items">',
286+
beforeLiElement,
287+
'<li ng-repeat="item in items" id="s-{{$index}}" class="sortable-item ui-sortable-item">{{ item }}</li>',
288+
afterLiElement,
289+
'</ul>'))($rootScope);
290+
291+
var itemsSelector = '.ui-sortable-item';
292+
$rootScope.$apply(function() {
293+
$rootScope.opts = {
294+
items: '> ' + itemsSelector,
295+
'ui-model-items': '> ' + itemsSelector
296+
};
297+
$rootScope.items = ['One', 'Two', 'Three'];
298+
});
299+
300+
host.append(element).append('<div class="clear"></div>');
301+
302+
var li = element.find(itemsSelector + ':eq(1)');
303+
var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight();
304+
li.simulate('drag', { dy: dy });
305+
expect($rootScope.items).toEqual(['One', 'Three', 'Two']);
306+
expect($rootScope.items).toEqual(listContent(element));
307+
308+
li = element.find(itemsSelector + ':eq(1)');
309+
dy = -(1 + EXTRA_DY_PERCENTAGE) * li.outerHeight();
310+
li.simulate('drag', { dy: dy });
311+
expect($rootScope.items).toEqual(['Three', 'One', 'Two']);
312+
expect($rootScope.items).toEqual(listContent(element));
313+
314+
$(element).remove();
315+
});
316+
});
317+
318+
xit('should work with multiple [ng-repeat] when attribute "ui-model-items" selector', function() {
319+
inject(function($compile, $rootScope) {
320+
var element;
321+
element = $compile(''.concat(
322+
'<ul ui-sortable="opts" ng-model="items">',
323+
beforeLiElement,
324+
beforeLiElement.replace('<li>', '<li ng-repeat="item in items" id="pre-{{$index}}" class="sortable-item">{{ item }}'),
325+
'<li ng-repeat="item in items" id="s-{{$index}}" class="sortable-item" ui-sortable-item>{{ item }}</li>',
326+
afterLiElement.replace('<li>', '<li ng-repeat="item in items" id="after-{{$index}}" class="sortable-item">{{ item }}'),
327+
afterLiElement,
328+
'</ul>'))($rootScope);
329+
330+
var itemsSelector = '[ui-sortable-item]';
331+
$rootScope.$apply(function() {
332+
$rootScope.opts = {
333+
items: '> ' + itemsSelector,
334+
'ui-model-items': '> ' + itemsSelector
335+
};
336+
$rootScope.items = ['One', 'Two', 'Three'];
337+
});
338+
339+
host.append(element).append('<div class="clear"></div>');
340+
341+
var li = element.find(itemsSelector + ':eq(1)');
342+
var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight();
343+
li.simulate('drag', { dy: dy });
344+
expect($rootScope.items).toEqual(['One', 'Three', 'Two']);
345+
expect($rootScope.items).toEqual(listContent(element, itemsSelector));
346+
347+
li = element.find(itemsSelector + ':eq(1)');
348+
dy = -(1 + EXTRA_DY_PERCENTAGE) * li.outerHeight();
349+
li.simulate('drag', { dy: dy });
350+
expect($rootScope.items).toEqual(['Three', 'One', 'Two']);
351+
expect($rootScope.items).toEqual(listContent(element, itemsSelector));
352+
353+
$(element).remove();
354+
});
355+
});
356+
357+
xit('should work with multiple [ng-repeat] when class "ui-model-items" selector', function() {
358+
inject(function($compile, $rootScope) {
359+
var element;
360+
element = $compile(''.concat(
361+
'<ul ui-sortable="opts" ng-model="items">',
362+
beforeLiElement,
363+
beforeLiElement.replace('<li>', '<li ng-repeat="item in items" id="pre-{{$index}}" class="sortable-item">{{ item }}'),
364+
'<li ng-repeat="item in items" id="s-{{$index}}" class="sortable-item ui-sortable-item">{{ item }}</li>',
365+
afterLiElement.replace('<li>', '<li ng-repeat="item in items" id="after-{{$index}}" class="sortable-item">{{ item }}'),
366+
afterLiElement,
367+
'</ul>'))($rootScope);
368+
369+
var itemsSelector = '.ui-sortable-item';
370+
$rootScope.$apply(function() {
371+
$rootScope.opts = {
372+
items: '> ' + itemsSelector,
373+
'ui-model-items': '> ' + itemsSelector
374+
};
375+
$rootScope.items = ['One', 'Two', 'Three'];
376+
});
377+
378+
host.append(element).append('<div class="clear"></div>');
379+
380+
var li = element.find(itemsSelector + ':eq(1)');
381+
var dy = (1 + EXTRA_DY_PERCENTAGE) * li.outerHeight();
382+
li.simulate('drag', { dy: dy });
383+
expect($rootScope.items).toEqual(['One', 'Three', 'Two']);
384+
expect($rootScope.items).toEqual(listContent(element, itemsSelector));
385+
386+
li = element.find(itemsSelector + ':eq(1)');
387+
dy = -(1 + EXTRA_DY_PERCENTAGE) * li.outerHeight();
388+
li.simulate('drag', { dy: dy });
389+
expect($rootScope.items).toEqual(['Three', 'One', 'Two']);
390+
expect($rootScope.items).toEqual(listContent(element, itemsSelector));
391+
392+
$(element).remove();
393+
});
394+
});
395+
243396
}
244397

245398
[0, 1].forEach(function(useExtraElements){

test/sortable.test-helper.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@ angular.module('ui.sortable.testHelper', [])
44
.factory('sortableTestHelper', function () {
55
var EXTRA_DY_PERCENTAGE = 0.25;
66

7-
function listContent (list) {
7+
function listContent (list, contentSelector) {
8+
if (!contentSelector) {
9+
contentSelector = '[ng-repeat], [data-ng-repeat], [x-ng-repeat]';
10+
}
11+
812
if (list && list.length) {
9-
return list.children('[ng-repeat], [data-ng-repeat], [x-ng-repeat]').map(function(){ return this.innerHTML; }).toArray();
13+
return list.children(contentSelector).map(function(){ return this.innerHTML; }).toArray();
1014
}
1115
return [];
1216
}

0 commit comments

Comments
 (0)