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
|
@@ -0,0 +1,120 @@
|
|
|
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;}
|
|
@@ -0,0 +1,26 @@
|
|
|
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; }
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module TheSortableTreeController
|
|
2
|
+
# include TheSortableTreeController::ReversedRebuild
|
|
3
|
+
# include TheSortableTreeController::Rebuild
|
|
4
|
+
|
|
5
|
+
module DefineVariablesMethod
|
|
6
|
+
public
|
|
7
|
+
def the_define_common_variables
|
|
8
|
+
collection = self.class.to_s.split(':').last.sub(/Controller/,"").underscore.downcase # recipes
|
|
9
|
+
variable = collection.singularize # recipe
|
|
10
|
+
klass = variable.classify.constantize # Recipe
|
|
11
|
+
["@#{variable}", collection, klass]
|
|
12
|
+
end
|
|
13
|
+
end#DefineVariablesMethod
|
|
14
|
+
|
|
15
|
+
module Rebuild
|
|
16
|
+
include DefineVariablesMethod
|
|
17
|
+
public
|
|
18
|
+
def rebuild
|
|
19
|
+
id = !params[:id].nil? ? params[:id].sub("_menuitem","") : ""
|
|
20
|
+
parent_id = !params[:parent_id].nil? ? params[:parent_id].sub("_menuitem","") : ""
|
|
21
|
+
prev_id = !params[:prev_id].nil? ? params[:prev_id].sub("_menuitem","") : ""
|
|
22
|
+
next_id = !params[:next_id].nil? ? params[:next_id].sub("_menuitem","") : ""
|
|
23
|
+
|
|
24
|
+
render :text => "Do nothing" and return if parent_id.empty? && prev_id.empty? && next_id.empty?
|
|
25
|
+
|
|
26
|
+
variable, collection, klass = self.the_define_common_variables
|
|
27
|
+
variable = self.instance_variable_set(variable, klass.find(id))
|
|
28
|
+
|
|
29
|
+
if prev_id.empty? && next_id.empty?
|
|
30
|
+
variable.move_to_child_of klass.find(parent_id)
|
|
31
|
+
elsif !prev_id.empty?
|
|
32
|
+
variable.move_to_right_of klass.find(prev_id)
|
|
33
|
+
elsif !next_id.empty?
|
|
34
|
+
variable.move_to_left_of klass.find(next_id)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
render(:nothing => true)
|
|
38
|
+
end
|
|
39
|
+
end#Rebuild
|
|
40
|
+
|
|
41
|
+
module ReversedRebuild
|
|
42
|
+
include DefineVariablesMethod
|
|
43
|
+
public
|
|
44
|
+
def rebuild
|
|
45
|
+
id = !params[:id].nil? ? params[:id].sub("_menuitem","") : ""
|
|
46
|
+
parent_id = !params[:parent_id].nil? ? params[:parent_id].sub("_menuitem","") : ""
|
|
47
|
+
prev_id = !params[:prev_id].nil? ? params[:prev_id].sub("_menuitem","") : ""
|
|
48
|
+
next_id = !params[:next_id].nil? ? params[:next_id].sub("_menuitem","") : ""
|
|
49
|
+
|
|
50
|
+
render :text => "Do nothing" and return if parent_id.empty? && prev_id.empty? && next_id.empty?
|
|
51
|
+
|
|
52
|
+
variable, collection, klass = self.the_define_common_variables
|
|
53
|
+
variable = self.instance_variable_set(variable, klass.find(id))
|
|
54
|
+
|
|
55
|
+
if prev_id.empty? && next_id.empty?
|
|
56
|
+
variable.move_to_child_of klass.find(parent_id)
|
|
57
|
+
elsif !prev_id.empty?
|
|
58
|
+
variable.move_to_left_of klass.find(prev_id)
|
|
59
|
+
elsif !next_id.empty?
|
|
60
|
+
variable.move_to_right_of klass.find(next_id)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
render(:nothing => true)
|
|
64
|
+
end
|
|
65
|
+
end#ReversedRebuild
|
|
66
|
+
|
|
67
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module TheSortableTreeHelper
|
|
2
|
+
# Publicated by MIT
|
|
3
|
+
# Nested Set View Helper
|
|
4
|
+
# Ilya Zykin, zykin-ilya@ya.ru, Russia, Ivanovo 2009-2012
|
|
5
|
+
# github.com/the-teacher
|
|
6
|
+
#-------------------------------------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
# = sortable_tree @pages, :new_url => new_page_url, :max_levels => 5
|
|
9
|
+
# = sortable_tree @products, :new_url => new_product_url, :path => 'products/the_sortable_tree'
|
|
10
|
+
# = sortable_tree @catalogs, :namespace => :admin, :new_url => new_catalog_url, :max_levels => 5
|
|
11
|
+
|
|
12
|
+
def define_class_of_elements_of tree
|
|
13
|
+
case
|
|
14
|
+
#when tree.is_a?(ActiveRecord::Relation) then tree.name.to_s.downcase
|
|
15
|
+
when tree.empty? then nil
|
|
16
|
+
else tree.first.class.to_s.downcase
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def sortable_tree(tree, opts= {})
|
|
21
|
+
opts.merge!({
|
|
22
|
+
:path => opts[:path] || :the_sortable_tree,
|
|
23
|
+
:klass => define_class_of_elements_of(tree),
|
|
24
|
+
:title => opts[:title] || :title,
|
|
25
|
+
:max_levels => opts[:max_levels] || 3,
|
|
26
|
+
:namespace => Array.wrap(opts[:namespace])
|
|
27
|
+
})
|
|
28
|
+
render :partial => "#{opts[:path]}/tree", :locals => { :tree => sortable_tree_builder(tree, opts), :opts => opts }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def sortable_tree_builder(tree, options= {})
|
|
32
|
+
result = ''
|
|
33
|
+
opts = {
|
|
34
|
+
:id => :id, # node id field
|
|
35
|
+
:node => nil, # node
|
|
36
|
+
:root => false, # is it root node?
|
|
37
|
+
:level => 0 # recursion level
|
|
38
|
+
}.merge!(options)
|
|
39
|
+
|
|
40
|
+
root = opts[:root]
|
|
41
|
+
node = opts[:node]
|
|
42
|
+
|
|
43
|
+
unless node
|
|
44
|
+
roots = tree.select{ |elem| elem.parent_id.nil? }
|
|
45
|
+
|
|
46
|
+
# TODO: try to remove compact
|
|
47
|
+
# children rendering
|
|
48
|
+
if roots.empty? && !tree.empty?
|
|
49
|
+
min_parent_id = tree.map(&:parent_id).compact.min
|
|
50
|
+
roots = tree.select{ |elem| elem.parent_id == min_parent_id }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
roots.each do |root|
|
|
54
|
+
_opts = opts.merge({:node => root, :root => true, :level => opts[:level].next})
|
|
55
|
+
result << sortable_tree_builder(tree, _opts)
|
|
56
|
+
end
|
|
57
|
+
else
|
|
58
|
+
children_res = ''
|
|
59
|
+
children = tree.select{|elem| elem.parent_id == node.id}
|
|
60
|
+
opts.merge!({:has_children => children.blank?})
|
|
61
|
+
children.each do |elem|
|
|
62
|
+
_opts = opts.merge({:node => elem, :root => false, :level => opts[:level].next})
|
|
63
|
+
children_res << sortable_tree_builder(tree, _opts)
|
|
64
|
+
end
|
|
65
|
+
result << render(:partial => "#{opts[:path]}/node", :locals => {:opts => opts, :root => root, :node => node, :children => children_res})
|
|
66
|
+
end
|
|
67
|
+
raw result
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
= content_tag :ol, raw(children)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
-# EDIT
|
|
2
|
+
- edit = link_to '', polymorphic_url(opts[:namespace] + [node], :action => :edit), :title => t('.edit_this'), :class => 'button edit'
|
|
3
|
+
-# DELETE
|
|
4
|
+
- if opts[:has_children]
|
|
5
|
+
- delete = link_to('', url_for(opts[:namespace] + [node]),
|
|
6
|
+
:title => t('.delete'),
|
|
7
|
+
:method => :delete,
|
|
8
|
+
:confirm => t('.delete_confirm'),
|
|
9
|
+
:class => 'button delete')
|
|
10
|
+
- else
|
|
11
|
+
- delete = link_to('', '#',
|
|
12
|
+
:title => t('.cant_be_deleted'),
|
|
13
|
+
:onclick => "alert('#{t('.delete_nested_elements')}')",
|
|
14
|
+
:class => 'button undeleted')
|
|
15
|
+
-# OUTPUT
|
|
16
|
+
= edit + delete
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
:javascript
|
|
2
|
+
$(function(){
|
|
3
|
+
$('ol.sortable').nestedSortable({
|
|
4
|
+
disableNesting: 'no-nest',
|
|
5
|
+
forcePlaceholderSize: true,
|
|
6
|
+
handle: 'i.handle',
|
|
7
|
+
helper: 'clone',
|
|
8
|
+
items: 'li',
|
|
9
|
+
maxLevels: #{opts[:max_levels]},
|
|
10
|
+
opacity: .6,
|
|
11
|
+
placeholder: 'placeholder',
|
|
12
|
+
revert: 250,
|
|
13
|
+
tabSize: 25,
|
|
14
|
+
tolerance: 'pointer',
|
|
15
|
+
toleranceElement: '> div'
|
|
16
|
+
})
|
|
17
|
+
});
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
:javascript
|
|
2
|
+
$(function(){
|
|
3
|
+
$('ol.sortable').sortable({
|
|
4
|
+
update: function(event, ui){
|
|
5
|
+
parent_id = ui.item.parent().parent().attr('id');
|
|
6
|
+
item_id = ui.item.attr('id');
|
|
7
|
+
prev_id = ui.item.prev().attr('id');
|
|
8
|
+
next_id = ui.item.next().attr('id');
|
|
9
|
+
sortable_tree(item_id, parent_id, prev_id, next_id);
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
:javascript
|
|
2
|
+
function sortable_tree(item_id, parent_id, prev_id, next_id){
|
|
3
|
+
jQuery.ajax({
|
|
4
|
+
type: 'POST',
|
|
5
|
+
dataType: 'script',
|
|
6
|
+
url: '#{url_for(:controller => opts[:klass].pluralize, :action => :rebuild)}',
|
|
7
|
+
data: { id: item_id, parent_id: parent_id, prev_id: prev_id, next_id: next_id },
|
|
8
|
+
|
|
9
|
+
beforeSend: function(xhr){ $('.nested_set i.handle').hide() },
|
|
10
|
+
success: function(data, status, xhr){ $('.nested_set i.handle').show() },
|
|
11
|
+
error: function(xhr, status, error){ alert(error) }
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
- title = node.send opts[:title]
|
|
2
|
+
- handle = content_tag :i, '', :class => :handle
|
|
3
|
+
- link = link_to(title, url_for(opts[:namespace] + [node]), :title => title)
|
|
4
|
+
- controls = render(:partial => "#{opts[:path]}/controls", :locals => { :node => node, :opts => opts })
|
|
5
|
+
- controls = content_tag(:b, controls, :class => :controls)
|
|
6
|
+
- element = handle + controls + link
|
|
7
|
+
%div{ :class => "link#{' root' if root}" }= element
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
%li{ :id => "#{node.send(opts[:id])}_#{opts[:klass]}" }
|
|
2
|
+
= raw render(:partial => "#{opts[:path]}/link", :locals => {:opts => opts, :root => root, :node => node})
|
|
3
|
+
= render(:partial => "#{opts[:path]}/children", :locals => {:opts => opts, :parent => node, :children => children}) unless children.blank?
|
|
@@ -0,0 +1,6 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
= content_tag :ol, raw(children)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
= link_to node.send(opts[:title]), url_for(opts[:namespace] + [node]), :title => node.send(opts[:title])
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
en:
|
|
2
|
+
the_sortable_tree:
|
|
3
|
+
new:
|
|
4
|
+
create: Add element
|
|
5
|
+
controls:
|
|
6
|
+
edit_this: Edit element
|
|
7
|
+
delete: Delete element
|
|
8
|
+
delete_confirm: Do you want to delete element?
|
|
9
|
+
cant_be_deleted: Cant be deleted. Has nested elements
|
|
10
|
+
delete_nested_elements: Delete all nested elements
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
ru:
|
|
2
|
+
the_sortable_tree:
|
|
3
|
+
new:
|
|
4
|
+
create: Добавить элемент
|
|
5
|
+
controls:
|
|
6
|
+
edit_this: Редактировать элемент
|
|
7
|
+
delete: Удалить элемент
|
|
8
|
+
delete_confirm: Удалить элемент безвозвратно?
|
|
9
|
+
cant_be_deleted: Не может быть удалено. Есть дочерние элементы
|
|
10
|
+
delete_nested_elements: Сперва удалите все дочерние элементы
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module TheSortableTree
|
|
2
|
+
module Generators
|
|
3
|
+
class ViewsGenerator < Rails::Generators::NamedBase
|
|
4
|
+
source_root File.expand_path('../../../../app/views', __FILE__)
|
|
5
|
+
|
|
6
|
+
def self.banner
|
|
7
|
+
<<-BANNER.chomp
|
|
8
|
+
rails g the_sortable_tree:views MODEL [min]
|
|
9
|
+
Copies files for rendering sortable nested set
|
|
10
|
+
BANNER
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def copy_sortable_tree_files
|
|
14
|
+
if ARGV[1] == 'min'
|
|
15
|
+
directory "the_sortable_tree_min", "app/views/#{folder}/the_sortable_tree_min"
|
|
16
|
+
else
|
|
17
|
+
directory "the_sortable_tree", "app/views/#{folder}/the_sortable_tree"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def folder
|
|
24
|
+
name.pluralize.downcase
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end#ViewsGenerator
|
|
28
|
+
end
|
|
29
|
+
end
|