activeadmin_sortable_table 1.1.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7eee1f5a8aea16d3c1e840ab58b4d5e357503ae0
4
- data.tar.gz: 20b55c4342234b9afeb1e3808c93d3a96768bc76
3
+ metadata.gz: 66207fb91f6c2abf4f7a29107fabb9ace050c52f
4
+ data.tar.gz: 679a10bc3b27667d32fe43a9a86dd14855bed9d7
5
5
  SHA512:
6
- metadata.gz: 861ada336d936e7d31d4733d9563cdf0954fd0cbb2ab31273f74aafb6579ecda25a13e780cef0a2311be0542d1e4a4a51499b7581aace52fd5587a0f6ab47369
7
- data.tar.gz: 087823ddf085e64d6f1dc4fa35c21e2062ad9e59c369f9a2705454f8fe631c31e9564232735e505005525fbc25039ad064643176ad7660dc608a0b4742be8f38
6
+ metadata.gz: f5ce91b8a8994c8322f90e941a4c5ba01cf7bcd0de42e5080eac43f8067969f0ab18871f945311f5b3a87ed276dd07e73b8045ec0f0a5c9e08754ef08ba86f48
7
+ data.tar.gz: 3686d18158dc53c1adaf5a581e72cced145057f33a8239e22448ed092b020e045b4302b3106eddecfbf9675eb78785b7bfd3324e3ddf91d5f333b3c24479193d
@@ -1,3 +1,7 @@
1
+ 1.1.3
2
+
3
+ * **Fix**. Reordering was broken.
4
+
1
5
  1.1.2
2
6
 
3
7
  * **Fix**. Reload page after drug-and-dropping rows, so it recalculates positions properly.
@@ -19,7 +19,7 @@ GIT
19
19
  PATH
20
20
  remote: .
21
21
  specs:
22
- activeadmin_sortable_table (1.1.1)
22
+ activeadmin_sortable_table (1.1.3)
23
23
  activeadmin (>= 1.0.0.pre1)
24
24
  uber (= 0.0.15)
25
25
 
@@ -9,16 +9,30 @@
9
9
  update: function(event, ui) {
10
10
  var item = ui.item.find('[data-sort-url]');
11
11
  var url = item.data('sort-url');
12
- var actionOnSuccess = item.data('sort-success-action');
13
12
  var customParams = {};
14
13
  if (typeof item.data('sort-custom-params') === 'object') {
15
14
  customParams = item.data('sort-custom-params');
16
15
  }
17
16
 
17
+ var nextElement = ui.item[0].nextElementSibling;
18
+
19
+ var nextPosition = $(nextElement).find('[data-position]').data('position');
20
+ var currentPosition = ui.item.find('[data-position]').data('position');
21
+
22
+ if(nextPosition === undefined || nextPosition > currentPosition) {
23
+ // moved down
24
+ var previousElement = ui.item[0].previousElementSibling;
25
+ var previousPosition = $(previousElement).find('[data-position]').data('position');
26
+ var newPosition = previousPosition;
27
+ } else {
28
+ // moved up
29
+ var newPosition = nextPosition;
30
+ }
31
+
18
32
  $.ajax({
19
33
  url: url,
20
34
  type: 'post',
21
- data: $.extend(customParams, { position: ui.item.find('[data-position]').data('position') - 1 }),
35
+ data: $.extend(customParams, { position: newPosition }),
22
36
  error: function () { console.error('Saving sortable error'); },
23
37
  success: function () {
24
38
  location.href = location.href;
@@ -1,6 +1,6 @@
1
1
  module ActiveAdmin
2
2
  #
3
3
  module SortableTable
4
- VERSION = '1.1.2'
4
+ VERSION = '1.1.3'
5
5
  end
6
6
  end
@@ -1,3 +1,3 @@
1
1
  #= require active_admin/base
2
- #= require jquery.simulate
2
+ #= require jquery.simulate.drag-sortable
3
3
  #= require activeadmin_sortable_table
@@ -0,0 +1,235 @@
1
+ (function($) {
2
+ /*
3
+ * Simulate drag of a JQuery UI sortable list
4
+ * Repository: https://github.com/mattheworiordan/jquery.simulate.drag-sortable.js
5
+ * Author: http://mattheworiordan.com
6
+ *
7
+ * options are:
8
+ * - move: move item up (positive) or down (negative) by Integer amount
9
+ * - dropOn: move item to a new linked list, move option now represents position in the new list (zero indexed)
10
+ * - handle: selector for the draggable handle element (optional)
11
+ * - listItem: selector to limit which sibling items can be used for reordering
12
+ * - placeHolder: if a placeholder is used during dragging, we need to consider it's height
13
+ * - tolerance: (optional) number of pixels to overlap by instead of the default 50% of the element height
14
+ *
15
+ */
16
+ $.fn.simulateDragSortable = function(options) {
17
+ // build main options before element iteration
18
+ var opts = $.extend({}, $.fn.simulateDragSortable.defaults, options);
19
+
20
+ applyDrag = function(options) {
21
+ // allow for a drag handle if item is not draggable
22
+ var that = this,
23
+ options = options || opts, // default to plugin opts unless options explicitly provided
24
+ handle = options.handle ? $(this).find(options.handle)[0] : $(this)[0],
25
+ listItem = options.listItem,
26
+ placeHolder = options.placeHolder,
27
+ sibling = $(this),
28
+ moveCounter = Math.floor(options.move),
29
+ direction = moveCounter > 0 ? 'down' : 'up',
30
+ moveVerticalAmount = 0,
31
+ initialVerticalPosition = 0,
32
+ extraDrag = !isNaN(parseInt(options.tolerance, 10)) ? function() { return Number(options.tolerance); } : function(obj) { return ($(obj).outerHeight() / 2) + 5; },
33
+ dragPastBy = 0, // represents the additional amount one drags past an element and bounce back
34
+ dropOn = options.dropOn ? $(options.dropOn) : false,
35
+ center = findCenter(handle),
36
+ x = Math.floor(center.x),
37
+ y = Math.floor(center.y),
38
+ mouseUpAfter = (opts.debug ? 2500 : 10);
39
+
40
+ if (dropOn) {
41
+ if (dropOn.length === 0) {
42
+ if (console && console.log) { console.log('simulate.drag-sortable.js ERROR: Drop on target could not be found'); console.log(options.dropOn); }
43
+ return;
44
+ }
45
+ sibling = dropOn.find('>*:last');
46
+ moveCounter = -(dropOn.find('>*').length + 1) + (moveCounter + 1); // calculate length of list after this move, use moveCounter as a positive index position in list to reverse back up
47
+ if (dropOn.offset().top - $(this).offset().top < 0) {
48
+ // moving to a list above this list, so move to just above top of last item (tried moving to top but JQuery UI wouldn't bite)
49
+ initialVerticalPosition = sibling.offset().top - $(this).offset().top - extraDrag(this);
50
+ } else {
51
+ // moving to a list below this list, so move to bottom and work up (JQuery UI does not trigger new list below unless you move past top item first)
52
+ initialVerticalPosition = sibling.offset().top - $(this).offset().top - $(this).height();
53
+ }
54
+ } else if (moveCounter === 0) {
55
+ if (console && console.log) { console.log('simulate.drag-sortable.js WARNING: Drag with move set to zero has no effect'); }
56
+ return;
57
+ } else {
58
+ while (moveCounter !== 0) {
59
+ if (direction === 'down') {
60
+ if (sibling.next(listItem).length) {
61
+ sibling = sibling.next(listItem);
62
+ moveVerticalAmount += sibling.outerHeight();
63
+ }
64
+ moveCounter -= 1;
65
+ } else {
66
+ if (sibling.prev(listItem).length) {
67
+ sibling = sibling.prev(listItem);
68
+ moveVerticalAmount -= sibling.outerHeight();
69
+ }
70
+ moveCounter += 1;
71
+ }
72
+ }
73
+ }
74
+
75
+ dispatchEvent(handle, 'mousedown', createEvent('mousedown', handle, { clientX: x, clientY: y }));
76
+ // simulate drag start
77
+ dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x+1, clientY: y+1 }));
78
+
79
+ if (dropOn) {
80
+ // jump to top or bottom of new list but do it in increments so that JQuery UI registers the drag events
81
+ slideUpTo(x, y, initialVerticalPosition);
82
+
83
+ // reset y position to top or bottom of list and move from there
84
+ y += initialVerticalPosition;
85
+
86
+ // now call regular shift/down in a list
87
+ options = jQuery.extend(options, { move: moveCounter });
88
+ delete options.dropOn;
89
+
90
+ // add some delays to allow JQuery UI to catch up
91
+ setTimeout(function() {
92
+ dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x, clientY: y }));
93
+ }, 5);
94
+ setTimeout(function() {
95
+ dispatchEvent(handle, 'mouseup', createEvent('mouseup', handle, { clientX: x, clientY: y }));
96
+ setTimeout(function() {
97
+ if (options.move) {
98
+ applyDrag.call(that, options);
99
+ }
100
+ }, 5);
101
+ }, mouseUpAfter);
102
+
103
+ // stop execution as applyDrag has been called again
104
+ return;
105
+ }
106
+
107
+ // Sortable is using a fixed height placeholder meaning items jump up and down as you drag variable height items into fixed height placeholder
108
+ placeHolder = placeHolder && $(this).parent().find(placeHolder);
109
+
110
+ if (!placeHolder && (direction === 'down')) {
111
+ // need to move at least as far as this item and or the last sibling
112
+ if ($(this).outerHeight() > $(sibling).outerHeight()) {
113
+ moveVerticalAmount += $(this).outerHeight() - $(sibling).outerHeight();
114
+ }
115
+ moveVerticalAmount += extraDrag(sibling);
116
+ dragPastBy += extraDrag(sibling);
117
+ } else if (direction === 'up') {
118
+ // move a little extra to ensure item clips into next position
119
+ moveVerticalAmount -= Math.max(extraDrag(this), 5);
120
+ } else if (direction === 'down') {
121
+ // moving down with a place holder
122
+ if (placeHolder.height() < $(this).height()) {
123
+ moveVerticalAmount += Math.max(placeHolder.height(), 5);
124
+ } else {
125
+ moveVerticalAmount += extraDrag(sibling);
126
+ }
127
+ }
128
+
129
+ if (sibling[0] !== $(this)[0]) {
130
+ // step through so that the UI controller can determine when to show the placeHolder
131
+ slideUpTo(x, y, moveVerticalAmount, dragPastBy);
132
+ } else {
133
+ if (window.console) {
134
+ console.log('simulate.drag-sortable.js WARNING: Could not move as at top or bottom already');
135
+ }
136
+ }
137
+
138
+ setTimeout(function() {
139
+ dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x, clientY: y + moveVerticalAmount }));
140
+ }, 5);
141
+ setTimeout(function() {
142
+ dispatchEvent(handle, 'mouseup', createEvent('mouseup', handle, { clientX: x, clientY: y + moveVerticalAmount }));
143
+ }, mouseUpAfter);
144
+ };
145
+
146
+ // iterate and move each matched element
147
+ return this.each(applyDrag);
148
+ };
149
+
150
+ // fire mouse events, go half way, then the next half, so small mouse movements near target and big at the start
151
+ function slideUpTo(x, y, targetOffset, goPastBy) {
152
+ var moveBy, offset;
153
+
154
+ if (!goPastBy) { goPastBy = 0; }
155
+ if ((targetOffset < 0) && (goPastBy > 0)) { goPastBy = -goPastBy; } // ensure go past is in the direction as often passed in from object height so always positive
156
+
157
+ // go forwards including goPastBy
158
+ for (offset = 0; Math.abs(offset) + 1 < Math.abs(targetOffset + goPastBy); offset += ((targetOffset + goPastBy - offset)/2) ) {
159
+ dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x, clientY: y + Math.ceil(offset) }));
160
+ }
161
+ offset = targetOffset + goPastBy;
162
+ dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x, clientY: y + offset }));
163
+
164
+ // now bounce back
165
+ for (; Math.abs(offset) - 1 >= Math.abs(targetOffset); offset += ((targetOffset - offset)/2) ) {
166
+ dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x, clientY: y + Math.ceil(offset) }));
167
+ }
168
+ dispatchEvent(document, 'mousemove', createEvent('mousemove', document, { clientX: x, clientY: y + targetOffset }));
169
+ }
170
+
171
+ function createEvent(type, target, options) {
172
+ var evt;
173
+ var e = $.extend({
174
+ target: target,
175
+ preventDefault: function() { },
176
+ stopImmediatePropagation: function() { },
177
+ stopPropagation: function() { },
178
+ isPropagationStopped: function() { return true; },
179
+ isImmediatePropagationStopped: function() { return true; },
180
+ isDefaultPrevented: function() { return true; },
181
+ bubbles: true,
182
+ cancelable: (type != "mousemove"),
183
+ view: window,
184
+ detail: 0,
185
+ screenX: 0,
186
+ screenY: 0,
187
+ clientX: 0,
188
+ clientY: 0,
189
+ ctrlKey: false,
190
+ altKey: false,
191
+ shiftKey: false,
192
+ metaKey: false,
193
+ button: 0,
194
+ relatedTarget: undefined
195
+ }, options || {});
196
+
197
+ if ($.isFunction(document.createEvent)) {
198
+ evt = document.createEvent("MouseEvents");
199
+ evt.initMouseEvent(type, e.bubbles, e.cancelable, e.view, e.detail,
200
+ e.screenX, e.screenY, e.clientX, e.clientY,
201
+ e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
202
+ e.button, e.relatedTarget || document.body.parentNode);
203
+ } else if (document.createEventObject) {
204
+ evt = document.createEventObject();
205
+ $.extend(evt, e);
206
+ evt.button = { 0:1, 1:4, 2:2 }[evt.button] || evt.button;
207
+ }
208
+ return evt;
209
+ }
210
+
211
+ function dispatchEvent(el, type, evt) {
212
+ if (el.dispatchEvent) {
213
+ el.dispatchEvent(evt);
214
+ } else if (el.fireEvent) {
215
+ el.fireEvent('on' + type, evt);
216
+ }
217
+ return evt;
218
+ }
219
+
220
+ function findCenter(el) {
221
+ var elm = $(el),
222
+ o = elm.offset();
223
+ return {
224
+ x: o.left + elm.outerWidth() / 2,
225
+ y: o.top + elm.outerHeight() / 2
226
+ };
227
+ }
228
+
229
+ //
230
+ // plugin defaults
231
+ //
232
+ $.fn.simulateDragSortable.defaults = {
233
+ move: 0
234
+ };
235
+ })(jQuery);
@@ -1,43 +1,66 @@
1
- RSpec.describe ActiveAdmin::SortableTable, 'Drag-and-Drop', type: :feature do
1
+ RSpec.describe ActiveAdmin::SortableTable, 'Drag-and-Drop', type: :feature, js: true do
2
2
  before do
3
3
  Category.create!
4
4
  Category.create!
5
5
  Category.create!
6
6
  end
7
7
 
8
- def ordered_elements
8
+ def ordered_ids
9
9
  Category.order(:position).pluck(:id)
10
10
  end
11
11
 
12
12
  context 'first page' do
13
- it 'reorders elements by dragging vertically by handle', js: true do
14
- expect(ordered_elements).to eq([1, 2, 3])
13
+ before do
14
+ expect(ordered_ids).to eq([1, 2, 3])
15
15
 
16
16
  visit admin_categories_path
17
17
 
18
- expect(visible_elements).to eq([1, 2, 3])
18
+ expect(visible_ids).to eq([1, 2, 3])
19
19
  expect(visible_positions).to eq([1, 2, 3])
20
+ end
20
21
 
21
- move_higher(2, by_handle: true)
22
+ context 'move element up' do
23
+ it 'to the top position' do
24
+ move_up(3, by: 2)
22
25
 
23
- expect(visible_elements).to eq([2, 1, 3])
24
- expect(visible_positions).to eq([1, 2, 3])
25
- expect(ordered_elements).to eq([2, 1, 3])
26
+ expect(visible_ids).to eq([3, 1, 2])
27
+ expect(visible_positions).to eq([1, 2, 3])
28
+ expect(ordered_ids).to eq([3, 1, 2])
29
+ end
30
+
31
+ it 'to the middle of the table' do
32
+ move_up(3, by: 1)
33
+
34
+ expect(visible_ids).to eq([1, 3, 2])
35
+ expect(visible_positions).to eq([1, 2, 3])
36
+ expect(ordered_ids).to eq([1, 3, 2])
37
+ end
26
38
  end
27
39
 
28
- it 'does not reorder elements by dragging vertically by row', js: true do
29
- expect(ordered_elements).to eq([1, 2, 3])
40
+ context 'move element down' do
41
+ it 'to the bottom of the table' do
42
+ move_down(1, by: 2)
30
43
 
31
- visit admin_categories_path
44
+ expect(visible_ids).to eq([2, 3, 1])
45
+ expect(visible_positions).to eq([1, 2, 3])
46
+ expect(ordered_ids).to eq([2, 3, 1])
47
+ end
32
48
 
33
- expect(visible_elements).to eq([1, 2, 3])
34
- expect(visible_positions).to eq([1, 2, 3])
49
+ it 'to the middle of the table' do
50
+ move_down(2, by: 1)
51
+
52
+ expect(visible_ids).to eq([1, 3, 2])
53
+ expect(visible_positions).to eq([1, 2, 3])
54
+ expect(ordered_ids).to eq([1, 3, 2])
55
+ end
56
+ end
35
57
 
36
- move_higher(2, by_handle: false)
58
+ it 'can not drug not by handle' do
59
+ move_up(3, by: 2, use_handle: false)
37
60
 
38
- expect(visible_elements).to eq([1, 2, 3])
61
+ expect(visible_ids).to eq([1, 2, 3])
39
62
  expect(visible_positions).to eq([1, 2, 3])
40
- expect(ordered_elements).to eq([1, 2, 3])
63
+ expect(ordered_ids).to eq([1, 2, 3])
41
64
  end
42
65
  end
43
66
 
@@ -48,40 +71,63 @@ RSpec.describe ActiveAdmin::SortableTable, 'Drag-and-Drop', type: :feature do
48
71
  Category.create!
49
72
  end
50
73
 
51
- it 'reorders elements by dragging vertically by handle', js: true do
52
- expect(ordered_elements).to eq([1, 2, 3, 4, 5, 6])
74
+ before do
75
+ expect(ordered_ids).to eq([1, 2, 3, 4, 5, 6])
53
76
 
54
77
  visit admin_categories_path(page: 2)
55
78
 
56
- expect(visible_elements).to eq([4, 5, 6])
79
+ expect(visible_ids).to eq([4, 5, 6])
57
80
  expect(visible_positions).to eq([4, 5, 6])
81
+ end
58
82
 
59
- move_higher(5, by_handle: true)
83
+ context 'move element up' do
84
+ it 'to the top position' do
85
+ move_up(6, by: 2)
60
86
 
61
- expect(visible_elements).to eq([5, 4, 6])
62
- expect(visible_positions).to eq([4, 5, 6])
63
- expect(ordered_elements).to eq([1, 2, 3, 5, 4, 6])
87
+ expect(visible_ids).to eq([6, 4, 5])
88
+ expect(visible_positions).to eq([4, 5, 6])
89
+ expect(ordered_ids).to eq([1, 2, 3, 6, 4, 5])
90
+ end
91
+
92
+ it 'to the middle of the table' do
93
+ move_up(6, by: 1)
94
+
95
+ expect(visible_ids).to eq([4, 6, 5])
96
+ expect(visible_positions).to eq([4, 5, 6])
97
+ expect(ordered_ids).to eq([1, 2, 3, 4, 6, 5])
98
+ end
64
99
  end
65
100
 
66
- it 'does not reorder elements by dragging vertically by row', js: true do
67
- expect(ordered_elements).to eq([1, 2, 3, 4, 5, 6])
101
+ context 'move element down' do
102
+ it 'to the bottom of the table' do
103
+ move_down(4, by: 2)
68
104
 
69
- visit admin_categories_path(page: 2)
105
+ expect(visible_ids).to eq([5, 6, 4])
106
+ expect(visible_positions).to eq([4, 5, 6])
107
+ expect(ordered_ids).to eq([1, 2, 3, 5, 6, 4])
108
+ end
70
109
 
71
- expect(visible_elements).to eq([4, 5, 6])
72
- expect(visible_positions).to eq([4, 5, 6])
110
+ it 'to the middle of the table' do
111
+ move_down(4, by: 1)
73
112
 
74
- move_higher(5, by_handle: false)
113
+ expect(visible_ids).to eq([5, 4, 6])
114
+ expect(visible_positions).to eq([4, 5, 6])
115
+ expect(ordered_ids).to eq([1, 2, 3, 5, 4, 6])
116
+ end
117
+ end
118
+
119
+ it 'can not drug not by handle' do
120
+ move_down(6, by: 2, use_handle: false)
75
121
 
76
- expect(visible_elements).to eq([4, 5, 6])
122
+ expect(visible_ids).to eq([4, 5, 6])
77
123
  expect(visible_positions).to eq([4, 5, 6])
78
- expect(ordered_elements).to eq([1, 2, 3, 4, 5, 6])
124
+ expect(ordered_ids).to eq([1, 2, 3, 4, 5, 6])
79
125
  end
80
126
  end
81
127
 
82
128
  private
83
129
 
84
- def visible_elements
130
+ def visible_ids
85
131
  all('.ui-sortable .col-id').map(&:text).map(&:to_i)
86
132
  end
87
133
 
@@ -89,14 +135,24 @@ RSpec.describe ActiveAdmin::SortableTable, 'Drag-and-Drop', type: :feature do
89
135
  all('.ui-sortable .col-position').map(&:text).map(&:to_i)
90
136
  end
91
137
 
92
- def move_higher(element_id, by_handle:)
93
- drag_element(element_id, by_handle, dy: -200)
138
+ def move_up(element_id, by: 1, use_handle: true)
139
+ drag_element(element_id, by: -by, use_handle: use_handle)
94
140
  end
95
141
 
96
- def drag_element(element_id, by_handle, options)
97
- options.reverse_merge! moves: 20
98
- selector = by_handle ? "#category_#{element_id} .handle" : "#category_#{element_id}"
99
- page.execute_script(%($("#{selector}").simulate("drag", #{options.to_json})))
100
- sleep 0.1
142
+ def move_down(element_id, by: 1, use_handle: true)
143
+ drag_element(element_id, by: by, use_handle: use_handle)
144
+ end
145
+
146
+ def drag_element(element_id, by:, use_handle:)
147
+ if use_handle
148
+ page.execute_script(<<-JS)
149
+ $("#category_#{element_id}").simulateDragSortable({ move: #{by}, handle: ".handle" })
150
+ JS
151
+ else
152
+ page.execute_script(<<-JS)
153
+ $("#category_#{element_id}").simulateDragSortable({ move: #{by} })
154
+ JS
155
+ end
156
+ sleep 0.5
101
157
  end
102
158
  end
@@ -1,4 +1,4 @@
1
- RSpec.describe ActiveAdmin::SortableTable, 'Move to top', type: :feature do
1
+ RSpec.describe ActiveAdmin::SortableTable, 'Move to top', type: :feature, js: true do
2
2
  before do
3
3
  Category.create!
4
4
  Category.create!
@@ -6,39 +6,47 @@ RSpec.describe ActiveAdmin::SortableTable, 'Move to top', type: :feature do
6
6
  Category.create!
7
7
  end
8
8
 
9
- def ordered_elements
9
+ def ordered_ids
10
10
  Category.order(:position).pluck(:id)
11
11
  end
12
12
 
13
- it 'push element to top by clicking "move to top"', js: true do
14
- expect(ordered_elements).to eq([1, 2, 3, 4])
13
+ before do
14
+ expect(ordered_ids).to eq([1, 2, 3, 4])
15
15
 
16
16
  # Initially only one element on the second page
17
17
  visit admin_categories_path(page: 2)
18
18
 
19
- expect(visible_elements).to contain_exactly(4)
19
+ expect(visible_ids).to contain_exactly(4)
20
+ expect(visible_positions).to contain_exactly(4)
21
+ end
20
22
 
23
+ it 'push element to top by clicking "move to top"' do
21
24
  # When I push "move to top" button
22
25
  move_to_top(4)
23
26
 
24
27
  # The last element from the previous page should be shown
25
28
  # save_and_open_page
26
- expect(visible_elements).to contain_exactly(3)
29
+ expect(visible_ids).to contain_exactly(3)
27
30
 
28
31
  # And when I visit previous page
29
32
  visit admin_categories_path(page: 1)
30
33
 
31
34
  # I should see pushed elenent on the top
32
- expect(visible_elements).to eq([4, 1, 2])
33
- expect(ordered_elements).to eq([4, 1, 2, 3])
35
+ expect(visible_ids).to eq([4, 1, 2])
36
+ expect(visible_positions).to eq([1, 2, 3])
37
+ expect(ordered_ids).to eq([4, 1, 2, 3])
34
38
  end
35
39
 
36
40
  private
37
41
 
38
- def visible_elements
42
+ def visible_ids
39
43
  all('.ui-sortable .col-id').map(&:text).map(&:to_i)
40
44
  end
41
45
 
46
+ def visible_positions
47
+ all('.ui-sortable .col-position').map(&:text).map(&:to_i)
48
+ end
49
+
42
50
  def move_to_top(element_id)
43
51
  within "#category_#{element_id}" do
44
52
  first('.move_to_top').click
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activeadmin_sortable_table
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam McCrea
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-10-19 00:00:00.000000000 Z
13
+ date: 2015-10-23 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activeadmin
@@ -172,7 +172,7 @@ files:
172
172
  - spec/dummy/app/assets/images/.keep
173
173
  - spec/dummy/app/assets/javascripts/active_admin.js.coffee
174
174
  - spec/dummy/app/assets/javascripts/application.js
175
- - spec/dummy/app/assets/javascripts/jquery.simulate.js
175
+ - spec/dummy/app/assets/javascripts/jquery.simulate.drag-sortable.js
176
176
  - spec/dummy/app/assets/stylesheets/active_admin.scss
177
177
  - spec/dummy/app/assets/stylesheets/application.css
178
178
  - spec/dummy/app/controllers/application_controller.rb
@@ -242,7 +242,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
242
242
  version: '0'
243
243
  requirements: []
244
244
  rubyforge_project:
245
- rubygems_version: 2.4.5
245
+ rubygems_version: 2.4.8
246
246
  signing_key:
247
247
  specification_version: 4
248
248
  summary: Drag and drop reordering interface for ActiveAdmin tables
@@ -254,7 +254,7 @@ test_files:
254
254
  - spec/dummy/app/assets/images/.keep
255
255
  - spec/dummy/app/assets/javascripts/active_admin.js.coffee
256
256
  - spec/dummy/app/assets/javascripts/application.js
257
- - spec/dummy/app/assets/javascripts/jquery.simulate.js
257
+ - spec/dummy/app/assets/javascripts/jquery.simulate.drag-sortable.js
258
258
  - spec/dummy/app/assets/stylesheets/active_admin.scss
259
259
  - spec/dummy/app/assets/stylesheets/application.css
260
260
  - spec/dummy/app/controllers/application_controller.rb
@@ -1,314 +0,0 @@
1
- /*!
2
- * jQuery Simulate v@VERSION - simulate browser mouse and keyboard events
3
- * https://github.com/jquery/jquery-simulate
4
- *
5
- * Copyright 2012 jQuery Foundation and other contributors
6
- * Released under the MIT license.
7
- * http://jquery.org/license
8
- *
9
- * Date: @DATE
10
- */
11
-
12
- ;(function( $, undefined ) {
13
-
14
- var rkeyEvent = /^key/,
15
- rmouseEvent = /^(?:mouse|contextmenu)|click/;
16
-
17
- $.fn.simulate = function( type, options ) {
18
- return this.each(function() {
19
- new $.simulate( this, type, options );
20
- });
21
- };
22
-
23
- $.simulate = function( elem, type, options ) {
24
- var method = $.camelCase( "simulate-" + type );
25
-
26
- this.target = elem;
27
- this.options = options;
28
-
29
- if ( this[ method ] ) {
30
- this[ method ]();
31
- } else {
32
- this.simulateEvent( elem, type, options );
33
- }
34
- };
35
-
36
- $.extend( $.simulate, {
37
-
38
- keyCode: {
39
- BACKSPACE: 8,
40
- COMMA: 188,
41
- DELETE: 46,
42
- DOWN: 40,
43
- END: 35,
44
- ENTER: 13,
45
- ESCAPE: 27,
46
- HOME: 36,
47
- LEFT: 37,
48
- NUMPAD_ADD: 107,
49
- NUMPAD_DECIMAL: 110,
50
- NUMPAD_DIVIDE: 111,
51
- NUMPAD_ENTER: 108,
52
- NUMPAD_MULTIPLY: 106,
53
- NUMPAD_SUBTRACT: 109,
54
- PAGE_DOWN: 34,
55
- PAGE_UP: 33,
56
- PERIOD: 190,
57
- RIGHT: 39,
58
- SPACE: 32,
59
- TAB: 9,
60
- UP: 38
61
- },
62
-
63
- buttonCode: {
64
- LEFT: 0,
65
- MIDDLE: 1,
66
- RIGHT: 2
67
- }
68
- });
69
-
70
- $.extend( $.simulate.prototype, {
71
-
72
- simulateEvent: function( elem, type, options ) {
73
- var event = this.createEvent( type, options );
74
- this.dispatchEvent( elem, type, event, options );
75
- },
76
-
77
- createEvent: function( type, options ) {
78
- if ( rkeyEvent.test( type ) ) {
79
- return this.keyEvent( type, options );
80
- }
81
-
82
- if ( rmouseEvent.test( type ) ) {
83
- return this.mouseEvent( type, options );
84
- }
85
- },
86
-
87
- mouseEvent: function( type, options ) {
88
- var event, eventDoc, doc, body;
89
- options = $.extend({
90
- bubbles: true,
91
- cancelable: (type !== "mousemove"),
92
- view: window,
93
- detail: 0,
94
- screenX: 0,
95
- screenY: 0,
96
- clientX: 1,
97
- clientY: 1,
98
- ctrlKey: false,
99
- altKey: false,
100
- shiftKey: false,
101
- metaKey: false,
102
- button: 0,
103
- relatedTarget: undefined
104
- }, options );
105
-
106
- if ( document.createEvent ) {
107
- event = document.createEvent( "MouseEvents" );
108
- event.initMouseEvent( type, options.bubbles, options.cancelable,
109
- options.view, options.detail,
110
- options.screenX, options.screenY, options.clientX, options.clientY,
111
- options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,
112
- options.button, options.relatedTarget || document.body.parentNode );
113
-
114
- // IE 9+ creates events with pageX and pageY set to 0.
115
- // Trying to modify the properties throws an error,
116
- // so we define getters to return the correct values.
117
- if ( event.pageX === 0 && event.pageY === 0 && Object.defineProperty ) {
118
- eventDoc = event.relatedTarget.ownerDocument || document;
119
- doc = eventDoc.documentElement;
120
- body = eventDoc.body;
121
-
122
- Object.defineProperty( event, "pageX", {
123
- get: function() {
124
- return options.clientX +
125
- ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) -
126
- ( doc && doc.clientLeft || body && body.clientLeft || 0 );
127
- }
128
- });
129
- Object.defineProperty( event, "pageY", {
130
- get: function() {
131
- return options.clientY +
132
- ( doc && doc.scrollTop || body && body.scrollTop || 0 ) -
133
- ( doc && doc.clientTop || body && body.clientTop || 0 );
134
- }
135
- });
136
- }
137
- } else if ( document.createEventObject ) {
138
- event = document.createEventObject();
139
- $.extend( event, options );
140
- // standards event.button uses constants defined here: http://msdn.microsoft.com/en-us/library/ie/ff974877(v=vs.85).aspx
141
- // old IE event.button uses constants defined here: http://msdn.microsoft.com/en-us/library/ie/ms533544(v=vs.85).aspx
142
- // so we actually need to map the standard back to oldIE
143
- event.button = {
144
- 0: 1,
145
- 1: 4,
146
- 2: 2
147
- }[ event.button ] || event.button;
148
- }
149
-
150
- return event;
151
- },
152
-
153
- keyEvent: function( type, options ) {
154
- var event;
155
- options = $.extend({
156
- bubbles: true,
157
- cancelable: true,
158
- view: window,
159
- ctrlKey: false,
160
- altKey: false,
161
- shiftKey: false,
162
- metaKey: false,
163
- keyCode: 0,
164
- charCode: undefined
165
- }, options );
166
-
167
- if ( document.createEvent ) {
168
- try {
169
- event = document.createEvent( "KeyEvents" );
170
- event.initKeyEvent( type, options.bubbles, options.cancelable, options.view,
171
- options.ctrlKey, options.altKey, options.shiftKey, options.metaKey,
172
- options.keyCode, options.charCode );
173
- // initKeyEvent throws an exception in WebKit
174
- // see: http://stackoverflow.com/questions/6406784/initkeyevent-keypress-only-works-in-firefox-need-a-cross-browser-solution
175
- // and also https://bugs.webkit.org/show_bug.cgi?id=13368
176
- // fall back to a generic event until we decide to implement initKeyboardEvent
177
- } catch( err ) {
178
- event = document.createEvent( "Events" );
179
- event.initEvent( type, options.bubbles, options.cancelable );
180
- $.extend( event, {
181
- view: options.view,
182
- ctrlKey: options.ctrlKey,
183
- altKey: options.altKey,
184
- shiftKey: options.shiftKey,
185
- metaKey: options.metaKey,
186
- keyCode: options.keyCode,
187
- charCode: options.charCode
188
- });
189
- }
190
- } else if ( document.createEventObject ) {
191
- event = document.createEventObject();
192
- $.extend( event, options );
193
- }
194
-
195
- if ( !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ) || (({}).toString.call( window.opera ) === "[object Opera]") ) {
196
- event.keyCode = (options.charCode > 0) ? options.charCode : options.keyCode;
197
- event.charCode = undefined;
198
- }
199
-
200
- return event;
201
- },
202
-
203
- dispatchEvent: function( elem, type, event ) {
204
- if ( elem[ type ] ) {
205
- elem[ type ]();
206
- } else if ( elem.dispatchEvent ) {
207
- elem.dispatchEvent( event );
208
- } else if ( elem.fireEvent ) {
209
- elem.fireEvent( "on" + type, event );
210
- }
211
- },
212
-
213
- simulateFocus: function() {
214
- var focusinEvent,
215
- triggered = false,
216
- element = $( this.target );
217
-
218
- function trigger() {
219
- triggered = true;
220
- }
221
-
222
- element.bind( "focus", trigger );
223
- element[ 0 ].focus();
224
-
225
- if ( !triggered ) {
226
- focusinEvent = $.Event( "focusin" );
227
- focusinEvent.preventDefault();
228
- element.trigger( focusinEvent );
229
- element.triggerHandler( "focus" );
230
- }
231
- element.unbind( "focus", trigger );
232
- },
233
-
234
- simulateBlur: function() {
235
- var focusoutEvent,
236
- triggered = false,
237
- element = $( this.target );
238
-
239
- function trigger() {
240
- triggered = true;
241
- }
242
-
243
- element.bind( "blur", trigger );
244
- element[ 0 ].blur();
245
-
246
- // blur events are async in IE
247
- setTimeout(function() {
248
- // IE won't let the blur occur if the window is inactive
249
- if ( element[ 0 ].ownerDocument.activeElement === element[ 0 ] ) {
250
- element[ 0 ].ownerDocument.body.focus();
251
- }
252
-
253
- // Firefox won't trigger events if the window is inactive
254
- // IE doesn't trigger events if we had to manually focus the body
255
- if ( !triggered ) {
256
- focusoutEvent = $.Event( "focusout" );
257
- focusoutEvent.preventDefault();
258
- element.trigger( focusoutEvent );
259
- element.triggerHandler( "blur" );
260
- }
261
- element.unbind( "blur", trigger );
262
- }, 1 );
263
- }
264
- });
265
-
266
-
267
-
268
- /** complex events **/
269
-
270
- function findCenter( elem ) {
271
- var offset,
272
- document = $( elem.ownerDocument );
273
- elem = $( elem );
274
- offset = elem.offset();
275
-
276
- return {
277
- x: offset.left + elem.outerWidth() / 2 - document.scrollLeft(),
278
- y: offset.top + elem.outerHeight() / 2 - document.scrollTop()
279
- };
280
- }
281
-
282
- $.extend( $.simulate.prototype, {
283
- simulateDrag: function() {
284
- var i = 0,
285
- target = this.target,
286
- options = this.options,
287
- center = findCenter( target ),
288
- x = Math.floor( center.x ),
289
- y = Math.floor( center.y ),
290
- dx = options.dx || 0,
291
- dy = options.dy || 0,
292
- moves = options.moves || 3,
293
- coord = { clientX: x, clientY: y };
294
-
295
- this.simulateEvent( target, "mousedown", coord );
296
-
297
- for ( ; i < moves ; i++ ) {
298
- x += dx / moves;
299
- y += dy / moves;
300
-
301
- coord = {
302
- clientX: Math.round( x ),
303
- clientY: Math.round( y )
304
- };
305
-
306
- this.simulateEvent( document, "mousemove", coord );
307
- }
308
-
309
- this.simulateEvent( target, "mouseup", coord );
310
- this.simulateEvent( target, "click", coord );
311
- }
312
- });
313
-
314
- })( jQuery );