the_sortable_tree_mongoid 1.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/README.md +302 -0
- data/Rakefile +37 -0
- data/app/assets/images/iconza/blue/add.png +0 -0
- data/app/assets/images/iconza/blue/delete.png +0 -0
- data/app/assets/images/iconza/blue/down.png +0 -0
- data/app/assets/images/iconza/blue/downloads_folder.png +0 -0
- data/app/assets/images/iconza/blue/edit.png +0 -0
- data/app/assets/images/iconza/blue/move.png +0 -0
- data/app/assets/images/iconza/blue/up.png +0 -0
- data/app/assets/images/iconza/gray/add.png +0 -0
- data/app/assets/images/iconza/gray/delete.png +0 -0
- data/app/assets/images/iconza/gray/down.png +0 -0
- data/app/assets/images/iconza/gray/edit.png +0 -0
- data/app/assets/images/iconza/gray/lock.png +0 -0
- data/app/assets/images/iconza/gray/mail.png +0 -0
- data/app/assets/images/iconza/gray/push_pin.png +0 -0
- data/app/assets/images/iconza/gray/up.png +0 -0
- data/app/assets/images/iconza/red/add.png +0 -0
- data/app/assets/images/iconza/red/delete.png +0 -0
- data/app/assets/images/iconza/red/down.png +0 -0
- data/app/assets/images/iconza/red/edit.png +0 -0
- data/app/assets/images/iconza/red/newspaper.png +0 -0
- data/app/assets/images/iconza/red/trash.png +0 -0
- data/app/assets/images/iconza/red/up.png +0 -0
- data/app/assets/images/iconza/red/zoom.png +0 -0
- data/app/assets/javascripts/jquery.ui.nestedSortable.js +356 -0
- data/app/assets/stylesheets/the_sortable_tree.css +120 -0
- data/app/assets/stylesheets/the_sortable_tree_min.css +26 -0
- data/app/controllers/the_sortable_tree_controller.rb +67 -0
- data/app/helpers/the_sortable_tree_helper.rb +69 -0
- data/app/views/the_sortable_tree/_children.html.haml +1 -0
- data/app/views/the_sortable_tree/_controls.html.haml +16 -0
- data/app/views/the_sortable_tree/_js_init_sortable_tree.html.haml +17 -0
- data/app/views/the_sortable_tree/_js_on_update_tree.html.haml +12 -0
- data/app/views/the_sortable_tree/_js_rebuild_ajax.html.haml +13 -0
- data/app/views/the_sortable_tree/_link.html.haml +7 -0
- data/app/views/the_sortable_tree/_new.html.haml +3 -0
- data/app/views/the_sortable_tree/_node.html.haml +3 -0
- data/app/views/the_sortable_tree/_tree.html.haml +6 -0
- data/app/views/the_sortable_tree_min/_children.html.haml +1 -0
- data/app/views/the_sortable_tree_min/_link.html.haml +1 -0
- data/app/views/the_sortable_tree_min/_node.html.haml +3 -0
- data/app/views/the_sortable_tree_min/_tree.html.haml +2 -0
- data/config/locales/en.yml +10 -0
- data/config/locales/ru.yml +10 -0
- data/lib/generators/the_sortable_tree/views_generator.rb +29 -0
- data/lib/tasks/the_sortable_tree.rake +4 -0
- data/lib/the_sortable_tree.rb +18 -0
- data/lib/the_sortable_tree/engine.rb +6 -0
- data/lib/the_sortable_tree/version.rb +3 -0
- data/spec/controlllers/controller_mixin_spec.rb +49 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/tests_controller.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +17 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +56 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +3 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/test.log +4 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/spec_helper.rb +15 -0
- metadata +231 -0
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2009-2012 Ilya N. Zykin, Matthew Clark
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
### TheSortableTree
|
|
2
|
+
|
|
3
|
+
Engine Based Drag&Drop GUI for awesome_nested_set gem. **Rails >= 3.1**
|
|
4
|
+
|
|
5
|
+
School teacher came to help! TaDa! ;)
|
|
6
|
+
|
|
7
|
+
**Drag&Drop sortable tree**
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
**Simple nested sets (__min__ option)**
|
|
12
|
+
|
|
13
|
+

|
|
14
|
+
|
|
15
|
+
**sortable_tree** - recursive helper-method for render sortable awesome_nested_set tree.
|
|
16
|
+
|
|
17
|
+
**sortable_tree** uses partials for rendering, that's why it is **so easy to customize**!
|
|
18
|
+
|
|
19
|
+
### List of available variants of rendering
|
|
20
|
+
|
|
21
|
+
* Drag&Drop sortable tree
|
|
22
|
+
* Simple nested sets (**min** option)
|
|
23
|
+
* Nested sets with expand/collapse animation (**expand** option) [under development]
|
|
24
|
+
* Nested comments (**comments** option) [under development]
|
|
25
|
+
|
|
26
|
+
### Can I use gem with Rails 2 or Rails 3.0?
|
|
27
|
+
|
|
28
|
+
Take files from the gem and put it in your rails 2 application.
|
|
29
|
+
|
|
30
|
+
View helper and view files does not depend on the version of rails.
|
|
31
|
+
|
|
32
|
+
Copy and Paste rebuild function from TheSortableTreeController.
|
|
33
|
+
|
|
34
|
+
Perhaps, you may have to slightly change the function of the controller.
|
|
35
|
+
|
|
36
|
+
### Changelog
|
|
37
|
+
|
|
38
|
+
1.8.5 - helper can rendering a part tree
|
|
39
|
+
|
|
40
|
+
1.8.0 - stable release
|
|
41
|
+
|
|
42
|
+
### Is it fast?
|
|
43
|
+
|
|
44
|
+
Hmmmm...
|
|
45
|
+
|
|
46
|
+
* Development env
|
|
47
|
+
* 584 elements
|
|
48
|
+
* 3 levels deep
|
|
49
|
+
|
|
50
|
+
Rendered by 50 sec.
|
|
51
|
+
|
|
52
|
+
I think it is good result for rendering by partials.
|
|
53
|
+
|
|
54
|
+
Can you makes it faster? Welcome!
|
|
55
|
+
|
|
56
|
+
### ERB vs HAML vs SLIM
|
|
57
|
+
|
|
58
|
+
So, ERB and SLIM fans want to make gem independent of HAML.
|
|
59
|
+
|
|
60
|
+
Ok, let it be. But you will convert view partials youself. It's my revenge ;)
|
|
61
|
+
|
|
62
|
+
Read project wiki for looking ERB partials
|
|
63
|
+
|
|
64
|
+
**By default I'm use HAML, and now you should define it manually in your Gemfile.**
|
|
65
|
+
|
|
66
|
+
### Install
|
|
67
|
+
|
|
68
|
+
gem 'haml'
|
|
69
|
+
gem 'awesome_nested_set' # gem 'nested_set'
|
|
70
|
+
gem 'the_sortable_tree'
|
|
71
|
+
|
|
72
|
+
bundle
|
|
73
|
+
|
|
74
|
+
### Require
|
|
75
|
+
|
|
76
|
+
1. gem 'nested_set' or gem 'awesome_nested_set'
|
|
77
|
+
2. gem 'haml'
|
|
78
|
+
3. JQuery UI
|
|
79
|
+
|
|
80
|
+
### Example of using with Page Model
|
|
81
|
+
|
|
82
|
+
### Jquery
|
|
83
|
+
|
|
84
|
+
**app/assets/javascripts/application.js**
|
|
85
|
+
|
|
86
|
+
``` ruby
|
|
87
|
+
//= require jquery
|
|
88
|
+
//= require jquery-ui
|
|
89
|
+
//= require jquery_ujs
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Extend your Model
|
|
93
|
+
|
|
94
|
+
``` ruby
|
|
95
|
+
class Page < ActiveRecord::Base
|
|
96
|
+
include TheSortableTree::Scopes
|
|
97
|
+
# any code here
|
|
98
|
+
end
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Extend your Controller
|
|
102
|
+
|
|
103
|
+
``` ruby
|
|
104
|
+
class PagesController < ApplicationController
|
|
105
|
+
include TheSortableTreeController::Rebuild
|
|
106
|
+
# any code here
|
|
107
|
+
end
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
or (for reversed tree)
|
|
111
|
+
|
|
112
|
+
``` ruby
|
|
113
|
+
class PagesController < ApplicationController
|
|
114
|
+
include TheSortableTreeController::ReversedRebuild
|
|
115
|
+
# any code here
|
|
116
|
+
end
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Extend your Routes
|
|
120
|
+
|
|
121
|
+
``` ruby
|
|
122
|
+
resources :pages do
|
|
123
|
+
collection do
|
|
124
|
+
get :manage
|
|
125
|
+
post :rebuild
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
**manage** action or any else action for show sortable tree
|
|
131
|
+
|
|
132
|
+
**rebuild** action is _required_ action for correctly work of **the_sortable_tree**
|
|
133
|
+
|
|
134
|
+
### Find your tree
|
|
135
|
+
|
|
136
|
+
``` ruby
|
|
137
|
+
class PagesController < ApplicationController
|
|
138
|
+
include TheSortableTreeController::Rebuild
|
|
139
|
+
|
|
140
|
+
def manage
|
|
141
|
+
@pages = Page.nested_set.all
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# any code here
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
or
|
|
150
|
+
|
|
151
|
+
``` ruby
|
|
152
|
+
class PagesController < ApplicationController
|
|
153
|
+
include TheSortableTreeController::ReversedRebuild
|
|
154
|
+
|
|
155
|
+
def manage
|
|
156
|
+
@pages = Page.reversed_nested_set.all
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# any code here
|
|
160
|
+
end
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Render your tree with TheSortableTree (Haml markup)
|
|
164
|
+
|
|
165
|
+
``` ruby
|
|
166
|
+
- content_for :css do
|
|
167
|
+
= stylesheet_link_tag 'the_sortable_tree', :media => :screen
|
|
168
|
+
- content_for :js do
|
|
169
|
+
= javascript_include_tag 'jquery.ui.nestedSortable'
|
|
170
|
+
|
|
171
|
+
= sortable_tree @pages, :new_url => new_page_path, :max_levels => 4
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
or (without administrator controls and drag&drop)
|
|
175
|
+
|
|
176
|
+
``` ruby
|
|
177
|
+
- content_for :css do
|
|
178
|
+
= stylesheet_link_tag 'the_sortable_tree_min', :media => :screen
|
|
179
|
+
|
|
180
|
+
= sortable_tree @pages, :new_url => new_page_path, :path => 'the_sortable_tree_min'
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Customize tree for User (min version)
|
|
184
|
+
|
|
185
|
+
**Use sortable_tree as view helper for simple rendering of nested_set tree**
|
|
186
|
+
|
|
187
|
+
``` ruby
|
|
188
|
+
rails g the_sortable_tree:views pages min
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
It's will generate minimal set of view partials for **sortable_tree** helper
|
|
192
|
+
|
|
193
|
+
``` ruby
|
|
194
|
+
create app/views/pages/the_sortable_tree_min
|
|
195
|
+
create app/views/pages/the_sortable_tree_min/_children.html.haml
|
|
196
|
+
create app/views/pages/the_sortable_tree_min/_node.html.haml
|
|
197
|
+
create app/views/pages/the_sortable_tree_min/_link.html.haml
|
|
198
|
+
create app/views/pages/the_sortable_tree_min/_tree.html.haml
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Just use it or Customize and use it!
|
|
202
|
+
|
|
203
|
+
``` ruby
|
|
204
|
+
- content_for :css do
|
|
205
|
+
= stylesheet_link_tag 'the_sortable_tree_min', :media => :screen
|
|
206
|
+
= sortable_tree @pages, :new_url => new_page_path, :path => 'pages/the_sortable_tree_min'
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Customize tree for Administrator (full version)
|
|
210
|
+
|
|
211
|
+
``` ruby
|
|
212
|
+
rails g the_sortable_tree:views pages
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
It's will generate view partials for **sortable_tree** helper
|
|
216
|
+
|
|
217
|
+
``` ruby
|
|
218
|
+
create app/views/pages/the_sortable_tree
|
|
219
|
+
create app/views/pages/the_sortable_tree/_controls.html.haml
|
|
220
|
+
create app/views/pages/the_sortable_tree/_node.html.haml
|
|
221
|
+
create app/views/pages/the_sortable_tree/_js_init_sortable_tree.html.haml
|
|
222
|
+
create app/views/pages/the_sortable_tree/_js_on_update_tree.html.haml
|
|
223
|
+
create app/views/pages/the_sortable_tree/_js_rebuild_ajax.html.haml
|
|
224
|
+
create app/views/pages/the_sortable_tree/_link.html.haml
|
|
225
|
+
create app/views/pages/the_sortable_tree/_children.html.haml
|
|
226
|
+
create app/views/pages/the_sortable_tree/_new.html.haml
|
|
227
|
+
create app/views/pages/the_sortable_tree/_tree.html.haml
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Customize and use it!
|
|
231
|
+
|
|
232
|
+
``` ruby
|
|
233
|
+
- content_for :css do
|
|
234
|
+
= stylesheet_link_tag 'the_sortable_tree', :media => :screen
|
|
235
|
+
- content_for :js do
|
|
236
|
+
= javascript_include_tag 'jquery.ui.nestedSortable'
|
|
237
|
+
|
|
238
|
+
= sortable_tree @pages, :new_url => new_page_path, :path => 'pages/the_sortable_tree', :max_levels => 2
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Rendering a part of tree
|
|
242
|
+
|
|
243
|
+
``` ruby
|
|
244
|
+
@root = Page.root
|
|
245
|
+
@pages = @root.descendants.nested_set.all
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
``` ruby
|
|
249
|
+
= @root.inspect
|
|
250
|
+
= sortable_tree @pages, :new_url => new_page_path
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### LiveDemo
|
|
254
|
+
|
|
255
|
+
https://github.com/the-teacher/the_sortable_tree_test_app
|
|
256
|
+
|
|
257
|
+
### Options
|
|
258
|
+
|
|
259
|
+
**id** - id field (:id => :friendly_id etc. **:id** by default)
|
|
260
|
+
|
|
261
|
+
**title** - title field of node (:title => :name etc. **:title** by default)
|
|
262
|
+
|
|
263
|
+
**path** - path to custom view partials (:path => 'pages/the_sortable_tree')
|
|
264
|
+
|
|
265
|
+
**max_levels** - how many draggable levels can be? (**3** by default). **Can't be 0 (zero) and negative**
|
|
266
|
+
|
|
267
|
+
**namespace** - namespace for admin sections for example. (:namespace => :admin, **:namespace** => nil by default)
|
|
268
|
+
|
|
269
|
+
**opts[:level]** - view helper define level of recursion for each node. You can call **opts[:level]** into view partials
|
|
270
|
+
|
|
271
|
+
### Partials
|
|
272
|
+
|
|
273
|
+
**_tree** - root container for nested set elements
|
|
274
|
+
|
|
275
|
+
**_node** - element of tree (link to current node and nested set of children)
|
|
276
|
+
|
|
277
|
+
**_link** - decoration of link to current element of tree
|
|
278
|
+
|
|
279
|
+
**_children** - decoration of children
|
|
280
|
+
|
|
281
|
+
**_new** - create new element link
|
|
282
|
+
|
|
283
|
+
**_controls** - control elements for current node
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
**_js_init_sortable_tree** - JS for sortable tree
|
|
287
|
+
|
|
288
|
+
**_js_on_update_tree**- JS for sortable tree
|
|
289
|
+
|
|
290
|
+
**_js_rebuild_ajax**- JS for sortable tree
|
|
291
|
+
|
|
292
|
+
### Contributors
|
|
293
|
+
|
|
294
|
+
* https://github.com/the-teacher
|
|
295
|
+
* https://github.com/winescout
|
|
296
|
+
* https://github.com/gbrain
|
|
297
|
+
* https://github.com/Mik-die
|
|
298
|
+
|
|
299
|
+
### Acknowledgments
|
|
300
|
+
|
|
301
|
+
* https://github.com/mjsarfatti/nestedSortable
|
|
302
|
+
* http://iconza.com
|
data/Rakefile
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env rake
|
|
2
|
+
begin
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
rescue LoadError
|
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
6
|
+
end
|
|
7
|
+
begin
|
|
8
|
+
require 'rdoc/task'
|
|
9
|
+
rescue LoadError
|
|
10
|
+
require 'rdoc/rdoc'
|
|
11
|
+
require 'rake/rdoctask'
|
|
12
|
+
RDoc::Task = Rake::RDocTask
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
17
|
+
rdoc.title = 'TheSortableTree'
|
|
18
|
+
rdoc.options << '--line-numbers'
|
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
|
24
|
+
load 'rails/tasks/engine.rake'
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
Bundler::GemHelper.install_tasks
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
require 'rspec/rails'
|
|
32
|
+
|
|
33
|
+
RSpec.configure do |config|
|
|
34
|
+
config.use_transactional_fixtures = true
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
task :default => :test
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* jQuery UI Nested Sortable
|
|
3
|
+
* v 1.3.4 / 28 apr 2011
|
|
4
|
+
* http://mjsarfatti.com/sandbox/nestedSortable
|
|
5
|
+
*
|
|
6
|
+
* Depends:
|
|
7
|
+
* jquery.ui.sortable.js 1.8+
|
|
8
|
+
*
|
|
9
|
+
* License CC BY-SA 3.0
|
|
10
|
+
* Copyright 2010-2011, Manuele J Sarfatti
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
(function($) {
|
|
14
|
+
|
|
15
|
+
$.widget("ui.nestedSortable", $.extend({}, $.ui.sortable.prototype, {
|
|
16
|
+
|
|
17
|
+
options: {
|
|
18
|
+
tabSize: 20,
|
|
19
|
+
disableNesting: 'ui-nestedSortable-no-nesting',
|
|
20
|
+
errorClass: 'ui-nestedSortable-error',
|
|
21
|
+
listType: 'ol',
|
|
22
|
+
maxLevels: 0,
|
|
23
|
+
noJumpFix: 0
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
_create: function(){
|
|
27
|
+
if (this.noJumpFix == false)
|
|
28
|
+
this.element.height(this.element.height());
|
|
29
|
+
this.element.data('sortable', this.element.data('nestedSortable'));
|
|
30
|
+
return $.ui.sortable.prototype._create.apply(this, arguments);
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
_mouseDrag: function(event) {
|
|
36
|
+
|
|
37
|
+
//Compute the helpers position
|
|
38
|
+
this.position = this._generatePosition(event);
|
|
39
|
+
this.positionAbs = this._convertPositionTo("absolute");
|
|
40
|
+
|
|
41
|
+
if (!this.lastPositionAbs) {
|
|
42
|
+
this.lastPositionAbs = this.positionAbs;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//Do scrolling
|
|
46
|
+
if(this.options.scroll) {
|
|
47
|
+
var o = this.options, scrolled = false;
|
|
48
|
+
if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
|
|
49
|
+
|
|
50
|
+
if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
|
|
51
|
+
this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
|
|
52
|
+
else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
|
|
53
|
+
this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
|
|
54
|
+
|
|
55
|
+
if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
|
|
56
|
+
this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
|
|
57
|
+
else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
|
|
58
|
+
this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
|
|
59
|
+
|
|
60
|
+
} else {
|
|
61
|
+
|
|
62
|
+
if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
|
|
63
|
+
scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
|
|
64
|
+
else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
|
|
65
|
+
scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
|
|
66
|
+
|
|
67
|
+
if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
|
|
68
|
+
scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
|
|
69
|
+
else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
|
|
70
|
+
scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
|
|
71
|
+
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
|
|
75
|
+
$.ui.ddmanager.prepareOffsets(this, event);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//Regenerate the absolute position used for position checks
|
|
79
|
+
this.positionAbs = this._convertPositionTo("absolute");
|
|
80
|
+
|
|
81
|
+
//Set the helper position
|
|
82
|
+
if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
|
|
83
|
+
if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
|
|
84
|
+
|
|
85
|
+
//Rearrange
|
|
86
|
+
for (var i = this.items.length - 1; i >= 0; i--) {
|
|
87
|
+
|
|
88
|
+
//Cache variables and intersection, continue if no intersection
|
|
89
|
+
var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
|
|
90
|
+
if (!intersection) continue;
|
|
91
|
+
|
|
92
|
+
if(itemElement != this.currentItem[0] //cannot intersect with itself
|
|
93
|
+
&& this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
|
|
94
|
+
&& !$.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
|
|
95
|
+
&& (this.options.type == 'semi-dynamic' ? !$.contains(this.element[0], itemElement) : true)
|
|
96
|
+
//&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
|
|
97
|
+
) {
|
|
98
|
+
|
|
99
|
+
this.direction = intersection == 1 ? "down" : "up";
|
|
100
|
+
|
|
101
|
+
if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
|
|
102
|
+
this._rearrange(event, item);
|
|
103
|
+
} else {
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Clear emtpy ul's/ol's
|
|
108
|
+
this._clearEmpty(itemElement);
|
|
109
|
+
|
|
110
|
+
this._trigger("change", event, this._uiHash());
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
var parentItem = (this.placeholder[0].parentNode.parentNode && $(this.placeholder[0].parentNode.parentNode).closest('.ui-sortable').length) ? $(this.placeholder[0].parentNode.parentNode) : null;
|
|
116
|
+
var level = this._getLevel(this.placeholder);
|
|
117
|
+
var childLevels = this._getChildLevels(this.helper);
|
|
118
|
+
var previousItem = this.placeholder[0].previousSibling ? $(this.placeholder[0].previousSibling) : null;
|
|
119
|
+
if (previousItem != null) {
|
|
120
|
+
while (previousItem[0].nodeName.toLowerCase() != 'li' || previousItem[0] == this.currentItem[0]) {
|
|
121
|
+
if (previousItem[0].previousSibling) {
|
|
122
|
+
previousItem = $(previousItem[0].previousSibling);
|
|
123
|
+
} else {
|
|
124
|
+
previousItem = null;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
newList = document.createElement(o.listType);
|
|
131
|
+
|
|
132
|
+
this.beyondMaxLevels = 0;
|
|
133
|
+
|
|
134
|
+
// If the item is moved to the left, send it to its parent level
|
|
135
|
+
if (parentItem != null && this.positionAbs.left < parentItem.offset().left) {
|
|
136
|
+
parentItem.after(this.placeholder[0]);
|
|
137
|
+
this._clearEmpty(parentItem[0]);
|
|
138
|
+
this._trigger("change", event, this._uiHash());
|
|
139
|
+
}
|
|
140
|
+
// If the item is below another one and is moved to the right, make it a children of it
|
|
141
|
+
else if (previousItem != null && this.positionAbs.left > previousItem.offset().left + o.tabSize) {
|
|
142
|
+
this._isAllowed(previousItem, level+childLevels+1);
|
|
143
|
+
if (!previousItem.children(o.listType).length) {
|
|
144
|
+
previousItem[0].appendChild(newList);
|
|
145
|
+
}
|
|
146
|
+
previousItem.children(o.listType)[0].appendChild(this.placeholder[0]);
|
|
147
|
+
this._trigger("change", event, this._uiHash());
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
this._isAllowed(parentItem, level+childLevels);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
//Post events to containers
|
|
154
|
+
this._contactContainers(event);
|
|
155
|
+
|
|
156
|
+
//Interconnect with droppables
|
|
157
|
+
if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
|
|
158
|
+
|
|
159
|
+
//Call callbacks
|
|
160
|
+
this._trigger('sort', event, this._uiHash());
|
|
161
|
+
|
|
162
|
+
this.lastPositionAbs = this.positionAbs;
|
|
163
|
+
return false;
|
|
164
|
+
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
_mouseStop: function(event, noPropagation) {
|
|
168
|
+
|
|
169
|
+
// If the item is in a position not allowed, send it back
|
|
170
|
+
if (this.beyondMaxLevels) {
|
|
171
|
+
var parent = this.placeholder.parent().closest(this.options.items);
|
|
172
|
+
|
|
173
|
+
for (var i = this.beyondMaxLevels - 1; i > 0; i--) {
|
|
174
|
+
parent = parent.parent().closest(this.options.items);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
this.placeholder.removeClass(this.options.errorClass);
|
|
178
|
+
parent.after(this.placeholder);
|
|
179
|
+
this._trigger("change", event, this._uiHash());
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
$.ui.sortable.prototype._mouseStop.apply(this, arguments);
|
|
183
|
+
|
|
184
|
+
},
|
|
185
|
+
|
|
186
|
+
serialize: function(o) {
|
|
187
|
+
|
|
188
|
+
var items = this._getItemsAsjQuery(o && o.connected);
|
|
189
|
+
var str = []; o = o || {};
|
|
190
|
+
|
|
191
|
+
$(items).each(function() {
|
|
192
|
+
var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
|
|
193
|
+
var pid = ($(o.item || this).parent(o.listType).parent('li').attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
|
|
194
|
+
if(res) str.push((o.key || res[1]+'['+(o.key && o.expression ? res[1] : res[2])+']')+'='+(pid ? (o.key && o.expression ? pid[1] : pid[2]) : 'root'));
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
if(!str.length && o.key) {
|
|
198
|
+
str.push(o.key + '=');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return str.join('&');
|
|
202
|
+
|
|
203
|
+
},
|
|
204
|
+
|
|
205
|
+
toHierarchy: function(o) {
|
|
206
|
+
|
|
207
|
+
o = o || {};
|
|
208
|
+
var sDepth = o.startDepthCount || 0;
|
|
209
|
+
var ret = [];
|
|
210
|
+
|
|
211
|
+
$(this.element).children('li').each(function() {
|
|
212
|
+
var level = _recursiveItems($(this));
|
|
213
|
+
ret.push(level);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
return ret;
|
|
217
|
+
|
|
218
|
+
function _recursiveItems(li) {
|
|
219
|
+
var id = ($(li).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
|
|
220
|
+
if (id != null) {
|
|
221
|
+
var item = {"id" : id[2]};
|
|
222
|
+
if ($(li).children(o.listType).children('li').length > 0) {
|
|
223
|
+
item.children = [];
|
|
224
|
+
$(li).children(o.listType).children('li').each(function () {
|
|
225
|
+
var level = _recursiveItems($(this));
|
|
226
|
+
item.children.push(level);
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
return item;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
toArray: function(o) {
|
|
235
|
+
|
|
236
|
+
o = o || {};
|
|
237
|
+
var sDepth = o.startDepthCount || 0;
|
|
238
|
+
var ret = [];
|
|
239
|
+
var left = 2;
|
|
240
|
+
|
|
241
|
+
ret.push({"item_id": 'root', "parent_id": 'none', "depth": sDepth, "left": '1', "right": ($('li', this.element).length + 1) * 2});
|
|
242
|
+
|
|
243
|
+
$(this.element).children('li').each(function () {
|
|
244
|
+
left = _recursiveArray(this, sDepth + 1, left);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
function _sortByLeft(a,b) {
|
|
248
|
+
return a['left'] - b['left'];
|
|
249
|
+
}
|
|
250
|
+
ret = ret.sort(_sortByLeft);
|
|
251
|
+
|
|
252
|
+
return ret;
|
|
253
|
+
|
|
254
|
+
function _recursiveArray(item, depth, left) {
|
|
255
|
+
|
|
256
|
+
right = left + 1;
|
|
257
|
+
|
|
258
|
+
if ($(item).children(o.listType).children('li').length > 0) {
|
|
259
|
+
depth ++;
|
|
260
|
+
$(item).children(o.listType).children('li').each(function () {
|
|
261
|
+
right = _recursiveArray($(this), depth, right);
|
|
262
|
+
});
|
|
263
|
+
depth --;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
id = ($(item).attr(o.attribute || 'id')).match(o.expression || (/(.+)[-=_](.+)/));
|
|
267
|
+
|
|
268
|
+
if (depth === sDepth + 1) pid = 'root';
|
|
269
|
+
else {
|
|
270
|
+
parentItem = ($(item).parent(o.listType).parent('li').attr('id')).match(o.expression || (/(.+)[-=_](.+)/));
|
|
271
|
+
pid = parentItem[2];
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (id != null) {
|
|
275
|
+
ret.push({"item_id": id[2], "parent_id": pid, "depth": depth, "left": left, "right": right});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return left = right + 1;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
},
|
|
282
|
+
|
|
283
|
+
_clear: function(event, noPropagation) {
|
|
284
|
+
|
|
285
|
+
$.ui.sortable.prototype._clear.apply(this, arguments);
|
|
286
|
+
|
|
287
|
+
// Clean last empty ul/ol
|
|
288
|
+
for (var i = this.items.length - 1; i >= 0; i--) {
|
|
289
|
+
var item = this.items[i].item[0];
|
|
290
|
+
this._clearEmpty(item);
|
|
291
|
+
}
|
|
292
|
+
return true;
|
|
293
|
+
|
|
294
|
+
},
|
|
295
|
+
|
|
296
|
+
_clearEmpty: function(item) {
|
|
297
|
+
|
|
298
|
+
if (item.children[1] && item.children[1].children.length == 0) {
|
|
299
|
+
item.removeChild(item.children[1]);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
_getLevel: function(item) {
|
|
305
|
+
|
|
306
|
+
var level = 1;
|
|
307
|
+
|
|
308
|
+
if (this.options.listType) {
|
|
309
|
+
var list = item.closest(this.options.listType);
|
|
310
|
+
while (!list.is('.ui-sortable')/* && level < this.options.maxLevels*/) {
|
|
311
|
+
level++;
|
|
312
|
+
list = list.parent().closest(this.options.listType);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return level;
|
|
317
|
+
},
|
|
318
|
+
|
|
319
|
+
_getChildLevels: function(parent, depth) {
|
|
320
|
+
var self = this,
|
|
321
|
+
o = this.options,
|
|
322
|
+
result = 0;
|
|
323
|
+
depth = depth || 0;
|
|
324
|
+
|
|
325
|
+
$(parent).children(o.listType).children(o.items).each(function (index, child) {
|
|
326
|
+
result = Math.max(self._getChildLevels(child, depth + 1), result);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
return depth ? result + 1 : result;
|
|
330
|
+
},
|
|
331
|
+
|
|
332
|
+
_isAllowed: function(parentItem, levels) {
|
|
333
|
+
var o = this.options
|
|
334
|
+
// Are we trying to nest under a no-nest or are we nesting too deep?
|
|
335
|
+
if (parentItem == null || !(parentItem.hasClass(o.disableNesting))) {
|
|
336
|
+
if (o.maxLevels < levels && o.maxLevels != 0) {
|
|
337
|
+
this.placeholder.addClass(o.errorClass);
|
|
338
|
+
this.beyondMaxLevels = levels - o.maxLevels;
|
|
339
|
+
} else {
|
|
340
|
+
this.placeholder.removeClass(o.errorClass);
|
|
341
|
+
this.beyondMaxLevels = 0;
|
|
342
|
+
}
|
|
343
|
+
} else {
|
|
344
|
+
this.placeholder.addClass(o.errorClass);
|
|
345
|
+
if (o.maxLevels < levels && o.maxLevels != 0) {
|
|
346
|
+
this.beyondMaxLevels = levels - o.maxLevels;
|
|
347
|
+
} else {
|
|
348
|
+
this.beyondMaxLevels = 1;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
}));
|
|
354
|
+
|
|
355
|
+
$.ui.nestedSortable.prototype.options = $.extend({}, $.ui.sortable.prototype.options, $.ui.nestedSortable.prototype.options);
|
|
356
|
+
})(jQuery);
|