jquery-mjs-nestedSortable-rails 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +147 -0
- data/lib/jquery/mjs/nestedSortable/rails.rb +12 -0
- data/lib/jquery/mjs/nestedSortable/rails/version.rb +9 -0
- data/vendor/assets/javascripts/jquery.mjs.netsedSortable.js +432 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f53549929a16d69fa3e5841844440fb089dc6d4c
|
4
|
+
data.tar.gz: f5219f306b029a13a499fd9717a664c1ff4b43eb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 739c6ebb755770dd82acaffa3ba8ffb32a2f84fb651b58d2d4135c8ecff109b70e5331b26c771d66cbe0421a68e4ed0d2f161ef60d29d4a5c5953f5d4c768fcb
|
7
|
+
data.tar.gz: db31fb694e824561abe1048debc4904e5684e5f1bc5fc07d984a6130b29495d776b257bde4fcde6ca7c80e7135091651bb5a151308ef1d5c2a9fab1b3567f8e3
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Michael Sprauer, Manuele J Sarfatti
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
# Jquery::Mjs::NestedSortable::Rails
|
2
|
+
|
3
|
+
Rails version of [mjs.nestedSortable](https://github.com/mjsarfatti/nestedSortable)
|
4
|
+
|
5
|
+
*nestedSortable* is a jQuery plugin that extends jQuery Sortable UI functionalities to nested lists.
|
6
|
+
*Note:* **Version 2.0** *is published in branch '2.0alpha' and is ready for testing! At the moment it has only been tested in Firefox and Chrome, if you work with IE feel free to give it a shot and let me know if something goes wrong.*
|
7
|
+
|
8
|
+
## Features
|
9
|
+
|
10
|
+
- Designed to work seamlessly with the [nested](http://articles.sitepoint.com/article/hierarchical-data-database "A Sitepoint tutorial on PHP, MYSQL and nested sets") [set](http://en.wikipedia.org/wiki/Nested_set_model "Wikipedia article on nested sets") model (have a look at the `toArray` method)
|
11
|
+
- Items can be sorted in their own list, moved across the tree, or nested under other items.
|
12
|
+
- Sublists are created and deleted on the fly
|
13
|
+
- All jQuery Sortable options, events and methods are available
|
14
|
+
- It is possible to define elements that will not accept a new nested item/list and a maximum depth for nested items
|
15
|
+
- The root level can be protected
|
16
|
+
|
17
|
+
## Installation
|
18
|
+
|
19
|
+
Add this line to your application's Gemfile:
|
20
|
+
|
21
|
+
gem 'jquery-mjs-nestedSortable-rails'
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
|
25
|
+
$ bundle
|
26
|
+
|
27
|
+
Or install it yourself as:
|
28
|
+
|
29
|
+
$ gem install jquery-mjs-nestedSortable-rails
|
30
|
+
|
31
|
+
## Usage
|
32
|
+
|
33
|
+
```
|
34
|
+
<ol class="sortable">
|
35
|
+
<li><div>Some content</div></li>
|
36
|
+
<li>
|
37
|
+
<div>Some content</div>
|
38
|
+
<ol>
|
39
|
+
<li><div>Some sub-item content</div></li>
|
40
|
+
<li><div>Some sub-item content</div></li>
|
41
|
+
</ol>
|
42
|
+
</li>
|
43
|
+
<li><div>Some content</div></li>
|
44
|
+
</ol>
|
45
|
+
```
|
46
|
+
|
47
|
+
```
|
48
|
+
$(document).ready(function(){
|
49
|
+
|
50
|
+
$('.sortable').nestedSortable({
|
51
|
+
handle: 'div',
|
52
|
+
items: 'li',
|
53
|
+
toleranceElement: '> div'
|
54
|
+
});
|
55
|
+
|
56
|
+
});
|
57
|
+
```
|
58
|
+
|
59
|
+
Please note: every `<li>` must have either one or two direct children, the first one being a container element (such as `<div>` in the above example), and the (optional) second one being the nested list. The container element has to be set as the 'toleranceElement' in the options, and this, or one of its children, as the 'handle'.
|
60
|
+
|
61
|
+
Also, the default list type is `<ol>`.
|
62
|
+
|
63
|
+
## Custom Options
|
64
|
+
|
65
|
+
<dl>
|
66
|
+
<dt>tabSize</dt>
|
67
|
+
<dd>How far right or left (in pixels) the item has to travel in order to be nested or to be sent outside its current list. Default: <b>20</b></dd>
|
68
|
+
<dt>disableNesting</dt>
|
69
|
+
<dd>The class name of the items that will not accept nested lists. Default: <b>ui-nestedSortable-no-nesting</b></dd>
|
70
|
+
<dt>errorClass</dt>
|
71
|
+
<dd>The class given to the placeholder in case of error. Default: <b>ui-nestedSortable-error</b></dd>
|
72
|
+
<dt>listType</dt>
|
73
|
+
<dd>The list type used (ordered or unordered). Default: <b>ol</b></dd>
|
74
|
+
<dt>maxLevels</dt>
|
75
|
+
<dd>The maximum depth of nested items the list can accept. If set to '0' the levels are unlimited. Default: <b>0</b></dd>
|
76
|
+
<dt>protectRoot</dt>
|
77
|
+
<dd>Wether to protect the root level (i.e. root items can be sorted but not nested, sub-items cannot become root items). Default: <b>false</b></dd>
|
78
|
+
<dt>rootID</dt>
|
79
|
+
<dd>The id given to the root element (set this to whatever suits your data structure). Default: <b>null</b></dd>
|
80
|
+
<dt>rtl</dt>
|
81
|
+
<dd>Set this to true if you have a right-to-left page. Default: <b>false</b></dd>
|
82
|
+
<dt>isAllowed (function)</dt>
|
83
|
+
<dd>You can specify a custom function to verify if a drop location is allowed. Default: <b>function(item, parent) { return true; }</b></dd>
|
84
|
+
</dl>
|
85
|
+
|
86
|
+
## Custom Methods
|
87
|
+
|
88
|
+
<dl>
|
89
|
+
<dt>serialize</dt>
|
90
|
+
<dd>Serializes the nested list into a string like <b>setName[item1Id]=parentId&setName[item2Id]=parentId</b>, reading from each item's id formatted as 'setName_itemId' (where itemId is a number).
|
91
|
+
It accepts the same options as the original Sortable method (<b>key</b>, <b>attribute</b> and <b>expression</b>).</dd>
|
92
|
+
<dt>toArray</dt>
|
93
|
+
<dd>Builds an array where each element is in the form:
|
94
|
+
<pre>setName[n] =>
|
95
|
+
{
|
96
|
+
'item_id': itemId,
|
97
|
+
'parent_id': parentId,
|
98
|
+
'depth': depth,
|
99
|
+
'left': left,
|
100
|
+
'right': right,
|
101
|
+
}
|
102
|
+
</pre>
|
103
|
+
It accepts the same options as the original Sortable method (<b>attribute</b> and <b>expression</b>) plus the custom <b>startDepthCount</b>, that sets the starting depth number (default is <b>0</b>).</dd>
|
104
|
+
<dt>toHierarchy</dt>
|
105
|
+
<dd>Builds a hierarchical object in the form:
|
106
|
+
<pre>'0' ...
|
107
|
+
'id' => itemId
|
108
|
+
'1' ...
|
109
|
+
'id' => itemId
|
110
|
+
'children' ...
|
111
|
+
'0' ...
|
112
|
+
'id' => itemId
|
113
|
+
'1' ...
|
114
|
+
'id' => itemId
|
115
|
+
'2' ...
|
116
|
+
'id' => itemId
|
117
|
+
</pre>
|
118
|
+
Similarly to <code>toArray</code>, it accepts <b>attribute</b> and <b>expression</b> options.</dd>
|
119
|
+
</dl>
|
120
|
+
|
121
|
+
## Known Bugs
|
122
|
+
|
123
|
+
*nestedSortable* doesn't work properly with connected draggables, because of the way Draggable simulates Sortable `mouseStart` and `mouseStop` events. This bug might or might not be fixed some time in the future (it's not specific to this plugin).
|
124
|
+
|
125
|
+
## Requirements
|
126
|
+
|
127
|
+
jQuery 1.4+
|
128
|
+
jQuery UI Sortable 1.8+
|
129
|
+
|
130
|
+
## Browser Compatibility
|
131
|
+
|
132
|
+
Tested with: IE 6/7/8, Firefox 3.6/4, Chrome, Safari 3
|
133
|
+
|
134
|
+
## License
|
135
|
+
|
136
|
+
This work is licensed under the MIT License.
|
137
|
+
|
138
|
+
This work is *pizzaware*. If it saved your life, or you just feel good at heart, please consider offering me a pizza. This can be done in two ways: (1) follow [this link](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=RSJEW3N9PRMYY&lc=IT&item_name=Manuele%20Sarfatti¤cy_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted) to donate through paypal; (2) send me cash via traditional mail to my home address in Italy. Is the second method legal? It is in Italy if you use Posta assicurata. You should check with your local laws if you live elsewhere.
|
139
|
+
|
140
|
+
## Contributing
|
141
|
+
|
142
|
+
1. Fork it ( http://github.com/<my-github-username>/jquery-mjs-nestedSortable-rails/fork )
|
143
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
144
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
145
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
146
|
+
5. Create new Pull Request
|
147
|
+
|
@@ -0,0 +1,432 @@
|
|
1
|
+
/*
|
2
|
+
* jQuery UI Nested Sortable
|
3
|
+
* v 1.3.5 / 21 jun 2012
|
4
|
+
* http://mjsarfatti.com/code/nestedSortable
|
5
|
+
*
|
6
|
+
* Depends on:
|
7
|
+
* jquery.ui.sortable.js 1.8+
|
8
|
+
*
|
9
|
+
* Copyright (c) 2010-2012 Manuele J Sarfatti
|
10
|
+
* Licensed under the MIT License
|
11
|
+
* http://www.opensource.org/licenses/mit-license.php
|
12
|
+
*/
|
13
|
+
|
14
|
+
(function ($) {
|
15
|
+
|
16
|
+
$.widget("mjs.nestedSortable", $.extend({}, $.ui.sortable.prototype, {
|
17
|
+
|
18
|
+
options: {
|
19
|
+
tabSize: 20,
|
20
|
+
disableNesting: 'mjs-nestedSortable-no-nesting',
|
21
|
+
errorClass: 'mjs-nestedSortable-error',
|
22
|
+
doNotClear: false,
|
23
|
+
listType: 'ol',
|
24
|
+
maxLevels: 0,
|
25
|
+
protectRoot: false,
|
26
|
+
rootID: null,
|
27
|
+
rtl: false,
|
28
|
+
isAllowed: function (item, parent) {
|
29
|
+
return true;
|
30
|
+
}
|
31
|
+
},
|
32
|
+
|
33
|
+
_create: function () {
|
34
|
+
this.element.data('sortable', this.element.data('nestedSortable'));
|
35
|
+
|
36
|
+
if (!this.element.is(this.options.listType))
|
37
|
+
throw new Error('nestedSortable: Please check the listType option is set to your actual list type');
|
38
|
+
|
39
|
+
return $.ui.sortable.prototype._create.apply(this, arguments);
|
40
|
+
},
|
41
|
+
|
42
|
+
destroy: function () {
|
43
|
+
this.element
|
44
|
+
.removeData("nestedSortable")
|
45
|
+
.unbind(".nestedSortable");
|
46
|
+
return $.ui.sortable.prototype.destroy.apply(this, arguments);
|
47
|
+
},
|
48
|
+
|
49
|
+
_mouseDrag: function (event) {
|
50
|
+
|
51
|
+
//Compute the helpers position
|
52
|
+
this.position = this._generatePosition(event);
|
53
|
+
this.positionAbs = this._convertPositionTo("absolute");
|
54
|
+
|
55
|
+
if (!this.lastPositionAbs) {
|
56
|
+
this.lastPositionAbs = this.positionAbs;
|
57
|
+
}
|
58
|
+
|
59
|
+
var o = this.options;
|
60
|
+
|
61
|
+
//Do scrolling
|
62
|
+
if (this.options.scroll) {
|
63
|
+
var scrolled = false;
|
64
|
+
if (this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
|
65
|
+
|
66
|
+
if ((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
|
67
|
+
this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
|
68
|
+
else if (event.pageY - this.overflowOffset.top < o.scrollSensitivity)
|
69
|
+
this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
|
70
|
+
|
71
|
+
if ((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
|
72
|
+
this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
|
73
|
+
else if (event.pageX - this.overflowOffset.left < o.scrollSensitivity)
|
74
|
+
this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
|
75
|
+
|
76
|
+
} else {
|
77
|
+
|
78
|
+
if (event.pageY - $(document).scrollTop() < o.scrollSensitivity)
|
79
|
+
scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
|
80
|
+
else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
|
81
|
+
scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
|
82
|
+
|
83
|
+
if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
|
84
|
+
scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
|
85
|
+
else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
|
86
|
+
scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
|
87
|
+
|
88
|
+
}
|
89
|
+
|
90
|
+
if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
|
91
|
+
$.ui.ddmanager.prepareOffsets(this, event);
|
92
|
+
}
|
93
|
+
|
94
|
+
//Regenerate the absolute position used for position checks
|
95
|
+
this.positionAbs = this._convertPositionTo("absolute");
|
96
|
+
|
97
|
+
// Find the top offset before rearrangement,
|
98
|
+
var previousTopOffset = this.placeholder.offset().top;
|
99
|
+
|
100
|
+
//Set the helper position
|
101
|
+
if (!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left + 'px';
|
102
|
+
if (!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top + 'px';
|
103
|
+
|
104
|
+
//Rearrange
|
105
|
+
for (var i = this.items.length - 1; i >= 0; i--) {
|
106
|
+
|
107
|
+
//Cache variables and intersection, continue if no intersection
|
108
|
+
var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
|
109
|
+
if (!intersection) continue;
|
110
|
+
|
111
|
+
if (itemElement != this.currentItem[0] //cannot intersect with itself
|
112
|
+
&& this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
|
113
|
+
&& !$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
|
114
|
+
&& (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true)
|
115
|
+
//&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
|
116
|
+
) {
|
117
|
+
|
118
|
+
$(itemElement).mouseenter();
|
119
|
+
|
120
|
+
this.direction = intersection == 1 ? "down" : "up";
|
121
|
+
|
122
|
+
if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
|
123
|
+
$(itemElement).mouseleave();
|
124
|
+
this._rearrange(event, item);
|
125
|
+
} else {
|
126
|
+
break;
|
127
|
+
}
|
128
|
+
|
129
|
+
// Clear emtpy ul's/ol's
|
130
|
+
this._clearEmpty(itemElement);
|
131
|
+
|
132
|
+
this._trigger("change", event, this._uiHash());
|
133
|
+
break;
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
var parentItem = (this.placeholder[0].parentNode.parentNode &&
|
138
|
+
$(this.placeholder[0].parentNode.parentNode).closest('.ui-sortable').length)
|
139
|
+
? $(this.placeholder[0].parentNode.parentNode)
|
140
|
+
: null,
|
141
|
+
level = this._getLevel(this.placeholder),
|
142
|
+
childLevels = this._getChildLevels(this.helper);
|
143
|
+
|
144
|
+
// To find the previous sibling in the list, keep backtracking until we hit a valid list item.
|
145
|
+
var previousItem = this.placeholder[0].previousSibling ? $(this.placeholder[0].previousSibling) : null;
|
146
|
+
if (previousItem != null) {
|
147
|
+
while (previousItem[0].nodeName.toLowerCase() != 'li' || previousItem[0] == this.currentItem[0] || previousItem[0] == this.helper[0]) {
|
148
|
+
if (previousItem[0].previousSibling) {
|
149
|
+
previousItem = $(previousItem[0].previousSibling);
|
150
|
+
} else {
|
151
|
+
previousItem = null;
|
152
|
+
break;
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
156
|
+
|
157
|
+
// To find the next sibling in the list, keep stepping forward until we hit a valid list item.
|
158
|
+
var nextItem = this.placeholder[0].nextSibling ? $(this.placeholder[0].nextSibling) : null;
|
159
|
+
if (nextItem != null) {
|
160
|
+
while (nextItem[0].nodeName.toLowerCase() != 'li' || nextItem[0] == this.currentItem[0] || nextItem[0] == this.helper[0]) {
|
161
|
+
if (nextItem[0].nextSibling) {
|
162
|
+
nextItem = $(nextItem[0].nextSibling);
|
163
|
+
} else {
|
164
|
+
nextItem = null;
|
165
|
+
break;
|
166
|
+
}
|
167
|
+
}
|
168
|
+
}
|
169
|
+
|
170
|
+
var newList = document.createElement(o.listType);
|
171
|
+
|
172
|
+
this.beyondMaxLevels = 0;
|
173
|
+
|
174
|
+
// If the item is moved to the left, send it to its parent's level unless there are siblings below it.
|
175
|
+
if (parentItem != null && nextItem == null &&
|
176
|
+
(o.rtl && (this.positionAbs.left + this.helper.outerWidth() > parentItem.offset().left + parentItem.outerWidth()) ||
|
177
|
+
!o.rtl && (this.positionAbs.left < parentItem.offset().left))) {
|
178
|
+
parentItem.after(this.placeholder[0]);
|
179
|
+
this._clearEmpty(parentItem[0]);
|
180
|
+
this._trigger("change", event, this._uiHash());
|
181
|
+
}
|
182
|
+
// If the item is below a sibling and is moved to the right, make it a child of that sibling.
|
183
|
+
else if (previousItem != null &&
|
184
|
+
(o.rtl && (this.positionAbs.left + this.helper.outerWidth() < previousItem.offset().left + previousItem.outerWidth() - o.tabSize) ||
|
185
|
+
!o.rtl && (this.positionAbs.left > previousItem.offset().left + o.tabSize))) {
|
186
|
+
this._isAllowed(previousItem, level, level + childLevels + 1);
|
187
|
+
if (!previousItem.children(o.listType).length) {
|
188
|
+
previousItem[0].appendChild(newList);
|
189
|
+
}
|
190
|
+
// If this item is being moved from the top, add it to the top of the list.
|
191
|
+
if (previousTopOffset && (previousTopOffset <= previousItem.offset().top)) {
|
192
|
+
previousItem.children(o.listType).prepend(this.placeholder);
|
193
|
+
}
|
194
|
+
// Otherwise, add it to the bottom of the list.
|
195
|
+
else {
|
196
|
+
previousItem.children(o.listType)[0].appendChild(this.placeholder[0]);
|
197
|
+
}
|
198
|
+
this._trigger("change", event, this._uiHash());
|
199
|
+
}
|
200
|
+
else {
|
201
|
+
this._isAllowed(parentItem, level, level + childLevels);
|
202
|
+
}
|
203
|
+
|
204
|
+
//Post events to containers
|
205
|
+
this._contactContainers(event);
|
206
|
+
|
207
|
+
//Interconnect with droppables
|
208
|
+
if ($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
|
209
|
+
|
210
|
+
//Call callbacks
|
211
|
+
this._trigger('sort', event, this._uiHash());
|
212
|
+
|
213
|
+
this.lastPositionAbs = this.positionAbs;
|
214
|
+
return false;
|
215
|
+
|
216
|
+
},
|
217
|
+
|
218
|
+
_mouseStop: function (event, noPropagation) {
|
219
|
+
|
220
|
+
// If the item is in a position not allowed, send it back
|
221
|
+
if (this.beyondMaxLevels) {
|
222
|
+
|
223
|
+
this.placeholder.removeClass(this.options.errorClass);
|
224
|
+
|
225
|
+
if (this.domPosition.prev) {
|
226
|
+
$(this.domPosition.prev).after(this.placeholder);
|
227
|
+
} else {
|
228
|
+
$(this.domPosition.parent).prepend(this.placeholder);
|
229
|
+
}
|
230
|
+
|
231
|
+
this._trigger("revert", event, this._uiHash());
|
232
|
+
|
233
|
+
}
|
234
|
+
|
235
|
+
// Clean last empty ul/ol
|
236
|
+
for (var i = this.items.length - 1; i >= 0; i--) {
|
237
|
+
var item = this.items[i].item[0];
|
238
|
+
this._clearEmpty(item);
|
239
|
+
}
|
240
|
+
|
241
|
+
$.ui.sortable.prototype._mouseStop.apply(this, arguments);
|
242
|
+
|
243
|
+
},
|
244
|
+
|
245
|
+
serialize: function (options) {
|
246
|
+
|
247
|
+
var o = $.extend({}, this.options, options),
|
248
|
+
items = this._getItemsAsjQuery(o && o.connected),
|
249
|
+
str = [];
|
250
|
+
|
251
|
+
$(items).each(function () {
|
252
|
+
var res = ($(o.item || this).attr(o.attribute || 'id') || '')
|
253
|
+
.match(o.expression || (/(.+)[-=_](.+)/)),
|
254
|
+
pid = ($(o.item || this).parent(o.listType)
|
255
|
+
.parent(o.items)
|
256
|
+
.attr(o.attribute || 'id') || '')
|
257
|
+
.match(o.expression || (/(.+)[-=_](.+)/));
|
258
|
+
|
259
|
+
if (res) {
|
260
|
+
str.push(((o.key || res[1]) + '[' + (o.key && o.expression ? res[1] : res[2]) + ']')
|
261
|
+
+ '='
|
262
|
+
+ (pid ? (o.key && o.expression ? pid[1] : pid[2]) : o.rootID));
|
263
|
+
}
|
264
|
+
});
|
265
|
+
|
266
|
+
if (!str.length && o.key) {
|
267
|
+
str.push(o.key + '=');
|
268
|
+
}
|
269
|
+
|
270
|
+
return str.join('&');
|
271
|
+
|
272
|
+
},
|
273
|
+
|
274
|
+
toHierarchy: function (options) {
|
275
|
+
|
276
|
+
var o = $.extend({}, this.options, options),
|
277
|
+
sDepth = o.startDepthCount || 0,
|
278
|
+
ret = [];
|
279
|
+
|
280
|
+
$(this.element).children(o.items).each(function () {
|
281
|
+
var level = _recursiveItems(this);
|
282
|
+
ret.push(level);
|
283
|
+
});
|
284
|
+
|
285
|
+
return ret;
|
286
|
+
|
287
|
+
function _recursiveItems(item) {
|
288
|
+
var id = ($(item).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
|
289
|
+
if (id) {
|
290
|
+
var currentItem = {"id": id[2]};
|
291
|
+
if ($(item).children(o.listType).children(o.items).length > 0) {
|
292
|
+
currentItem.children = [];
|
293
|
+
$(item).children(o.listType).children(o.items).each(function () {
|
294
|
+
var level = _recursiveItems(this);
|
295
|
+
currentItem.children.push(level);
|
296
|
+
});
|
297
|
+
}
|
298
|
+
return currentItem;
|
299
|
+
}
|
300
|
+
}
|
301
|
+
},
|
302
|
+
|
303
|
+
toArray: function (options) {
|
304
|
+
|
305
|
+
var o = $.extend({}, this.options, options),
|
306
|
+
sDepth = o.startDepthCount || 0,
|
307
|
+
ret = [],
|
308
|
+
left = 2;
|
309
|
+
|
310
|
+
ret.push({
|
311
|
+
"item_id": o.rootID,
|
312
|
+
"parent_id": 'none',
|
313
|
+
"depth": sDepth,
|
314
|
+
"left": '1',
|
315
|
+
"right": ($(o.items, this.element).length + 1) * 2
|
316
|
+
});
|
317
|
+
|
318
|
+
$(this.element).children(o.items).each(function () {
|
319
|
+
left = _recursiveArray(this, sDepth + 1, left);
|
320
|
+
});
|
321
|
+
|
322
|
+
ret = ret.sort(function (a, b) {
|
323
|
+
return (a.left - b.left);
|
324
|
+
});
|
325
|
+
|
326
|
+
return ret;
|
327
|
+
|
328
|
+
function _recursiveArray(item, depth, left) {
|
329
|
+
|
330
|
+
var right = left + 1,
|
331
|
+
id,
|
332
|
+
pid;
|
333
|
+
|
334
|
+
if ($(item).children(o.listType).children(o.items).length > 0) {
|
335
|
+
depth++;
|
336
|
+
$(item).children(o.listType).children(o.items).each(function () {
|
337
|
+
right = _recursiveArray($(this), depth, right);
|
338
|
+
});
|
339
|
+
depth--;
|
340
|
+
}
|
341
|
+
|
342
|
+
id = ($(item).attr(o.attribute || 'id')).match(o.expression || (/(.+)[-=_](.+)/));
|
343
|
+
|
344
|
+
if (depth === sDepth + 1) {
|
345
|
+
pid = o.rootID;
|
346
|
+
} else {
|
347
|
+
var parentItem = ($(item).parent(o.listType)
|
348
|
+
.parent(o.items)
|
349
|
+
.attr(o.attribute || 'id'))
|
350
|
+
.match(o.expression || (/(.+)[-=_](.+)/));
|
351
|
+
pid = parentItem[2];
|
352
|
+
}
|
353
|
+
|
354
|
+
if (id) {
|
355
|
+
ret.push({"item_id": id[2], "parent_id": pid, "depth": depth, "left": left, "right": right});
|
356
|
+
}
|
357
|
+
|
358
|
+
left = right + 1;
|
359
|
+
return left;
|
360
|
+
}
|
361
|
+
|
362
|
+
},
|
363
|
+
|
364
|
+
_clearEmpty: function (item) {
|
365
|
+
|
366
|
+
var emptyList = $(item).children(this.options.listType);
|
367
|
+
if (emptyList.length && !emptyList.children().length && !this.options.doNotClear) {
|
368
|
+
emptyList.remove();
|
369
|
+
}
|
370
|
+
|
371
|
+
},
|
372
|
+
|
373
|
+
_getLevel: function (item) {
|
374
|
+
|
375
|
+
var level = 1;
|
376
|
+
|
377
|
+
if (this.options.listType) {
|
378
|
+
var list = item.closest(this.options.listType);
|
379
|
+
while (list && list.length > 0 && !list.is('.ui-sortable')) {
|
380
|
+
level++;
|
381
|
+
list = list.parent().closest(this.options.listType);
|
382
|
+
}
|
383
|
+
}
|
384
|
+
|
385
|
+
return level;
|
386
|
+
},
|
387
|
+
|
388
|
+
_getChildLevels: function (parent, depth) {
|
389
|
+
var self = this,
|
390
|
+
o = this.options,
|
391
|
+
result = 0;
|
392
|
+
depth = depth || 0;
|
393
|
+
|
394
|
+
$(parent).children(o.listType).children(o.items).each(function (index, child) {
|
395
|
+
result = Math.max(self._getChildLevels(child, depth + 1), result);
|
396
|
+
});
|
397
|
+
|
398
|
+
return depth ? result + 1 : result;
|
399
|
+
},
|
400
|
+
|
401
|
+
_isAllowed: function (parentItem, level, levels) {
|
402
|
+
var o = this.options,
|
403
|
+
isRoot = $(this.domPosition.parent).hasClass('ui-sortable') ? true : false,
|
404
|
+
maxLevels = this.placeholder.closest('.ui-sortable').nestedSortable('option', 'maxLevels'); // this takes into account the maxLevels set to the recipient list
|
405
|
+
|
406
|
+
// Is the root protected?
|
407
|
+
// Are we trying to nest under a no-nest?
|
408
|
+
// Are we nesting too deep?
|
409
|
+
if (!o.isAllowed(this.currentItem, parentItem) ||
|
410
|
+
parentItem && parentItem.hasClass(o.disableNesting) ||
|
411
|
+
o.protectRoot && (parentItem == null && !isRoot || isRoot && level > 1)) {
|
412
|
+
this.placeholder.addClass(o.errorClass);
|
413
|
+
if (maxLevels < levels && maxLevels != 0) {
|
414
|
+
this.beyondMaxLevels = levels - maxLevels;
|
415
|
+
} else {
|
416
|
+
this.beyondMaxLevels = 1;
|
417
|
+
}
|
418
|
+
} else {
|
419
|
+
if (maxLevels < levels && maxLevels != 0) {
|
420
|
+
this.placeholder.addClass(o.errorClass);
|
421
|
+
this.beyondMaxLevels = levels - maxLevels;
|
422
|
+
} else {
|
423
|
+
this.placeholder.removeClass(o.errorClass);
|
424
|
+
this.beyondMaxLevels = 0;
|
425
|
+
}
|
426
|
+
}
|
427
|
+
}
|
428
|
+
|
429
|
+
}));
|
430
|
+
|
431
|
+
$.mjs.nestedSortable.prototype.options = $.extend({}, $.ui.sortable.prototype.options, $.mjs.nestedSortable.prototype.options);
|
432
|
+
})(jQuery);
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jquery-mjs-nestedSortable-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Sprauer
|
8
|
+
- Manuele J Sarfatti
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2014-03-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ~>
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.5'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1.5'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rake
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - '>='
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
description: |
|
43
|
+
Features
|
44
|
+
Designed to work seamlessly with the nested set model (have a look at the toArray method)
|
45
|
+
Items can be sorted in their own list, moved across the tree, or nested under other items.
|
46
|
+
Sublists are created and deleted on the fly
|
47
|
+
All jQuery Sortable options, events and methods are available
|
48
|
+
It is possible to define elements that will not accept a new nested item/list and a maximum depth for nested items
|
49
|
+
The root level can be protected
|
50
|
+
email:
|
51
|
+
- Sprauer@Inline.de
|
52
|
+
executables: []
|
53
|
+
extensions: []
|
54
|
+
extra_rdoc_files: []
|
55
|
+
files:
|
56
|
+
- LICENSE.txt
|
57
|
+
- README.md
|
58
|
+
- lib/jquery/mjs/nestedSortable/rails.rb
|
59
|
+
- lib/jquery/mjs/nestedSortable/rails/version.rb
|
60
|
+
- vendor/assets/javascripts/jquery.mjs.netsedSortable.js
|
61
|
+
homepage: https://github.com/MichaelSp/jquery.mjs.nestedSortable-rails
|
62
|
+
licenses:
|
63
|
+
- MIT
|
64
|
+
metadata: {}
|
65
|
+
post_install_message:
|
66
|
+
rdoc_options: []
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
requirements: []
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 2.2.2
|
82
|
+
signing_key:
|
83
|
+
specification_version: 4
|
84
|
+
summary: nestedSortable is a jQuery plugin for rails that extends jQuery Sortable
|
85
|
+
UI functionalities to nested lists.
|
86
|
+
test_files: []
|