the_sortable_tree 1.8.6 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +89 -76
- data/app/assets/javascripts/comments_tree.js.coffee +46 -0
- data/app/assets/stylesheets/comments_tree.css.scss +84 -0
- data/app/assets/stylesheets/sortable.css.scss +106 -0
- data/app/assets/stylesheets/tree.css.scss +38 -0
- data/app/controllers/the_sortable_tree_controller.rb +6 -7
- data/app/helpers/the_sortable_tree_helper.rb +35 -14
- data/app/views/{the_sortable_tree → comments/base}/_children.html.haml +0 -0
- data/app/views/comments/base/_comment.html.haml +7 -0
- data/app/views/comments/base/_new_comment_form.html.haml +18 -0
- data/app/views/comments/base/_node.html.haml +3 -0
- data/app/views/comments/base/_tree.html.haml +5 -0
- data/app/views/{the_sortable_tree_min → sortable/base}/_children.html.haml +0 -0
- data/app/views/{the_sortable_tree → sortable/base}/_controls.html.haml +0 -0
- data/app/views/{the_sortable_tree → sortable/base}/_js_init_sortable_tree.html.haml +0 -0
- data/app/views/{the_sortable_tree → sortable/base}/_js_on_update_tree.html.haml +0 -0
- data/app/views/{the_sortable_tree → sortable/base}/_js_rebuild_ajax.html.haml +0 -0
- data/app/views/{the_sortable_tree → sortable/base}/_link.html.haml +0 -0
- data/app/views/{the_sortable_tree → sortable/base}/_new.html.haml +0 -0
- data/app/views/{the_sortable_tree → sortable/base}/_node.html.haml +0 -0
- data/app/views/sortable/base/_tree.html.haml +7 -0
- data/app/views/tree/base/_children.html.haml +1 -0
- data/app/views/{the_sortable_tree_min → tree/base}/_link.html.haml +0 -0
- data/app/views/{the_sortable_tree_min → tree/base}/_node.html.haml +0 -0
- data/app/views/tree/base/_tree.html.haml +3 -0
- data/config/locales/en.yml +30 -9
- data/lib/generators/the_sortable_tree/views_generator.rb +10 -5
- data/lib/the_sortable_tree/version.rb +1 -1
- metadata +36 -27
- data/app/assets/stylesheets/the_sortable_tree.css +0 -120
- data/app/assets/stylesheets/the_sortable_tree_min.css +0 -26
- data/app/views/the_sortable_tree/_tree.html.haml +0 -6
- data/app/views/the_sortable_tree_min/_tree.html.haml +0 -2
data/README.md
CHANGED
@@ -1,40 +1,51 @@
|
|
1
1
|
### TheSortableTree
|
2
2
|
|
3
|
-
|
3
|
+
Awesome Helper for building sortable nested sets
|
4
4
|
|
5
|
-
|
5
|
+
### Keywords
|
6
6
|
|
7
|
-
|
7
|
+
Sortable awesom_nested_set, Drag&Drop GUI for awesom_nested_set, View Helper for nested set, Nested Comments
|
8
8
|
|
9
|
-
|
9
|
+
### Description
|
10
|
+
|
11
|
+
**sortable_tree** - recursive helper-method for rendering sortable awesome_nested_set tree.
|
12
|
+
|
13
|
+
**sortable_tree** uses partials for rendering, that's why it is **so easy to customize**!
|
14
|
+
|
15
|
+
### Capabilities
|
10
16
|
|
11
|
-
**
|
17
|
+
**Just Tree [default or tree option)**
|
12
18
|
|
13
19
|
![TheSortableTree](https://github.com/the-teacher/the_sortable_tree/raw/master/pic_min.jpg)
|
14
20
|
|
15
|
-
**
|
21
|
+
**Drag&Drop Sortable Tree [sortable option]**
|
16
22
|
|
17
|
-
|
23
|
+
![TheSortableTree](https://github.com/the-teacher/the_sortable_tree/raw/master/pic.jpg)
|
24
|
+
|
25
|
+
**Comments Tree [__comments__ option]**
|
18
26
|
|
19
|
-
|
27
|
+
With New Comment form and reply functionality
|
20
28
|
|
21
|
-
|
22
|
-
* Simple nested sets (**min** option)
|
23
|
-
* Nested sets with expand/collapse animation (**expand** option) [under development]
|
24
|
-
* Nested comments (**comments** option) [under development]
|
29
|
+
![TheSortableTree](https://github.com/the-teacher/the_sortable_tree/raw/dev/comments.gif)
|
25
30
|
|
26
31
|
### Can I use gem with Rails 2 or Rails 3.0?
|
27
32
|
|
28
|
-
|
33
|
+
There is no strong dependencies for Rails 3.
|
29
34
|
|
30
|
-
|
35
|
+
Take files from the gem and put it in your Rails 2 application.
|
31
36
|
|
32
|
-
|
37
|
+
And fix errors :) Ha-Ha-Ha! You can ask me if you will do it.
|
33
38
|
|
34
|
-
|
39
|
+
### LiveDemo and App for testcase creating
|
40
|
+
|
41
|
+
https://github.com/the-teacher/the_sortable_tree_test_app
|
35
42
|
|
36
43
|
### Changelog
|
37
44
|
|
45
|
+
1.9.0 - 1) **Helper API changed!** 2) Comments tree with sand form and reply fu! 3) Way to manual set sortable Model klass into controller.
|
46
|
+
|
47
|
+
1.8.6 - fixed CamelCase names definition (by andisthejackass)
|
48
|
+
|
38
49
|
1.8.5 - helper can rendering a part tree
|
39
50
|
|
40
51
|
1.8.0 - stable release
|
@@ -51,17 +62,15 @@ Rendered by 50 sec.
|
|
51
62
|
|
52
63
|
I think it is good result for rendering by partials.
|
53
64
|
|
54
|
-
|
55
|
-
|
56
|
-
### ERB vs HAML vs SLIM
|
65
|
+
### It's can be faster?
|
57
66
|
|
58
|
-
|
67
|
+
Perhaps. Read next idea to learn more. There is no implementation now, sorry.
|
59
68
|
|
60
|
-
|
69
|
+
https://github.com/the-teacher/the_sortable_tree/issues/milestones?with_issues=no
|
61
70
|
|
62
|
-
|
71
|
+
### ERB vs HAML vs SLIM
|
63
72
|
|
64
|
-
|
73
|
+
HAML by default. You can use any Template Engine, but convert partials by yourself, plz.
|
65
74
|
|
66
75
|
### Install
|
67
76
|
|
@@ -69,13 +78,9 @@ Read project wiki for looking ERB partials
|
|
69
78
|
gem 'awesome_nested_set' # gem 'nested_set'
|
70
79
|
gem 'the_sortable_tree'
|
71
80
|
|
81
|
+
```ruby
|
72
82
|
bundle
|
73
|
-
|
74
|
-
### Require
|
75
|
-
|
76
|
-
1. gem 'nested_set' or gem 'awesome_nested_set'
|
77
|
-
2. gem 'haml'
|
78
|
-
3. JQuery UI
|
83
|
+
```
|
79
84
|
|
80
85
|
### Example of using with Page Model
|
81
86
|
|
@@ -160,82 +165,72 @@ class PagesController < ApplicationController
|
|
160
165
|
end
|
161
166
|
```
|
162
167
|
|
163
|
-
###
|
168
|
+
### Extend your Layout (erb)
|
164
169
|
|
165
170
|
``` ruby
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
171
|
+
<%= stylesheet_link_tag "application" %>
|
172
|
+
<%= javascript_include_tag "application" %>
|
173
|
+
<%= csrf_meta_tags %>
|
174
|
+
|
175
|
+
<%= javascript_include_tag 'jquery.ui.nestedSortable' %>
|
176
|
+
<%= javascript_include_tag 'comments_tree' %>
|
170
177
|
|
171
|
-
|
178
|
+
<%= stylesheet_link_tag 'tree', :media => :all %>
|
179
|
+
<%= stylesheet_link_tag 'sortable', :media => :all %>
|
180
|
+
<%= stylesheet_link_tag 'comments_tree', :media => :all %>
|
172
181
|
```
|
173
182
|
|
174
|
-
or (without administrator controls and drag&drop)
|
175
183
|
|
176
|
-
|
177
|
-
- content_for :css do
|
178
|
-
= stylesheet_link_tag 'the_sortable_tree_min', :media => :screen
|
184
|
+
### Render your tree
|
179
185
|
|
180
|
-
|
186
|
+
``` ruby
|
187
|
+
= sortable_tree @pages, :new_url => new_page_path
|
181
188
|
```
|
182
189
|
|
183
|
-
###
|
184
|
-
|
185
|
-
**Use sortable_tree as view helper for simple rendering of nested_set tree**
|
190
|
+
### Render your sortable tree
|
186
191
|
|
187
192
|
``` ruby
|
188
|
-
|
193
|
+
= sortable_tree @pages, :new_url => new_page_path, :type => :sortable, :max_levels => 4
|
189
194
|
```
|
190
195
|
|
191
|
-
|
196
|
+
### Render your comments tree (with New Form and Reply)
|
197
|
+
|
198
|
+
Plz, read **Comments Doc** before using this
|
192
199
|
|
193
200
|
``` ruby
|
194
|
-
|
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
|
201
|
+
= sortable_tree @comments, :title => :name, :type => :comments
|
199
202
|
```
|
200
203
|
|
201
|
-
|
204
|
+
### Comments Doc
|
205
|
+
|
206
|
+
Coming soon...
|
207
|
+
|
208
|
+
### Customization
|
209
|
+
|
210
|
+
TheSortableTree view generator will copy a set of partials from gem to your View directory.
|
202
211
|
|
203
212
|
``` ruby
|
204
|
-
|
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'
|
213
|
+
rails g the_sortable_tree:views Model [option]
|
207
214
|
```
|
208
215
|
|
209
|
-
|
216
|
+
## Examples
|
217
|
+
|
218
|
+
### Customize your tree
|
210
219
|
|
211
220
|
``` ruby
|
212
|
-
rails g the_sortable_tree:views
|
221
|
+
rails g the_sortable_tree:views Page
|
213
222
|
```
|
214
223
|
|
215
|
-
|
224
|
+
### Customize your sortable tree
|
216
225
|
|
217
226
|
``` ruby
|
218
|
-
|
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
|
227
|
+
rails g the_sortable_tree:views Page sortable
|
228
228
|
```
|
229
229
|
|
230
|
-
Customize
|
230
|
+
### Customize your comments tree
|
231
231
|
|
232
232
|
``` ruby
|
233
|
-
|
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
|
233
|
+
rails g the_sortable_tree:views Comment comments
|
239
234
|
```
|
240
235
|
|
241
236
|
### Rendering a part of tree
|
@@ -250,9 +245,27 @@ Customize and use it!
|
|
250
245
|
= sortable_tree @pages, :new_url => new_page_path
|
251
246
|
```
|
252
247
|
|
253
|
-
###
|
248
|
+
### Troubleshooting
|
254
249
|
|
255
|
-
|
250
|
+
If **TheSortableTree** can't correctly define a Name of your Model, just add **sortable_model** into your Controller:
|
251
|
+
|
252
|
+
``` ruby
|
253
|
+
class Inventory::CategoriesController < ApplicationController
|
254
|
+
include TheSortableTreeController::Rebuild
|
255
|
+
|
256
|
+
def sortable_model
|
257
|
+
Inventory::Category
|
258
|
+
end
|
259
|
+
|
260
|
+
def index
|
261
|
+
@inventory_categories = Inventory::Category.nested_set.all
|
262
|
+
end
|
263
|
+
|
264
|
+
def manage
|
265
|
+
@inventory_categories = Inventory::Category.nested_set.all
|
266
|
+
end
|
267
|
+
end
|
268
|
+
```
|
256
269
|
|
257
270
|
### Options
|
258
271
|
|
@@ -0,0 +1,46 @@
|
|
1
|
+
$ ->
|
2
|
+
class @CommentsTreeInit
|
3
|
+
# SELECTORS
|
4
|
+
reply_links: $('.comments_tree .comment .reply')
|
5
|
+
skip_link: $('.comments_tree .new_comment .skip')
|
6
|
+
new_comment_form: $('.comments_tree form.new_comment')
|
7
|
+
parent_input: $(".comments_tree form.new_comment input[name='comment[parent_id]']")
|
8
|
+
|
9
|
+
constructor: ->
|
10
|
+
|
11
|
+
@reply_links.click (event) =>
|
12
|
+
# GET DATA
|
13
|
+
link = $ event.target
|
14
|
+
comment = link.parents('.comment')
|
15
|
+
title = comment.find('.title .main')
|
16
|
+
hidden_field = comment.find('input:hidden')
|
17
|
+
parent_id = hidden_field.val()
|
18
|
+
|
19
|
+
form = @new_comment_form
|
20
|
+
for_block = form.find('.for')
|
21
|
+
name_field = for_block.find('i')
|
22
|
+
|
23
|
+
# SET DATA
|
24
|
+
name_field.html title.html()
|
25
|
+
@parent_input.val parent_id
|
26
|
+
|
27
|
+
# SHOW and JUMP
|
28
|
+
for_block.show()
|
29
|
+
window.location.hash = '#new_comment'
|
30
|
+
|
31
|
+
false
|
32
|
+
|
33
|
+
@skip_link.click (event) =>
|
34
|
+
link = $ event.target
|
35
|
+
form = @new_comment_form
|
36
|
+
for_block = form.find('.for')
|
37
|
+
name_field = for_block.find('i')
|
38
|
+
|
39
|
+
name_field.html ''
|
40
|
+
@parent_input.val ''
|
41
|
+
|
42
|
+
for_block.hide()
|
43
|
+
|
44
|
+
false
|
45
|
+
|
46
|
+
new @CommentsTreeInit
|
@@ -0,0 +1,84 @@
|
|
1
|
+
.comments_tree{
|
2
|
+
* {
|
3
|
+
margin: 0; padding: 0;
|
4
|
+
list-style:none;
|
5
|
+
}
|
6
|
+
|
7
|
+
.new_comment{
|
8
|
+
padding: 10px;
|
9
|
+
margin-bottom: 10px;
|
10
|
+
border: 1px solid Blue;
|
11
|
+
border-radius: 5px;
|
12
|
+
p{
|
13
|
+
margin-bottom: 10px;
|
14
|
+
}
|
15
|
+
input[type=text], textarea{
|
16
|
+
border: 1px solid Grey;
|
17
|
+
border-left: 2px solid Grey;
|
18
|
+
width: 90%;
|
19
|
+
}
|
20
|
+
}
|
21
|
+
|
22
|
+
.nested_set{
|
23
|
+
margin-bottom: 25px;
|
24
|
+
}
|
25
|
+
|
26
|
+
ol{
|
27
|
+
|
28
|
+
margin: 0;
|
29
|
+
padding: 0;
|
30
|
+
list-style:none;
|
31
|
+
|
32
|
+
&.nested_set {
|
33
|
+
list-style:none;
|
34
|
+
font-size: 16px;
|
35
|
+
|
36
|
+
li{
|
37
|
+
font-size: 0.95em;
|
38
|
+
line-height: 130%;
|
39
|
+
margin-bottom: 5px;
|
40
|
+
list-style:none;
|
41
|
+
list-style-position: outside;
|
42
|
+
|
43
|
+
.comment{
|
44
|
+
border: 1px solid LightGray;
|
45
|
+
border-radius: 4px;
|
46
|
+
padding: 10px;
|
47
|
+
|
48
|
+
.title, .contacts{
|
49
|
+
margin-bottom: 5px;
|
50
|
+
}
|
51
|
+
|
52
|
+
.title{
|
53
|
+
color: blue;
|
54
|
+
.reply a{
|
55
|
+
font-size: 0.9em;
|
56
|
+
font-family: Arial;
|
57
|
+
color: green;
|
58
|
+
text-decoration: none;
|
59
|
+
&:hover{ text-decoration: underline; }
|
60
|
+
}
|
61
|
+
}
|
62
|
+
.contacts{
|
63
|
+
font-style: italic;
|
64
|
+
}
|
65
|
+
.content{
|
66
|
+
background: LightGray;
|
67
|
+
border-radius: 2px;
|
68
|
+
font-family: Arial;
|
69
|
+
padding: 5px;
|
70
|
+
}
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
ol{
|
75
|
+
border-left: 1px dashed LightGreen;
|
76
|
+
padding-left: 10px;
|
77
|
+
margin-left: 15px;
|
78
|
+
margin-top: 5px;
|
79
|
+
|
80
|
+
li{ font-weight: normal; }
|
81
|
+
}
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
@@ -0,0 +1,106 @@
|
|
1
|
+
.sortable{
|
2
|
+
* {
|
3
|
+
margin: 0; padding: 0;
|
4
|
+
list-style: none;
|
5
|
+
}
|
6
|
+
|
7
|
+
.nested_set_new_image{
|
8
|
+
vertical-align: middle;
|
9
|
+
border: none;
|
10
|
+
}
|
11
|
+
|
12
|
+
.nested_set_new{
|
13
|
+
margin: 25px 0;
|
14
|
+
a{ font-size: 14pt }
|
15
|
+
}
|
16
|
+
|
17
|
+
.nested_set{
|
18
|
+
margin: 0; padding: 0;
|
19
|
+
list-style: none;
|
20
|
+
font-size: 16px;
|
21
|
+
|
22
|
+
a{
|
23
|
+
color: #000;
|
24
|
+
font-size: 10pt;
|
25
|
+
font-weight: normal;
|
26
|
+
text-decoration: none;
|
27
|
+
line-height: 150%;
|
28
|
+
margin-left: 30px;
|
29
|
+
margin-right: 120px;
|
30
|
+
display: block;
|
31
|
+
|
32
|
+
&:hover{
|
33
|
+
color: #2476FF;
|
34
|
+
text-decoration: none;
|
35
|
+
}
|
36
|
+
|
37
|
+
img{
|
38
|
+
float: left
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
ol{
|
43
|
+
margin: 0 0 0 25px;
|
44
|
+
border-left: 1px dashed gray;
|
45
|
+
li{ margin-bottom: 5px; }
|
46
|
+
}
|
47
|
+
|
48
|
+
.root{
|
49
|
+
a{ font-weight: bold; }
|
50
|
+
}
|
51
|
+
.handle{
|
52
|
+
width: 16px;
|
53
|
+
height: 16px;
|
54
|
+
float: left;
|
55
|
+
cursor: move;
|
56
|
+
background: transparent url(/assets/iconza/blue/move.png) no-repeat scroll center center;
|
57
|
+
}
|
58
|
+
.link{
|
59
|
+
position: relative;
|
60
|
+
overflow: hidden;
|
61
|
+
zoom: 1;
|
62
|
+
padding: 5px;
|
63
|
+
margin: 0 0 5px 5px;
|
64
|
+
background: #EFEFEF;
|
65
|
+
border-radius: 5px;
|
66
|
+
&:hover{
|
67
|
+
background: #FEE;
|
68
|
+
}
|
69
|
+
}
|
70
|
+
.controls{
|
71
|
+
position: absolute;
|
72
|
+
top: 5px; right: 10px;
|
73
|
+
}
|
74
|
+
.button{
|
75
|
+
width: 20px;
|
76
|
+
height: 20px;
|
77
|
+
display: block;
|
78
|
+
float: left;
|
79
|
+
margin: 0 0 0 3px;
|
80
|
+
cursor: pointer;
|
81
|
+
|
82
|
+
.new{
|
83
|
+
background: transparent url(/assets/iconza/blue/add.png) no-repeat scroll center center;
|
84
|
+
&:hover{ background: transparent url(/assets/iconza/red/add.png) no-repeat scroll center center }
|
85
|
+
}
|
86
|
+
.edit{
|
87
|
+
background: transparent url(/assets/iconza/blue/edit.png) no-repeat scroll center center;
|
88
|
+
&:hover{ background: transparent url(/assets/iconza/red/edit.png) no-repeat scroll center center }
|
89
|
+
}
|
90
|
+
.delete{
|
91
|
+
background: transparent url(/assets/iconza/blue/delete.png) no-repeat scroll center center;
|
92
|
+
&:hover{ background: transparent url(/assets/iconza/red/delete.png) no-repeat scroll center center }
|
93
|
+
}
|
94
|
+
.undeleted{ background: transparent url(/assets/iconza/gray/delete.png) no-repeat scroll center center }
|
95
|
+
}
|
96
|
+
|
97
|
+
.placeholder {
|
98
|
+
background-color: #EEF;
|
99
|
+
border: 1px dashed blue;
|
100
|
+
}
|
101
|
+
.ui-nestedSortable-error {
|
102
|
+
background: #FAA;
|
103
|
+
color: #8a1f11;
|
104
|
+
}
|
105
|
+
}
|
106
|
+
}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
.tree{
|
2
|
+
* {
|
3
|
+
margin: 0; padding: 0;
|
4
|
+
list-style:none;
|
5
|
+
}
|
6
|
+
|
7
|
+
ol{
|
8
|
+
|
9
|
+
margin: 0; padding: 0;
|
10
|
+
list-style:none;
|
11
|
+
|
12
|
+
&.nested_set {
|
13
|
+
list-style:none;
|
14
|
+
font-size: 16px;
|
15
|
+
|
16
|
+
li{
|
17
|
+
font-size: 0.9em;
|
18
|
+
line-height: 130%;
|
19
|
+
margin-bottom: 5px;
|
20
|
+
font-weight: bold;
|
21
|
+
list-style:none;
|
22
|
+
list-style-position: outside;
|
23
|
+
}
|
24
|
+
|
25
|
+
ol{
|
26
|
+
border-left: 1px dashed #AAA;
|
27
|
+
padding-left: 10px;
|
28
|
+
margin-left: 15px;
|
29
|
+
margin-top: 5px;
|
30
|
+
|
31
|
+
li{ font-weight: normal; }
|
32
|
+
}
|
33
|
+
|
34
|
+
a:hover { color: #003A89 !important; }
|
35
|
+
a:visited { color: #809dc4; }
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
@@ -5,12 +5,12 @@ module TheSortableTreeController
|
|
5
5
|
module DefineVariablesMethod
|
6
6
|
public
|
7
7
|
def the_define_common_variables
|
8
|
-
collection =
|
9
|
-
variable
|
10
|
-
klass
|
8
|
+
collection = self.class.to_s.split(':').last.sub(/Controller/,'').underscore.downcase # recipes
|
9
|
+
variable = collection.singularize # recipe
|
10
|
+
klass = self.respond_to?(:sortable_model) ? self.sortable_model : variable.classify.constantize # Recipe
|
11
11
|
["@#{variable}", collection, klass]
|
12
12
|
end
|
13
|
-
end
|
13
|
+
end
|
14
14
|
|
15
15
|
module Rebuild
|
16
16
|
include DefineVariablesMethod
|
@@ -36,7 +36,7 @@ module TheSortableTreeController
|
|
36
36
|
|
37
37
|
render(:nothing => true)
|
38
38
|
end
|
39
|
-
end
|
39
|
+
end
|
40
40
|
|
41
41
|
module ReversedRebuild
|
42
42
|
include DefineVariablesMethod
|
@@ -62,6 +62,5 @@ module TheSortableTreeController
|
|
62
62
|
|
63
63
|
render(:nothing => true)
|
64
64
|
end
|
65
|
-
end
|
66
|
-
|
65
|
+
end
|
67
66
|
end
|
@@ -12,28 +12,49 @@ module TheSortableTreeHelper
|
|
12
12
|
def define_class_of_elements_of tree
|
13
13
|
case
|
14
14
|
when tree.is_a?(ActiveRecord::Relation) then tree.name.to_s.underscore.downcase
|
15
|
-
when tree.empty?
|
15
|
+
when tree.empty? then nil
|
16
16
|
else tree.first.class.to_s.underscore.downcase
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
:
|
27
|
-
|
20
|
+
# types:
|
21
|
+
# tree
|
22
|
+
# sortable
|
23
|
+
# comments
|
24
|
+
def sortable_tree(tree, options= {})
|
25
|
+
opts = {
|
26
|
+
:max_levels => 3,
|
27
|
+
:type => :tree,
|
28
|
+
:js => false,
|
29
|
+
:path => false,
|
30
|
+
:title => :title,
|
31
|
+
:klass => define_class_of_elements_of(tree),
|
32
|
+
# comments options
|
33
|
+
:node_id => :id,
|
34
|
+
:contacts_field => :email,
|
35
|
+
:content_field => :content,
|
36
|
+
:raw_content_field => :raw_content
|
37
|
+
}.merge! options
|
38
|
+
|
39
|
+
# RAILS require
|
40
|
+
opts[:namespace] = Array.wrap opts[:namespace]
|
41
|
+
|
42
|
+
# PATH building
|
43
|
+
unless opts[:path]
|
44
|
+
variant = 'base'
|
45
|
+
variant = 'js' if opts[:js]
|
46
|
+
opts[:path] = "#{opts[:type]}/#{variant}"
|
47
|
+
end
|
48
|
+
|
28
49
|
render :partial => "#{opts[:path]}/tree", :locals => { :tree => sortable_tree_builder(tree, opts), :opts => opts }
|
29
50
|
end
|
30
51
|
|
31
52
|
def sortable_tree_builder(tree, options= {})
|
32
53
|
result = ''
|
33
|
-
opts
|
34
|
-
:id
|
35
|
-
:node
|
36
|
-
:root
|
54
|
+
opts = {
|
55
|
+
:id => :id, # node id field
|
56
|
+
:node => nil, # node
|
57
|
+
:root => false, # is it root node?
|
37
58
|
:level => 0 # recursion level
|
38
59
|
}.merge!(options)
|
39
60
|
|
@@ -66,4 +87,4 @@ module TheSortableTreeHelper
|
|
66
87
|
end
|
67
88
|
raw result
|
68
89
|
end
|
69
|
-
end
|
90
|
+
end
|
File without changes
|
@@ -0,0 +1,18 @@
|
|
1
|
+
= form_for Comment.new, :class => :new_comment do |f|
|
2
|
+
= f.hidden_field :parent_id
|
3
|
+
|
4
|
+
%label= t('.title')
|
5
|
+
%p= f.text_field opts[:title]
|
6
|
+
|
7
|
+
%label= t('.contacts')
|
8
|
+
%p= f.text_field opts[:contacts_field]
|
9
|
+
|
10
|
+
%label
|
11
|
+
= t('.content')
|
12
|
+
%span.for{ :style => 'display:none' }
|
13
|
+
= t('.for')
|
14
|
+
%i Undefined
|
15
|
+
= link_to t('.skip'), '#', :class => :skip
|
16
|
+
%p= f.text_area opts[:raw_content_field]
|
17
|
+
|
18
|
+
%div= f.submit t('.submit')
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,7 @@
|
|
1
|
+
.sortable
|
2
|
+
= render :partial => "#{opts[:path]}/new", :locals => { :opts => opts }
|
3
|
+
- unless tree.empty?
|
4
|
+
= render :partial => "#{opts[:path]}/js_init_sortable_tree", :locals => { :opts => opts }
|
5
|
+
= render :partial => "#{opts[:path]}/js_on_update_tree"
|
6
|
+
= render :partial => "#{opts[:path]}/js_rebuild_ajax", :locals => { :opts => opts }
|
7
|
+
%ol.ui-sortable.sortable.nested_set{ :id => "#{opts[:klass]}_nested_set" }= raw tree
|
@@ -0,0 +1 @@
|
|
1
|
+
= content_tag :ol, raw(children)
|
File without changes
|
File without changes
|
data/config/locales/en.yml
CHANGED
@@ -1,10 +1,31 @@
|
|
1
1
|
en:
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
2
|
+
sortable:
|
3
|
+
base:
|
4
|
+
new:
|
5
|
+
create: Add element
|
6
|
+
controls:
|
7
|
+
edit_this: Edit element
|
8
|
+
delete: Delete element
|
9
|
+
delete_confirm: Do you want to delete element?
|
10
|
+
cant_be_deleted: Cant be deleted. Has nested elements
|
11
|
+
delete_nested_elements: Delete all nested elements
|
12
|
+
|
13
|
+
comments:
|
14
|
+
base:
|
15
|
+
new_comment_form:
|
16
|
+
title: Name
|
17
|
+
conatacts: Email
|
18
|
+
content: Your comment
|
19
|
+
for: for
|
20
|
+
skip: '[skip]'
|
21
|
+
submit: Send Comment
|
22
|
+
comment:
|
23
|
+
reply: '[reply]'
|
24
|
+
new:
|
25
|
+
create: Add element
|
26
|
+
controls:
|
27
|
+
edit_this: Edit element
|
28
|
+
delete: Delete element
|
29
|
+
delete_confirm: Do you want to delete element?
|
30
|
+
cant_be_deleted: Cant be deleted. Has nested elements
|
31
|
+
delete_nested_elements: Delete all nested elements
|
@@ -5,16 +5,21 @@ module TheSortableTree
|
|
5
5
|
|
6
6
|
def self.banner
|
7
7
|
<<-BANNER.chomp
|
8
|
-
rails g the_sortable_tree:views MODEL [
|
8
|
+
rails g the_sortable_tree:views MODEL [tree|sortable|comments]
|
9
9
|
Copies files for rendering sortable nested set
|
10
10
|
BANNER
|
11
11
|
end
|
12
12
|
|
13
13
|
def copy_sortable_tree_files
|
14
|
-
|
15
|
-
|
14
|
+
# sortable
|
15
|
+
# comments
|
16
|
+
# tree
|
17
|
+
if ARGV[1] == 'sortable'
|
18
|
+
directory "sortable/base", "app/views/#{folder}/sortable/base"
|
19
|
+
elsif ARGV[1] == 'comments'
|
20
|
+
directory "comments/base", "app/views/#{folder}/comments/base"
|
16
21
|
else
|
17
|
-
directory "
|
22
|
+
directory "tree/base", "app/views/#{folder}/tree/base"
|
18
23
|
end
|
19
24
|
end
|
20
25
|
|
@@ -24,6 +29,6 @@ rails g the_sortable_tree:views MODEL [min]
|
|
24
29
|
name.pluralize.downcase
|
25
30
|
end
|
26
31
|
|
27
|
-
end
|
32
|
+
end
|
28
33
|
end
|
29
34
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: the_sortable_tree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.9.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-05-
|
12
|
+
date: 2012-05-08 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
16
|
-
requirement: &
|
16
|
+
requirement: &76895850 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '3.1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *76895850
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: sqlite3
|
27
|
-
requirement: &
|
27
|
+
requirement: &76895640 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *76895640
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rspec
|
38
|
-
requirement: &
|
38
|
+
requirement: &76895410 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *76895410
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rspec-rails
|
49
|
-
requirement: &
|
49
|
+
requirement: &76895200 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,8 +54,9 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
58
|
-
description: Drag&Drop GUI
|
57
|
+
version_requirements: *76895200
|
58
|
+
description: Sortable awesom_nested_set, Drag&Drop GUI for awesom_nested_set, View
|
59
|
+
Helper for nested set, Nested Comments
|
59
60
|
email:
|
60
61
|
- zykin-ilya@ya.ru
|
61
62
|
executables: []
|
@@ -87,22 +88,29 @@ files:
|
|
87
88
|
- app/assets/images/iconza/blue/delete.png
|
88
89
|
- app/assets/images/iconza/blue/up.png
|
89
90
|
- app/assets/images/iconza/blue/add.png
|
90
|
-
- app/assets/stylesheets/
|
91
|
-
- app/assets/stylesheets/
|
91
|
+
- app/assets/stylesheets/tree.css.scss
|
92
|
+
- app/assets/stylesheets/comments_tree.css.scss
|
93
|
+
- app/assets/stylesheets/sortable.css.scss
|
92
94
|
- app/assets/javascripts/jquery.ui.nestedSortable.js
|
93
|
-
- app/
|
94
|
-
- app/views/
|
95
|
-
- app/views/
|
96
|
-
- app/views/
|
97
|
-
- app/views/
|
98
|
-
- app/views/
|
99
|
-
- app/views/
|
100
|
-
- app/views/
|
101
|
-
- app/views/
|
102
|
-
- app/views/
|
103
|
-
- app/views/
|
104
|
-
- app/views/
|
105
|
-
- app/views/
|
95
|
+
- app/assets/javascripts/comments_tree.js.coffee
|
96
|
+
- app/views/comments/base/_children.html.haml
|
97
|
+
- app/views/comments/base/_node.html.haml
|
98
|
+
- app/views/comments/base/_tree.html.haml
|
99
|
+
- app/views/comments/base/_comment.html.haml
|
100
|
+
- app/views/comments/base/_new_comment_form.html.haml
|
101
|
+
- app/views/sortable/base/_children.html.haml
|
102
|
+
- app/views/sortable/base/_node.html.haml
|
103
|
+
- app/views/sortable/base/_link.html.haml
|
104
|
+
- app/views/sortable/base/_tree.html.haml
|
105
|
+
- app/views/sortable/base/_new.html.haml
|
106
|
+
- app/views/sortable/base/_controls.html.haml
|
107
|
+
- app/views/sortable/base/_js_rebuild_ajax.html.haml
|
108
|
+
- app/views/sortable/base/_js_init_sortable_tree.html.haml
|
109
|
+
- app/views/sortable/base/_js_on_update_tree.html.haml
|
110
|
+
- app/views/tree/base/_children.html.haml
|
111
|
+
- app/views/tree/base/_node.html.haml
|
112
|
+
- app/views/tree/base/_link.html.haml
|
113
|
+
- app/views/tree/base/_tree.html.haml
|
106
114
|
- app/helpers/the_sortable_tree_helper.rb
|
107
115
|
- config/locales/ru.yml
|
108
116
|
- config/locales/en.yml
|
@@ -169,7 +177,8 @@ rubyforge_project: the_sortable_tree
|
|
169
177
|
rubygems_version: 1.8.15
|
170
178
|
signing_key:
|
171
179
|
specification_version: 3
|
172
|
-
summary: Drag&Drop GUI
|
180
|
+
summary: Sortable awesom_nested_set, Drag&Drop GUI for awesom_nested_set, View Helper
|
181
|
+
for nested set, Nested Comments
|
173
182
|
test_files:
|
174
183
|
- spec/controlllers/controller_mixin_spec.rb
|
175
184
|
- spec/spec_helper.rb
|
@@ -1,120 +0,0 @@
|
|
1
|
-
ol.nested_set * {
|
2
|
-
margin: 0; padding: 0;
|
3
|
-
list-style:none;
|
4
|
-
}
|
5
|
-
.nested_set{
|
6
|
-
padding: 0;
|
7
|
-
list-style:none;
|
8
|
-
font-size: 16px;
|
9
|
-
}
|
10
|
-
.nested_set ol{
|
11
|
-
margin:0 0 0 25px;
|
12
|
-
border-left:1px dashed gray;
|
13
|
-
}
|
14
|
-
.nested_set li{
|
15
|
-
margin-bottom:5px;
|
16
|
-
}
|
17
|
-
.nested_set a{
|
18
|
-
color:#000;
|
19
|
-
font-size:10pt;
|
20
|
-
font-weight:normal;
|
21
|
-
text-decoration:none;
|
22
|
-
line-height: 150%;
|
23
|
-
margin-left:30px;
|
24
|
-
margin-right:120px;
|
25
|
-
display:block;
|
26
|
-
}
|
27
|
-
.nested_set a img{float:left;}
|
28
|
-
|
29
|
-
.nested_set .root a{
|
30
|
-
font-weight:bold;
|
31
|
-
}
|
32
|
-
.nested_set a:hover{
|
33
|
-
color:#2476FF;
|
34
|
-
text-decoration:none;
|
35
|
-
}
|
36
|
-
.nested_set .handle{
|
37
|
-
cursor: move;
|
38
|
-
}
|
39
|
-
.nested_set .link{
|
40
|
-
position: relative;
|
41
|
-
overflow: hidden;
|
42
|
-
zoom:1;
|
43
|
-
padding:5px;
|
44
|
-
margin:0 0 5px 5px;
|
45
|
-
background:#EFEFEF;
|
46
|
-
-moz-border-radius:5px;
|
47
|
-
}
|
48
|
-
.nested_set .link:hover{
|
49
|
-
background:#FEE;
|
50
|
-
}
|
51
|
-
.nested_set .controls{
|
52
|
-
position: absolute;
|
53
|
-
top: 5px; right: 10px;
|
54
|
-
}
|
55
|
-
.nested_set .button{
|
56
|
-
width:20px;
|
57
|
-
height:20px;
|
58
|
-
display:block;
|
59
|
-
float:left;
|
60
|
-
margin:0 0 0 3px;
|
61
|
-
cursor:pointer;
|
62
|
-
}
|
63
|
-
.nested_set_new_image{
|
64
|
-
vertical-align:middle;
|
65
|
-
border:none;
|
66
|
-
}
|
67
|
-
.nested_set_new{
|
68
|
-
margin:25px 0;
|
69
|
-
}
|
70
|
-
.nested_set_new a{
|
71
|
-
font-size:14pt;
|
72
|
-
}
|
73
|
-
.nested_set .handle{
|
74
|
-
width:16px;
|
75
|
-
height:16px;
|
76
|
-
float:left;
|
77
|
-
background:transparent url(/assets/iconza/blue/move.png) no-repeat scroll center center;
|
78
|
-
}
|
79
|
-
.nested_set .placeholder {
|
80
|
-
background-color:#EEF;
|
81
|
-
border:1px dashed blue;
|
82
|
-
}
|
83
|
-
.nested_set .ui-nestedSortable-error {
|
84
|
-
background:#FAA;
|
85
|
-
color:#8a1f11;
|
86
|
-
}
|
87
|
-
.nested_set .button.new{ background:transparent url(/assets/iconza/blue/add.png) no-repeat scroll center center; }
|
88
|
-
.nested_set .button.new:hover{ background:transparent url(/assets/iconza/red/add.png) no-repeat scroll center center;}
|
89
|
-
|
90
|
-
.nested_set .button.edit{ background:transparent url(/assets/iconza/blue/edit.png) no-repeat scroll center center; }
|
91
|
-
.nested_set .button.edit:hover{ background:transparent url(/assets/iconza/red/edit.png) no-repeat scroll center center;}
|
92
|
-
|
93
|
-
.nested_set .button.up{ background:transparent url(/assets/iconza/blue/up.png) no-repeat scroll center center; }
|
94
|
-
.nested_set .button.up:hover{ background:transparent url(/assets/iconza/red/up.png) no-repeat scroll center center;}
|
95
|
-
|
96
|
-
.nested_set .button.down{ background:transparent url(/assets/iconza/blue/down.png) no-repeat scroll center center; }
|
97
|
-
.nested_set .button.down:hover{ background:transparent url(/assets/iconza/red/down.png) no-repeat scroll center center;}
|
98
|
-
|
99
|
-
.nested_set .button.delete{ background:transparent url(/assets/iconza/blue/delete.png) no-repeat scroll center center; }
|
100
|
-
.nested_set .button.delete:hover{ background:transparent url(/assets/iconza/red/delete.png) no-repeat scroll center center;}
|
101
|
-
|
102
|
-
.nested_set .button.hard_delete{ background:transparent url(/assets/iconza/gray/delete.png) no-repeat scroll center center; }
|
103
|
-
.nested_set .button.hard_delete:hover{ background:transparent url(/assets/iconza/red/delete.png) no-repeat scroll center center;}
|
104
|
-
|
105
|
-
.nested_set .undeleted{ background:transparent url(/assets/iconza/gray/delete.png) no-repeat scroll center center; }
|
106
|
-
.nested_set .cantup{ background:transparent url(/assets/iconza/gray/up.png) no-repeat scroll center center; }
|
107
|
-
.nested_set .cantdown{ background:transparent url(/assets/iconza/gray/down.png) no-repeat scroll center center; }
|
108
|
-
|
109
|
-
/*STATES*/
|
110
|
-
.nested_set .unsafe{ background:transparent url(/assets/modern/mini-icons/unsafe.png) no-repeat scroll center center; cursor: help; }
|
111
|
-
.nested_set .draft{ background:transparent url(/assets/modern/mini-icons/draft.png) no-repeat scroll center center; cursor: help;}
|
112
|
-
.nested_set .published{ background:transparent url(/assets/modern/mini-icons/publiched.png) no-repeat scroll center center; cursor: help;}
|
113
|
-
.nested_set .restricted{ background:transparent url(/assets/modern/mini-icons/restricted.png) no-repeat scroll center center; cursor: help;}
|
114
|
-
.nested_set .archived{ background:transparent url(/assets/modern/mini-icons/archived.png) no-repeat scroll center center; cursor: help;}
|
115
|
-
.nested_set .deleted{ background:transparent url(/assets/modern/mini-icons/bin.png) no-repeat scroll center center; cursor: help;}
|
116
|
-
|
117
|
-
/* Moderation states*/
|
118
|
-
.nested_set .moderation_unsafe{ background:transparent url(/assets/modern/mini-icons/moderation_unsafe.png) no-repeat scroll center center; cursor: help;}
|
119
|
-
.nested_set .moderation_safe{ background:transparent url(/assets/modern/mini-icons/shield.png) no-repeat scroll center center; cursor: help;}
|
120
|
-
.nested_set .moderation_blocked{ background:transparent url(/assets/modern/mini-icons/moderation_blocked.png) no-repeat scroll center center; cursor: help;}
|
@@ -1,26 +0,0 @@
|
|
1
|
-
ol.nested_set_min * {
|
2
|
-
margin: 0; padding: 0;
|
3
|
-
list-style:none;
|
4
|
-
}
|
5
|
-
ol.nested_set_min {
|
6
|
-
list-style:none;
|
7
|
-
font-size: 16px;
|
8
|
-
}
|
9
|
-
ol.nested_set_min li{
|
10
|
-
font-size: 0.9em;
|
11
|
-
line-height: 130%;
|
12
|
-
margin-bottom: 5px;
|
13
|
-
font-weight: bold;
|
14
|
-
list-style:none;
|
15
|
-
list-style-position: outside;
|
16
|
-
}
|
17
|
-
ol.nested_set_min ol{
|
18
|
-
border-left: 1px dashed #AAA;
|
19
|
-
padding-left: 10px;
|
20
|
-
margin-left: 15px;
|
21
|
-
margin-top: 5px;
|
22
|
-
}
|
23
|
-
ol.nested_set_min ol li{ font-weight: normal; }
|
24
|
-
|
25
|
-
.nested_set_min a:hover { color: #003A89 !important; }
|
26
|
-
.nested_set_min a:visited { color: #809dc4; }
|
@@ -1,6 +0,0 @@
|
|
1
|
-
= render :partial => "#{opts[:path]}/new", :locals => { :opts => opts }
|
2
|
-
- unless tree.empty?
|
3
|
-
= render :partial => "#{opts[:path]}/js_init_sortable_tree", :locals => { :opts => opts }
|
4
|
-
= render :partial => "#{opts[:path]}/js_on_update_tree"
|
5
|
-
= render :partial => "#{opts[:path]}/js_rebuild_ajax", :locals => { :opts => opts }
|
6
|
-
%ol.ui-sortable.sortable.nested_set{ :id => "#{opts[:klass]}_nested_set" }= raw tree
|