sortable_nested_set 0.2.3 → 0.3.0

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/README.rdoc CHANGED
@@ -1,32 +1,44 @@
1
- jQuery is required.
1
+ = Sortable Nested Set
2
2
 
3
- In the Gemfile
4
- gem 'sortable_nested_set'
3
+ == Requirements
5
4
 
6
- In each "Category" model (e.g. "Directory"):
7
- acts_as_sortable_nested_set_of :items
8
- where :items is the pluralized Item model (e.g. "File").
5
+ jQuery is required.
9
6
 
10
- In each "Category" controller:
11
- handles_sortable_nested_set
12
- to include menu actions.
7
+ == Usage
13
8
 
14
- In the routes config file:
15
- sortable_nested_set_for :categories
16
- for each pluralized "Category" model.
9
+ Add the gem to your Gemfile.
17
10
 
18
- In each "Category" migration:
19
- name:string
11
+ gem 'sortable_nested_set'
12
+
13
+ In each "Category" (e.g. "Directory") migration:
20
14
  lft:integer
21
15
  rgt:integer
16
+ depth:integer [optional]
22
17
 
23
- In each "Item" migration:
24
- position:integer
18
+ In the routing configuration file:
19
+ nest the "Category" and "Item" resources
20
+
21
+ In each "Category" model:
22
+ acts_as_sortable_nested_set_of :items
23
+ where :items is the pluralized, underscored "Item" model (e.g. "ImageFile"=>:image_files).
24
+
25
+ In the "Category" and "Item" controllers:
26
+ [new] use param[:category_id]
27
+ [destroy] respond_to format.js (and provide associated view)
28
+
29
+ In the "Category" and "Items" models:
30
+ provide #to_s.
25
31
 
26
32
  In the <head> section of the layout(s) where the trees will be displayed:
27
33
  yield(:head)
34
+ after jQuery is loaded.
35
+
36
+ == Support for acts_as_list
37
+
38
+ When an "Item" model acts_as_list, SortableNestedSet will use its position for sorting.
39
+
40
+ == Helpers
28
41
 
29
- Helpers:
30
42
  sns_options
31
43
  sns_lineage
32
- sortable_nested_set_tree
44
+ sns_tree
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.3
1
+ 0.3.0
@@ -0,0 +1,35 @@
1
+ class SortableNestedSetController < ActionController::Base
2
+ def sns_sort
3
+ category_class = params[:category_class].classify.constantize
4
+
5
+ matches = params[:moved].match(/(\w+)_(\d+)$/)
6
+ moved_type = matches[1]
7
+ moved_id = matches[2].to_i
8
+ moved_parent = nil
9
+ tree = {} # category_id => [children of move_type]
10
+
11
+ for node in params[:tree].scan(/(\w+)\[(\d+)\]=(\w+)/)
12
+ type = node[0]
13
+ next unless type == moved_type
14
+
15
+ id = node[1].to_i
16
+ parent = (node[2] == 'root') ? nil : node[2].to_i
17
+
18
+ moved_parent = parent if id == moved_id
19
+
20
+ tree[parent] ||= []
21
+ tree[parent] << id
22
+ end
23
+
24
+ if moved_type == category_class.sns_items_type.to_s.singularize
25
+ item = category_class.sns_items_type.to_s.classify.constantize.find(moved_id)
26
+ item.remove_from_list if item.respond_to?(:remove_from_list) # acts_as_list support
27
+ item.update_attribute(category_class.name.foreign_key, moved_parent)
28
+ item.insert_at(tree[moved_parent].index(moved_id)) if item.respond_to?(:insert_at) # acts_as_list support
29
+ else
30
+ moved_type.classify.constantize.find(moved_id).move(moved_parent, tree[moved_parent])
31
+ end
32
+
33
+ render :nothing => true
34
+ end
35
+ end
@@ -1,5 +1,5 @@
1
1
  module SortableNestedSetHelper
2
- def sortable_nested_set_tree(class_or_category)
2
+ def sns_tree(class_or_category)
3
3
  if class_or_category.is_a?(Class)
4
4
  @category_class = class_or_category
5
5
  @categories = @category_class.includes(@category_class.sns_items_type)
@@ -8,8 +8,7 @@ module SortableNestedSetHelper
8
8
  @categories = class_or_category.self_and_descendants.includes(@category_class.sns_items_type)
9
9
  end
10
10
 
11
- sns_sort_path = "sns_sort_#{@category_class.name.underscore.pluralize}_path"
12
- render 'sortable_nested_set/tree', :categories => @categories.arrange, :sns_sort_path => sns_sort_path
11
+ render 'sortable_nested_set/tree', :category_class => @category_class, :categories => @categories.arrange
13
12
  end
14
13
 
15
14
  def sns_lineage(category, options={})
@@ -27,8 +26,6 @@ module SortableNestedSetHelper
27
26
  end
28
27
 
29
28
  def sns_options(category_class, mover=nil)
30
- sorted_nested_set_options(category_class, lambda(&:left_column_name), mover) do |category, level|
31
- '.' * level + category.name
32
- end
29
+ sorted_nested_set_options(category_class, lambda(&:left_column_name), mover) { |cat, lvl| "#{'.'*lvl}#{cat}" }
33
30
  end
34
31
  end
@@ -1,20 +1,14 @@
1
- <% cpath = category.class.name.underscore + '_path' %>
2
-
3
1
  <div>
4
2
  <span class="toggle open"></span>
5
3
  <span class="handle"><%= category %></span>
6
4
  <%= link_to image_tag('mega_menu.png'), category, :class => :mega_menu %>
7
5
  <div class="mega_menu_links">
8
6
  <%= link_to_unless_current 'show', category %> |
9
- <%= link_to 'edit', send("edit_#{cpath}", category) %> |
10
- <%= link_to 'remove',
11
- send("sns_destroy_category_#{cpath}", category),
12
- :confirm => 'Are you sure?',
13
- :method => :delete,
14
- :remote => !current_page?(send(cpath, category)) %> |
7
+ <%= link_to 'edit', polymorphic_path(category, :action => :edit) %> |
8
+ <%= link_to 'remove', category, :confirm => 'Are you sure?', :method => :delete, :remote => !current_page?(category) %> |
15
9
  <%= link_to "add #{category.class.sns_subcategories_type.to_s.singularize}",
16
- send("sns_add_subcategory_#{cpath}", category) %> |
10
+ polymorphic_path([category, category.class], :action => :new) %> |
17
11
  <%= link_to "add #{category.class.sns_items_type.to_s.singularize}",
18
- send("sns_add_item_#{cpath}", category) %>
12
+ polymorphic_path([category, category.class.sns_items_class], :action => :new) %>
19
13
  </div>
20
14
  </div>
@@ -4,12 +4,8 @@
4
4
  <%= link_to image_tag('mega_menu.png'), item, :class => :mega_menu %>
5
5
  <div class="mega_menu_links">
6
6
  <%= link_to 'show', item %> |
7
- <%= link_to 'edit', send("edit_#{item.class.name.underscore}_path", item) %> |
8
- <%= link_to 'remove',
9
- send("sns_destroy_item_#{item.class.name.underscore}_path", item),
10
- :confirm => 'Are you sure?',
11
- :method => :delete,
12
- :remote => true %>
7
+ <%= link_to 'edit', polymorphic_path(item, :action => :edit) %> |
8
+ <%= link_to 'remove', item, :confirm => 'Are you sure?', :method => :delete, :remote => true %>
13
9
  </div>
14
10
  </div>
15
11
  </li>
@@ -5,14 +5,12 @@
5
5
  'sortable_nested_set' %>
6
6
  <% end %>
7
7
 
8
- <%= render_tree categories, :id => :sns_categories, :class => :sortable, 'data-url' => send(sns_sort_path) do |node, child| %>
9
- <li id="<%= node.class.name.underscore %>_<%= node.id %>" class="sns_category">
10
- <%= render :partial => 'sortable_nested_set/category', :object => node %>
11
-
12
- <ul>
13
- <%= render :partial => 'sortable_nested_set/item', :collection => node.sns_items %>
14
- </ul>
15
-
8
+ <%= render_tree categories, :id => :sns_categories,
9
+ :class => :sortable,
10
+ 'data-url' => sns_sort_path(:category_class => @category_class) do |category, child| %>
11
+ <li id="<%= category.class.name.underscore %>_<%= category.id %>" class="sns_category">
12
+ <%= render :partial => 'sortable_nested_set/category', :object => category %>
13
+ <ul><%= render :partial => 'sortable_nested_set/item', :collection => category.sns_items %></ul>
16
14
  <%= child %>
17
15
  </li>
18
16
  <% end %>
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ Rails::Application.routes.draw do
2
+ put :sns_sort, :controller => :sortable_nested_set
3
+ end
@@ -1,5 +1,4 @@
1
1
  require 'nested_set'
2
- include CollectiveIdea::Acts::NestedSet
3
2
 
4
3
  module SortableNestedSet
5
4
  def self.included(base)
@@ -11,10 +10,12 @@ module SortableNestedSet
11
10
  def acts_as_sortable_nested_set_of(items_type)
12
11
  @subcategories_type = "sub#{name.tableize}".to_sym
13
12
  @items_type = items_type
13
+ @foreign_key = self.class.method_defined?(:parent) ? :parent_id : name.foreign_key
14
14
 
15
15
  instance_eval do
16
16
  def sns_subcategories_type ; @subcategories_type end
17
17
  def sns_items_type ; @items_type end
18
+ def sns_items_class ; @items_type.to_s.singularize.classify.constantize end
18
19
  end
19
20
 
20
21
  class_eval do
@@ -22,16 +23,22 @@ module SortableNestedSet
22
23
  define_method(:sns_items) { send(self.class.sns_items_type) }
23
24
  end
24
25
 
25
- acts_as_nested_set :parent_column => name.foreign_key
26
+ acts_as_nested_set :parent_column => @foreign_key
26
27
 
27
- belongs_to name.underscore.to_sym
28
+ has_many @subcategories_type, :class_name => name, :foreign_key => @foreign_key, :dependent => :destroy
29
+ has_many @items_type,
30
+ :order => (sns_items_class.position_column if sns_items_class.method_defined?(:position_column)),
31
+ :dependent => :destroy
28
32
 
29
- has_many @subcategories_type, :class_name => name, :dependent => :destroy
30
- has_many @items_type, :order => :position, :dependent => :destroy
33
+ after_initialize :default_depth_to_zero
31
34
  end
32
35
  end
33
36
 
34
37
  module InstanceMethods
38
+ def indented_name(indentation_character='.')
39
+ indentation_character * depth + name
40
+ end
41
+
35
42
  def move(parent, children)
36
43
  if children.size == 1
37
44
  move_to_child_of(parent)
@@ -39,7 +46,7 @@ module SortableNestedSet
39
46
  prev_sibling = nil
40
47
 
41
48
  for i in 0...children.size
42
- if children[i] == id
49
+ if children[i] == self.id
43
50
  prev_sibling ? move_to_right_of(prev_sibling) : move_to_left_of(children[i+1])
44
51
  break
45
52
  end
@@ -49,8 +56,10 @@ module SortableNestedSet
49
56
  end
50
57
  end
51
58
 
52
- def indented_name(indentation_character='.')
53
- indentation_character * level + name
59
+ private
60
+
61
+ def default_depth_to_zero
62
+ self.depth ||= 0 if has_attribute?(:depth)
54
63
  end
55
64
  end
56
65
  end
@@ -1,4 +1,12 @@
1
- require 'sortable_nested_set/engine'
2
- require 'sortable_nested_set/acts_as_sortable_nested_set'
3
- require 'sortable_nested_set/handles_sortable_nested_set'
4
- require 'sortable_nested_set/routes'
1
+ module SortableNestedSet
2
+ class Engine < Rails::Engine
3
+ initializer 'nested_fields.add_middleware' do |app|
4
+ require 'acts_as_sortable_nested_set'
5
+ app.middleware.use ActionDispatch::Static, "#{root}/public"
6
+ end
7
+
8
+ config.to_prepare do
9
+ ApplicationController.helper(SortableNestedSetHelper)
10
+ end
11
+ end
12
+ end
@@ -1,38 +1,44 @@
1
- $(document).ready(function() {
2
- function linkHover() {
3
- $(this).next().addClass('link_hover');
4
- }
5
-
6
- function linkUnhover() {
7
- if (!$(this).next().hasClass('pop_up_hover'))
8
- $(this).next().removeClass('link_hover');
9
- }
10
-
11
- function popUpHover() {
12
- $(this).removeClass('link_hover');
13
- $(this).addClass('pop_up_hover');
14
- }
15
-
16
- function popUpUnhover() {
17
- $(this).removeClass('pop_up_hover');
18
- }
19
-
20
- var linkConfig = {
21
- interval: 200,
22
- out: linkUnhover,
23
- over: linkHover,
24
- sensitivity: 4,
25
- timeout: 250
26
- };
27
-
28
- var popUpConfig = {
29
- interval: 0,
30
- out: popUpUnhover,
31
- over: popUpHover,
32
- sensitivity: 4,
33
- timeout: 250
34
- };
1
+ $('#sns_categories span.toggle').live('click', function() {
2
+ $(this).toggleClass('open');
3
+ $(this).toggleClass('closed');
4
+ $(this).closest('li').find('> ul').toggle();
5
+ });
6
+
7
+ function linkHover() {
8
+ $(this).next().addClass('link_hover');
9
+ }
10
+
11
+ function linkUnhover() {
12
+ if (!$(this).next().hasClass('pop_up_hover'))
13
+ $(this).next().removeClass('link_hover');
14
+ }
15
+
16
+ function popUpHover() {
17
+ $(this).removeClass('link_hover');
18
+ $(this).addClass('pop_up_hover');
19
+ }
20
+
21
+ function popUpUnhover() {
22
+ $(this).removeClass('pop_up_hover');
23
+ }
24
+
25
+ var linkConfig = {
26
+ interval: 200,
27
+ out: linkUnhover,
28
+ over: linkHover,
29
+ sensitivity: 4,
30
+ timeout: 250
31
+ };
32
+
33
+ var popUpConfig = {
34
+ interval: 0,
35
+ out: popUpUnhover,
36
+ over: popUpHover,
37
+ sensitivity: 4,
38
+ timeout: 250
39
+ };
35
40
 
41
+ $(document).ready(function() {
36
42
  $('.mega_menu').hoverIntent(linkConfig);
37
43
  $('.mega_menu_links').hoverIntent(popUpConfig);
38
44
 
@@ -54,10 +60,4 @@ $(document).ready(function() {
54
60
  });
55
61
  }
56
62
  });
57
-
58
- $('#sns_categories .toggle').click(function() {
59
- $(this).toggleClass('open');
60
- $(this).toggleClass('closed');
61
- $(this).closest('li').find('> ul').toggle();
62
- });
63
63
  });
@@ -1,3 +1,8 @@
1
+ .toggle {
2
+ cursor: pointer;
3
+ padding-right: 1em;
4
+ }
5
+
1
6
  .mega_menu_links {
2
7
  background: #ffc;
3
8
  border: 1px solid #eea;
@@ -12,8 +17,8 @@
12
17
  }
13
18
 
14
19
  .pop_up_hover {
15
- display: block;
16
20
  border: 1px solid #cca;
21
+ display: block;
17
22
  }
18
23
 
19
24
  #sns_categories, #sns_categories ul {
@@ -23,7 +28,7 @@
23
28
  }
24
29
 
25
30
  #sns_categories {
26
- margin: 0;
31
+ margin: 0 0 10px 0;
27
32
  }
28
33
 
29
34
  #sns_categories li {
@@ -47,11 +52,6 @@
47
52
  color: #8a1f11;
48
53
  }
49
54
 
50
- .toggle {
51
- cursor: pointer;
52
- padding-right: 1em;
53
- }
54
-
55
55
  #sns_categories span.open {
56
56
  background: url(/images/folder_open.png) no-repeat center;
57
57
  }
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{sortable_nested_set}
8
- s.version = "0.2.3"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Jason Murad"]
12
- s.date = %q{2011-01-22}
12
+ s.date = %q{2011-01-25}
13
13
  s.description = %q{reusable menu for navigation and modification or hierarchical categories}
14
14
  s.email = %q{jason@thriess.com}
15
15
  s.extra_rdoc_files = [
@@ -22,17 +22,14 @@ Gem::Specification.new do |s|
22
22
  "README.rdoc",
23
23
  "Rakefile",
24
24
  "VERSION",
25
+ "app/controllers/sortable_nested_set_controller.rb",
25
26
  "app/helpers/sortable_nested_set_helper.rb",
26
27
  "app/views/sortable_nested_set/_category.html.erb",
27
28
  "app/views/sortable_nested_set/_item.html.erb",
28
29
  "app/views/sortable_nested_set/_tree.html.erb",
29
- "app/views/sortable_nested_set/sns_destroy_category.js.erb",
30
- "app/views/sortable_nested_set/sns_destroy_item.js.erb",
30
+ "config/routes.rb",
31
+ "lib/acts_as_sortable_nested_set.rb",
31
32
  "lib/sortable_nested_set.rb",
32
- "lib/sortable_nested_set/acts_as_sortable_nested_set.rb",
33
- "lib/sortable_nested_set/engine.rb",
34
- "lib/sortable_nested_set/handles_sortable_nested_set.rb",
35
- "lib/sortable_nested_set/routes.rb",
36
33
  "public/images/folder_closed.png",
37
34
  "public/images/folder_open.png",
38
35
  "public/images/mega_menu.png",
data/test/helper.rb CHANGED
@@ -12,7 +12,6 @@ require 'shoulda'
12
12
 
13
13
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
14
14
  $LOAD_PATH.unshift(File.dirname(__FILE__))
15
- require 'sortable_nested_set'
16
15
 
17
16
  class Test::Unit::TestCase
18
17
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 2
8
7
  - 3
9
- version: 0.2.3
8
+ - 0
9
+ version: 0.3.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Jason Murad
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-01-22 00:00:00 -05:00
17
+ date: 2011-01-25 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -101,17 +101,14 @@ files:
101
101
  - README.rdoc
102
102
  - Rakefile
103
103
  - VERSION
104
+ - app/controllers/sortable_nested_set_controller.rb
104
105
  - app/helpers/sortable_nested_set_helper.rb
105
106
  - app/views/sortable_nested_set/_category.html.erb
106
107
  - app/views/sortable_nested_set/_item.html.erb
107
108
  - app/views/sortable_nested_set/_tree.html.erb
108
- - app/views/sortable_nested_set/sns_destroy_category.js.erb
109
- - app/views/sortable_nested_set/sns_destroy_item.js.erb
109
+ - config/routes.rb
110
+ - lib/acts_as_sortable_nested_set.rb
110
111
  - lib/sortable_nested_set.rb
111
- - lib/sortable_nested_set/acts_as_sortable_nested_set.rb
112
- - lib/sortable_nested_set/engine.rb
113
- - lib/sortable_nested_set/handles_sortable_nested_set.rb
114
- - lib/sortable_nested_set/routes.rb
115
112
  - public/images/folder_closed.png
116
113
  - public/images/folder_open.png
117
114
  - public/images/mega_menu.png
@@ -136,7 +133,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
136
133
  requirements:
137
134
  - - ">="
138
135
  - !ruby/object:Gem::Version
139
- hash: 787758848533743446
136
+ hash: 3123587155221195723
140
137
  segments:
141
138
  - 0
142
139
  version: "0"
@@ -1 +0,0 @@
1
- $('#category_<%= @category.id %>').remove();
@@ -1 +0,0 @@
1
- $('#item_<%= @item.id %>').remove();
@@ -1,7 +0,0 @@
1
- module SortableNestedSet
2
- class Engine < Rails::Engine
3
- initializer 'sortable_nested_set.add_middleware' do |app|
4
- app.middleware.use ActionDispatch::Static, "#{root}/public"
5
- end
6
- end
7
- end
@@ -1,74 +0,0 @@
1
- module SortableNestedSet
2
- def self.included(base)
3
- base.extend ClassMethods
4
- end
5
-
6
- module ClassMethods
7
- def handles_sortable_nested_set
8
- class_eval do
9
- define_method(:sns_category_id_field) { "#{controller_name.singularize}_id" }
10
- define_method(:sns_category_class) { controller_name.classify.constantize }
11
- define_method(:sns_items_type) { sns_category_class.sns_items_type }
12
- define_method(:sns_item_class) { sns_items_type.to_s.classify.constantize }
13
- end
14
-
15
- include InstanceMethods
16
- end
17
- end
18
-
19
- module InstanceMethods
20
- def sns_add_subcategory
21
- redirect_to :action => :new, sns_category_id_field => params[:id]
22
- end
23
-
24
- def sns_add_item
25
- redirect_to :controller => sns_items_type, :action => :new, sns_category_id_field => params[:id]
26
- end
27
-
28
- def sns_sort
29
- matches = params[:moved].match(/(\w+)_(\d+)$/)
30
- moved_type = matches[1]
31
- moved_id = matches[2].to_i
32
- moved_parent = nil
33
- tree = {} # category_id => [children of move_type]
34
-
35
- for node in params[:tree].scan(/(\w+)\[(\d+)\]=(\w+)/)
36
- type = node[0]
37
- next unless type == moved_type
38
-
39
- id = node[1].to_i
40
- parent = (node[2] == 'root') ? nil : node[2].to_i
41
-
42
- moved_parent = parent if id == moved_id
43
-
44
- tree[parent] ||= []
45
- tree[parent] << id
46
- end
47
-
48
- if moved_type == sns_items_type.to_s.singularize
49
- item = sns_item_class.find(moved_id)
50
- item.remove_from_list
51
- item.update_attribute(sns_category_id_field, moved_parent)
52
- item.insert_at(tree[moved_parent].index(moved_id))
53
- else
54
- moved_type.classify.constantize.find(moved_id).move(moved_parent, tree[moved_parent])
55
- end
56
-
57
- render :nothing => true
58
- end
59
-
60
- def sns_destroy_category
61
- @category = sns_category_class.find(params[:id])
62
- @category.destroy
63
- render 'sortable_nested_set/sns_destroy_category'
64
- end
65
-
66
- def sns_destroy_item
67
- @item = sns_item_class.find(params[:id])
68
- @item.destroy
69
- render 'sortable_nested_set/sns_destroy_item'
70
- end
71
- end
72
- end
73
-
74
- ActionController::Base.send :include, SortableNestedSet
@@ -1,27 +0,0 @@
1
- module ActionDispatch::Routing
2
- class Mapper
3
- def sortable_nested_set_for(category_type)
4
- item_type = category_type.to_s.classify.constantize.sns_items_type
5
-
6
- resources category_type do
7
- resources category_type, :as => "sub#{category_type}"
8
- resources item_type
9
-
10
- member do
11
- get :sns_toggle
12
- get :sns_add_subcategory
13
- get :sns_add_item
14
- delete :sns_destroy_category
15
- end
16
-
17
- collection do
18
- put :sns_sort
19
- end
20
- end
21
-
22
- resources item_type do
23
- delete :sns_destroy_item, :on => :member, :controller => category_type
24
- end
25
- end
26
- end
27
- end