rest-assured 1.1.2 → 1.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +26 -26
- data/README.markdown +11 -7
- data/db/migrate/20120320200820_change_fullpath_to_text.rb +9 -0
- data/features/step_definitions/redirect_rules_steps.rb +5 -7
- data/features/web_ui/redirects.feature +2 -2
- data/lib/rest-assured/version.rb +1 -1
- data/public/javascript/jquery.simulate.drag-sortable.js +235 -0
- data/spec/models/double_spec.rb +7 -0
- data/views/layout.haml +5 -3
- metadata +17 -16
- data/prof-result.html +0 -79521
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rest-assured (1.1.
|
4
|
+
rest-assured (1.1.3)
|
5
5
|
activerecord (~> 3.2.0)
|
6
6
|
activeresource (~> 3.2.0)
|
7
7
|
childprocess (~> 0.3.0)
|
@@ -12,23 +12,23 @@ PATH
|
|
12
12
|
GEM
|
13
13
|
remote: http://rubygems.org/
|
14
14
|
specs:
|
15
|
-
activemodel (3.2.
|
16
|
-
activesupport (= 3.2.
|
15
|
+
activemodel (3.2.2)
|
16
|
+
activesupport (= 3.2.2)
|
17
17
|
builder (~> 3.0.0)
|
18
|
-
activerecord (3.2.
|
19
|
-
activemodel (= 3.2.
|
20
|
-
activesupport (= 3.2.
|
21
|
-
arel (~> 3.0.
|
18
|
+
activerecord (3.2.2)
|
19
|
+
activemodel (= 3.2.2)
|
20
|
+
activesupport (= 3.2.2)
|
21
|
+
arel (~> 3.0.2)
|
22
22
|
tzinfo (~> 0.3.29)
|
23
|
-
activeresource (3.2.
|
24
|
-
activemodel (= 3.2.
|
25
|
-
activesupport (= 3.2.
|
26
|
-
activesupport (3.2.
|
23
|
+
activeresource (3.2.2)
|
24
|
+
activemodel (= 3.2.2)
|
25
|
+
activesupport (= 3.2.2)
|
26
|
+
activesupport (3.2.2)
|
27
27
|
i18n (~> 0.6)
|
28
28
|
multi_json (~> 1.0)
|
29
29
|
addressable (2.2.7)
|
30
30
|
archive-tar-minitar (0.5.2)
|
31
|
-
arel (3.0.
|
31
|
+
arel (3.0.2)
|
32
32
|
awesome_print (1.0.2)
|
33
33
|
builder (3.0.0)
|
34
34
|
capybara (1.1.2)
|
@@ -43,10 +43,10 @@ GEM
|
|
43
43
|
childprocess (0.3.1)
|
44
44
|
ffi (~> 1.0.6)
|
45
45
|
columnize (0.3.6)
|
46
|
-
cucumber (1.1.
|
46
|
+
cucumber (1.1.9)
|
47
47
|
builder (>= 2.1.2)
|
48
48
|
diff-lcs (>= 1.1.2)
|
49
|
-
gherkin (~> 2.
|
49
|
+
gherkin (~> 2.9.0)
|
50
50
|
json (>= 1.4.6)
|
51
51
|
term-ansicolor (>= 1.0.6)
|
52
52
|
daemons (1.1.8)
|
@@ -54,7 +54,7 @@ GEM
|
|
54
54
|
diff-lcs (1.1.3)
|
55
55
|
eventmachine (0.12.10)
|
56
56
|
ffi (1.0.11)
|
57
|
-
gherkin (2.
|
57
|
+
gherkin (2.9.0)
|
58
58
|
json (>= 1.4.6)
|
59
59
|
growl (1.0.3)
|
60
60
|
guard (1.0.0)
|
@@ -72,12 +72,12 @@ GEM
|
|
72
72
|
addressable (~> 2.2.6)
|
73
73
|
linecache (0.46)
|
74
74
|
rbx-require-relative (> 0.0.4)
|
75
|
-
linecache19 (0.5.
|
75
|
+
linecache19 (0.5.12)
|
76
76
|
ruby_core_source (>= 0.1.4)
|
77
77
|
mime-types (1.17.2)
|
78
|
-
multi_json (1.0
|
78
|
+
multi_json (1.1.0)
|
79
79
|
mysql2 (0.3.11)
|
80
|
-
nokogiri (1.5.
|
80
|
+
nokogiri (1.5.2)
|
81
81
|
pg (0.13.2)
|
82
82
|
rack (1.4.1)
|
83
83
|
rack-protection (1.2.0)
|
@@ -87,7 +87,7 @@ GEM
|
|
87
87
|
rake (0.9.2.2)
|
88
88
|
rb-fsevent (0.9.0)
|
89
89
|
rb-readline (0.4.2)
|
90
|
-
rbx-require-relative (0.0.
|
90
|
+
rbx-require-relative (0.0.9)
|
91
91
|
relish (0.5.3)
|
92
92
|
archive-tar-minitar (>= 0.5.2)
|
93
93
|
json (>= 1.4.6)
|
@@ -107,7 +107,7 @@ GEM
|
|
107
107
|
ruby-debug-base (~> 0.10.4.0)
|
108
108
|
ruby-debug-base (0.10.4)
|
109
109
|
linecache (>= 0.3)
|
110
|
-
ruby-debug-base19 (0.11.
|
110
|
+
ruby-debug-base19 (0.11.25)
|
111
111
|
columnize (>= 0.3.1)
|
112
112
|
linecache19 (>= 0.5.11)
|
113
113
|
ruby_core_source (>= 0.1.4)
|
@@ -118,14 +118,14 @@ GEM
|
|
118
118
|
ruby_core_source (0.1.5)
|
119
119
|
archive-tar-minitar (>= 0.5.2)
|
120
120
|
rubyzip (0.9.6.1)
|
121
|
-
selenium-webdriver (2.
|
121
|
+
selenium-webdriver (2.20.0)
|
122
122
|
childprocess (>= 0.2.5)
|
123
|
-
ffi (~> 1.0
|
124
|
-
multi_json (~> 1.0
|
123
|
+
ffi (~> 1.0)
|
124
|
+
multi_json (~> 1.0)
|
125
125
|
rubyzip
|
126
126
|
shoulda-matchers (1.0.0)
|
127
|
-
simplecov (0.
|
128
|
-
multi_json (~> 1.0
|
127
|
+
simplecov (0.6.1)
|
128
|
+
multi_json (~> 1.0)
|
129
129
|
simplecov-html (~> 0.5.3)
|
130
130
|
simplecov-html (0.5.3)
|
131
131
|
sinatra (1.3.2)
|
@@ -146,7 +146,7 @@ GEM
|
|
146
146
|
rack (>= 1.0.0)
|
147
147
|
thor (0.14.6)
|
148
148
|
tilt (1.3.3)
|
149
|
-
tzinfo (0.3.
|
149
|
+
tzinfo (0.3.32)
|
150
150
|
xpath (0.1.4)
|
151
151
|
nokogiri (~> 1.3)
|
152
152
|
|
data/README.markdown
CHANGED
@@ -5,12 +5,16 @@
|
|
5
5
|
## Overview
|
6
6
|
|
7
7
|
Stub/spy http(s) based external dependencies in your integration/acceptance tests.
|
8
|
-
In essense, here is what it could be useful for:
|
9
8
|
|
10
|
-
|
11
|
-
|
9
|
+
In a nutshell, here is how you can use it:
|
10
|
+
|
11
|
+
* replace external data sources with predefined data (stubbing)
|
12
|
+
* verify requests to external services (spying)
|
12
13
|
* simulate different behavior of external services using web UI; useful in development
|
13
14
|
|
15
|
+
Check out [example](https://github.com/artemave/REST-assured-example)
|
16
|
+
|
17
|
+
|
14
18
|
## Usage
|
15
19
|
|
16
20
|
You are going to need MRI ruby >= 1.8.7 on Linux/MacOS.
|
@@ -32,7 +36,7 @@ Then install gem and run:
|
|
32
36
|
|
33
37
|
Or clone and run:
|
34
38
|
|
35
|
-
bash$ git clone git
|
39
|
+
bash$ git clone git://github.com/BBC/REST-assured.git
|
36
40
|
bash$ cd rest-assured && bundle install
|
37
41
|
bash$ ./bin/rest-assured -d :memory: & # in-memory sqlite db
|
38
42
|
|
@@ -42,7 +46,7 @@ Various options (such as ssl, port, db credentials, etc.) are available through
|
|
42
46
|
|
43
47
|
You can also deploy it to heroku:
|
44
48
|
|
45
|
-
bash$ git clone git
|
49
|
+
bash$ git clone git://github.com/BBC/REST-assured.git
|
46
50
|
bash$ cd rest-assured
|
47
51
|
|
48
52
|
bash$ gem install heroku
|
@@ -57,7 +61,7 @@ Double is a stub/spy of HTTP request. Create a double that has the same request
|
|
57
61
|
|
58
62
|
### Ruby Client API
|
59
63
|
|
60
|
-
Rest-assured provides client library to work with doubles. Check out 'Ruby API' section in [documentation](https://www.relishapp.com/artemave/rest-assured) for full reference.
|
64
|
+
Rest-assured provides client library to work with doubles. Check out 'Ruby API' section in [live documentation](https://www.relishapp.com/artemave/rest-assured) for full reference.
|
61
65
|
|
62
66
|
Start up the server:
|
63
67
|
|
@@ -209,7 +213,7 @@ Here is the rest API for managing redirects:
|
|
209
213
|
|
210
214
|
Tests require there to be mysql database `rest_assured_test` accessible by `root` with no password. Cucumber tests also need firefox.
|
211
215
|
|
212
|
-
bash$ git clone git
|
216
|
+
bash$ git clone git://github.com/BBC/REST-assured.git
|
213
217
|
bash$ cd rest-assured && bundle install
|
214
218
|
bash$ bundle exec rspec spec
|
215
219
|
bash$ bundle exec cucumber
|
@@ -46,19 +46,17 @@ Given /^I choose to delete redirect with pattern "([^"]*)"$/ do |pattern|
|
|
46
46
|
end
|
47
47
|
|
48
48
|
When /^I reorder second redirect to be the first one$/ do
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
page.execute_script %{
|
50
|
+
$('#redirects #redirect_#{RestAssured::Models::Redirect.order('position').last.id}').simulateDragSortable({move: -1, handle: '.handle'})
|
51
|
+
}
|
52
|
+
sleep 2
|
53
53
|
end
|
54
54
|
|
55
55
|
Then /^"([^"]*)" should be redirected to "([^"]*)"$/ do |missing_request, url|
|
56
|
-
pending('This does not pass due to Capybara/Selelium broken drag and drop support')
|
57
|
-
|
58
56
|
get missing_request
|
59
57
|
follow_redirect!
|
60
58
|
|
61
|
-
last_request.url.should ==
|
59
|
+
last_request.url.should == url
|
62
60
|
end
|
63
61
|
|
64
62
|
Given /^blank slate$/ do
|
@@ -49,9 +49,9 @@ Feature: manage redirects via ui
|
|
49
49
|
| /api/bbb | http://twitter.com/api |
|
50
50
|
And I am on "redirects" page
|
51
51
|
When I reorder second redirect to be the first one
|
52
|
-
Then "/api/bbb" should be redirected to "http://twitter.com/api"
|
52
|
+
Then "/api/bbb/ccc" should be redirected to "http://twitter.com/api/ccc"
|
53
53
|
When I reorder second redirect to be the first one
|
54
|
-
Then "/api/bbb" should be redirected to "http://google.com/api"
|
54
|
+
Then "/api/bbb/ccc" should be redirected to "http://google.com/api"
|
55
55
|
|
56
56
|
@javascript
|
57
57
|
Scenario: delete redirect
|
data/lib/rest-assured/version.rb
CHANGED
@@ -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);
|