the_sortable_tree 1.9.4 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/MIT-LICENSE +4 -2
  2. data/README.md +237 -438
  3. data/app/assets/images/iconza/{gray → icons}/add.png +0 -0
  4. data/app/assets/images/iconza/{gray → icons}/delete.png +0 -0
  5. data/app/assets/images/iconza/{gray → icons}/edit.png +0 -0
  6. data/app/assets/images/iconza/icons/move.png +0 -0
  7. data/app/assets/images/iconza/{red/add.png → icons/red_add.png} +0 -0
  8. data/app/assets/images/iconza/{red/delete.png → icons/red_delete.png} +0 -0
  9. data/app/assets/images/iconza/{red/edit.png → icons/red_edit.png} +0 -0
  10. data/app/assets/images/iconza/icons/red_move.png +0 -0
  11. data/app/assets/javascripts/render_tree_helper.js.coffee +82 -0
  12. data/app/assets/javascripts/sortable_tree/initializer.js.coffee +54 -0
  13. data/app/assets/stylesheets/sortable_tree.css.scss +106 -0
  14. data/app/assets/stylesheets/tree.css.scss +26 -29
  15. data/app/controllers/the_sortable_tree_controller.rb +3 -2
  16. data/app/helpers/render_sortable_tree_helper.rb +62 -0
  17. data/app/helpers/render_tree_helper.rb +45 -0
  18. data/app/helpers/the_sortable_tree_helper.rb +67 -52
  19. data/app/views/sortable/client/_tree.html.erb +9 -0
  20. data/app/views/tree/client/_tree.html.erb +23 -0
  21. data/lib/fake.example +44 -0
  22. data/lib/generators/the_sortable_tree/views_generator.rb +29 -18
  23. data/lib/the_sortable_tree.rb +4 -8
  24. data/lib/the_sortable_tree/engine.rb +1 -1
  25. data/lib/the_sortable_tree/version.rb +1 -1
  26. metadata +31 -60
  27. data/app/assets/images/iconza/blue/add.png +0 -0
  28. data/app/assets/images/iconza/blue/delete.png +0 -0
  29. data/app/assets/images/iconza/blue/down.png +0 -0
  30. data/app/assets/images/iconza/blue/downloads_folder.png +0 -0
  31. data/app/assets/images/iconza/blue/edit.png +0 -0
  32. data/app/assets/images/iconza/blue/move.png +0 -0
  33. data/app/assets/images/iconza/blue/up.png +0 -0
  34. data/app/assets/images/iconza/gray/down.png +0 -0
  35. data/app/assets/images/iconza/gray/lock.png +0 -0
  36. data/app/assets/images/iconza/gray/mail.png +0 -0
  37. data/app/assets/images/iconza/gray/push_pin.png +0 -0
  38. data/app/assets/images/iconza/gray/up.png +0 -0
  39. data/app/assets/images/iconza/red/down.png +0 -0
  40. data/app/assets/images/iconza/red/newspaper.png +0 -0
  41. data/app/assets/images/iconza/red/trash.png +0 -0
  42. data/app/assets/images/iconza/red/up.png +0 -0
  43. data/app/assets/images/iconza/red/zoom.png +0 -0
  44. data/app/assets/javascripts/comments/base.js.coffee +0 -46
  45. data/app/assets/javascripts/sortable/base.js.coffee +0 -47
  46. data/app/assets/stylesheets/comments_tree.css.scss +0 -84
  47. data/app/assets/stylesheets/sortable.css.scss +0 -106
  48. data/app/views/comments/base/_children.html.haml +0 -1
  49. data/app/views/comments/base/_comment.html.haml +0 -8
  50. data/app/views/comments/base/_new_comment_form.html.haml +0 -18
  51. data/app/views/comments/base/_node.html.haml +0 -3
  52. data/app/views/comments/base/_tree.html.haml +0 -5
  53. data/app/views/sortable/base/_children.html.haml +0 -1
  54. data/app/views/sortable/base/_controls.html.haml +0 -16
  55. data/app/views/sortable/base/_link.html.haml +0 -7
  56. data/app/views/sortable/base/_new.html.haml +0 -3
  57. data/app/views/sortable/base/_node.html.haml +0 -3
  58. data/app/views/sortable/base/_tree.html.haml +0 -12
  59. data/app/views/tree/base/_children.html.haml +0 -1
  60. data/app/views/tree/base/_link.html.haml +0 -1
  61. data/app/views/tree/base/_node.html.haml +0 -3
  62. data/app/views/tree/base/_tree.html.haml +0 -3
  63. data/config/locales/en.yml +0 -31
  64. data/config/locales/ru.yml +0 -31
  65. data/lib/tasks/the_sortable_tree.rake +0 -4
File without changes
File without changes
File without changes
@@ -0,0 +1,82 @@
1
+ @_escape = (str) ->
2
+ str
3
+ .replace(/&/g, '&')
4
+ .replace(/>/g, '>')
5
+ .replace(/</g, '&lt;')
6
+ .replace(/"/g, '&quot;')
7
+
8
+ @_unescape = (str) ->
9
+ str
10
+ .replace(/&amp;/g, '&')
11
+ .replace(/&gt;/g, '>')
12
+ .replace(/&lt;/g, '<')
13
+ .replace(/&quot;/g, '"')
14
+
15
+ @render_tree = (tree, options = {}) ->
16
+ html = ''
17
+
18
+ opts =
19
+ id: 'id'
20
+ node: null
21
+ root: false
22
+ level: 0
23
+ boost: []
24
+
25
+ # JQuery hash merge
26
+ $.extend opts, options
27
+
28
+ # Define Boost Only Once
29
+ unless opts['boost'].length is 0
30
+ boost = []
31
+ for node in tree
32
+ num = node.parent_id || 0
33
+ item = boost[num]
34
+ boost[num] = [] unless item instanceof Array
35
+ boost[num].push node
36
+
37
+ opts['boost'] = boost
38
+
39
+ unless opts.node
40
+ # render root nodes
41
+ roots = opts['boost'][0]
42
+
43
+ # select roots
44
+ # for node in tree
45
+ # roots.push node if node.parent_id is null
46
+
47
+ # roots is empty, but tree is not empty
48
+ # I should select nodes with minimal parent_id
49
+ # they will be roots
50
+ # order by lft, should be made at server side
51
+ min_elem = tree[0]
52
+ if roots.length is 0 and tree.length isnt 0
53
+ for elem in tree
54
+ min_elem = elem if elem.parent_id < min_elem.parent_id
55
+ # select roots witn min parent_id
56
+ for elem in tree
57
+ if elem.parent_id is min_elem.parent_id
58
+ roots.push elem
59
+
60
+ # render tree
61
+ for node in roots
62
+ $.extend opts, { node: node, root: false, level: opts.level + 1 }
63
+ children_html = render_tree tree, opts
64
+ html += opts.render_node(node, children_html, opts)
65
+ else
66
+ # render children nodes
67
+ children = []
68
+ children_html = ''
69
+ children = boost[opts.node.id]
70
+
71
+ # select children
72
+ # for elem in tree
73
+ # children.push elem if elem.parent_id is opts.node.id
74
+
75
+ # render children nodes
76
+ for node in children
77
+ $.extend opts, { node: node, root: false, level: opts.level + 1 }
78
+ children_html = render_tree tree, opts
79
+ html += opts.render_node(node, children_html, opts)
80
+
81
+ # result html
82
+ html
@@ -0,0 +1,54 @@
1
+ @rebuild_sortable_tree = (rebuild_url, item_id, parent_id, prev_id, next_id) ->
2
+ $.ajax
3
+ type: 'POST'
4
+ dataType: 'script'
5
+ url: rebuild_url
6
+ data:
7
+ id: item_id
8
+ parent_id: parent_id
9
+ prev_id: prev_id
10
+ next_id: next_id
11
+
12
+ beforeSend: (xhr) ->
13
+ $('.sortable_tree i.handle').hide()
14
+
15
+ success: (data, status, xhr) ->
16
+ $('.sortable_tree i.handle').show()
17
+
18
+ error: (xhr, status, error) ->
19
+ console.log error
20
+
21
+ $ ->
22
+ for sortable_tree in $('ol.sortable_tree')
23
+ sortable_tree = $ sortable_tree
24
+ rebuild_url = sortable_tree.data('rebuild_url')
25
+ max_levels = sortable_tree.data('max_levels')
26
+
27
+ ############################################
28
+ # Initialize Sortable Tree
29
+ ############################################
30
+ sortable_tree.nestedSortable
31
+ items: 'li'
32
+ helper: 'clone'
33
+ handle: 'i.handle'
34
+ tolerance: 'pointer'
35
+ maxLevels: max_levels
36
+ revert: 250
37
+ tabSize: 25
38
+ opacity: 0.6
39
+ placeholder: 'placeholder'
40
+ disableNesting: 'no-nest'
41
+ toleranceElement: '> div'
42
+ forcePlaceholderSize: true
43
+
44
+ ############################################
45
+ # Sortable Update Event
46
+ ############################################
47
+ sortable_tree.on "sortupdate", (event, ui) =>
48
+ item = ui.item
49
+ item_id = item.attr('id')
50
+ prev_id = item.prev().attr('id')
51
+ next_id = item.next().attr('id')
52
+ parent_id = item.parent().parent().attr('id')
53
+
54
+ rebuild_sortable_tree(rebuild_url, item_id, parent_id, prev_id, next_id)
@@ -0,0 +1,106 @@
1
+ .sortable_tree{
2
+ margin: 0; padding: 0;
3
+ *{ margin: 0; padding: 0; }
4
+
5
+ ol{
6
+ margin: 0 0 0 13px;
7
+ padding: 0 0 0 15px;
8
+ border-left: 1px dashed gray;
9
+ list-style: none outside none;
10
+ }
11
+
12
+ li{
13
+ margin-bottom:5px;
14
+ position: relative;
15
+ list-style: none outside none;
16
+ }
17
+
18
+ a{
19
+ color:#000;
20
+ font-size:10pt;
21
+ font-weight:normal;
22
+ text-decoration:none;
23
+ line-height: 150%;
24
+ margin-left:30px;
25
+ margin-right:120px;
26
+ display:block;
27
+ &:hover{ text-decoration: underline; }
28
+ }
29
+
30
+ h4{
31
+ margin: 0;
32
+ a{
33
+ color: #333;
34
+ font-size: 14px;
35
+ &:hover{ background: #eee; }
36
+ }
37
+ }
38
+
39
+ p{
40
+ margin-right: 75px;
41
+ padding: 5px;
42
+ }
43
+
44
+ .handle{
45
+ background: transparent url(/assets/iconza/icons/move.png);
46
+ background-position: center center;
47
+
48
+ width: 16px;
49
+ height: 16px;
50
+ margin: 3px 10px 0 0;
51
+ float: left;
52
+ cursor: move;
53
+
54
+ &:hover{ background: transparent url(/assets/iconza/icons/red_move.png); }
55
+ }
56
+
57
+ .item{
58
+ padding: 5px;
59
+ background: #f7f7f7;
60
+ border-radius: 3px;
61
+ margin-bottom: 5px;
62
+ &:hover{ background: #eee; }
63
+ }
64
+
65
+ .placeholder {
66
+ background-color: #EEF;
67
+ border: 1px dashed blue;
68
+ }
69
+
70
+ .ui-nestedSortable-error {
71
+ background: #FAA;
72
+ color: #8a1f11;
73
+ }
74
+
75
+ .controls{
76
+ position: absolute;
77
+ top: 1px; right: 10px;
78
+
79
+ a{
80
+ width: 20px;
81
+ height: 20px;
82
+ display: block;
83
+
84
+ float: left;
85
+ padding: 5px;
86
+ cursor: pointer;
87
+ position: relative;
88
+
89
+ margin: 0 0 5px 5px;
90
+ overflow: hidden; zoom: 1;
91
+
92
+ &.new{
93
+ background: transparent url(/assets/iconza/icons/add.png) no-repeat scroll center center;
94
+ &:hover{ background: transparent url(/assets/iconza/icons/red_add.png) no-repeat scroll center center; }
95
+ }
96
+ &.edit{
97
+ background: transparent url(/assets/iconza/icons/edit.png) no-repeat scroll center center;
98
+ &:hover{ background: transparent url(/assets/iconza/icons/red_edit.png) no-repeat scroll center center; }
99
+ }
100
+ &.delete{
101
+ background: transparent url(/assets/iconza/icons/delete.png) no-repeat scroll center center;
102
+ &:hover{ background: transparent url(/assets/iconza/icons/red_delete.png) no-repeat scroll center center; }
103
+ }
104
+ }
105
+ }
106
+ }
@@ -1,38 +1,35 @@
1
1
  .tree{
2
- * {
3
- margin: 0; padding: 0;
4
- list-style:none;
5
- }
2
+ margin:0; padding:0;
3
+ *{ margin: 0; padding: 0; }
6
4
 
7
5
  ol{
6
+ margin: 0 0 0 13px;
7
+ padding: 0 0 0 15px;
8
+ border-left: 1px dashed gray;
9
+ list-style: none outside none;
10
+ }
8
11
 
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;
12
+ li{
13
+ margin-bottom:5px;
14
+ position: relative;
15
+ list-style: none outside none;
16
+ }
30
17
 
31
- li{ font-weight: normal; }
32
- }
18
+ a{
19
+ color: black;
20
+ font-size: 14px;
33
21
 
34
- a:hover { color: #003A89 !important; }
35
- a:visited { color: #809dc4; }
22
+ &:hover {
23
+ color: black;
24
+ background: #ddd;
36
25
  }
37
26
  }
27
+
28
+ .item{
29
+ padding: 5px;
30
+ background: #eee;
31
+ margin-bottom: 5px;
32
+ border-radius: 3px;
33
+ &:hover{ background: #ddd; }
34
+ }
38
35
  }
@@ -5,8 +5,9 @@ module TheSortableTreeController
5
5
  module DefineVariablesMethod
6
6
  public
7
7
  def the_define_common_variables
8
- collection = self.class.to_s.split(':').last.sub(/Controller/,'').underscore.downcase # recipes
9
- variable = collection.singularize # recipe
8
+ collection = self.class.to_s.split(':').last.sub(/Controller/,'').underscore.downcase # 'recipes'
9
+ collection = self.respond_to?(:sortable_collection) ? self.sortable_collection : collection # 'recipes'
10
+ variable = collection.singularize # 'recipe'
10
11
  klass = self.respond_to?(:sortable_model) ? self.sortable_model : variable.classify.constantize # Recipe
11
12
  ["@#{variable}", collection, klass]
12
13
  end
@@ -0,0 +1,62 @@
1
+ # DOC:
2
+ # We use Helper Methods for tree building,
3
+ # because it's faster than View Templates and Partials
4
+
5
+ # SECURITY note
6
+ # Prepare your data on server side for rendering
7
+ # or use h.html_escape(node.content)
8
+ # for escape potentially dangerous content
9
+ module RenderSortableTreeHelper
10
+ module Render
11
+ class << self
12
+ attr_accessor :h, :options
13
+
14
+ def render_node(h, options)
15
+ @h, @options = h, options
16
+
17
+ node = options[:node]
18
+
19
+ "
20
+ <li id='#{ node.id }_#{ options[:klass] }'>
21
+ <div class='item'>
22
+ <i class='handle'></i>
23
+ #{ show_link }
24
+ #{ controls }
25
+ </div>
26
+ #{ children }
27
+ </li>
28
+ "
29
+ end
30
+
31
+ def show_link
32
+ node = options[:node]
33
+ ns = options[:namespace]
34
+ url = h.url_for(ns + [node])
35
+ title_field = options[:title]
36
+
37
+ "<h4>#{ h.link_to(node.send(title_field), url) }</h4>"
38
+ end
39
+
40
+ def controls
41
+ node = options[:node]
42
+
43
+ edit_path = h.url_for(:controller => options[:klass].pluralize, :action => :edit, :id => node)
44
+ show_path = h.url_for(:controller => options[:klass].pluralize, :action => :show, :id => node)
45
+
46
+ "
47
+ <div class='controls'>
48
+ #{ h.link_to '', edit_path, :class => :edit }
49
+ #{ h.link_to '', show_path, :class => :delete, :data => { :confirm => 'Are you sure?' } }
50
+ </div>
51
+ "
52
+ end
53
+
54
+ def children
55
+ unless options[:children].blank?
56
+ "<ol class='nested_set'>#{ options[:children] }</ol>"
57
+ end
58
+ end
59
+
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,45 @@
1
+ # DOC:
2
+ # We use Helper Methods for tree building,
3
+ # because it's faster than View Templates and Partials
4
+
5
+ # SECURITY note
6
+ # Prepare your data on server side for rendering
7
+ # or use h.html_escape(node.content)
8
+ # for escape potentially dangerous content
9
+ module RenderTreeHelper
10
+ class Render
11
+ class << self
12
+ attr_accessor :h, :options
13
+
14
+ def render_node(h, options)
15
+ @h, @options = h, options
16
+
17
+ node = options[:node]
18
+ "
19
+ <li>
20
+ <div class='item'>
21
+ #{ show_link }
22
+ </div>
23
+ #{ children }
24
+ </li>
25
+ "
26
+ end
27
+
28
+ def show_link
29
+ node = options[:node]
30
+ ns = options[:namespace]
31
+ url = h.url_for(ns + [node])
32
+ title_field = options[:title]
33
+
34
+ "<h4>#{ h.link_to(node.send(title_field), url) }</h4>"
35
+ end
36
+
37
+ def children
38
+ unless options[:children].blank?
39
+ "<ol>#{ options[:children] }</ol>"
40
+ end
41
+ end
42
+
43
+ end
44
+ end
45
+ end