lolita-menu 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/.rspec +1 -0
  2. data/Gemfile +10 -6
  3. data/README.rdoc +1 -1
  4. data/Rakefile +0 -7
  5. data/VERSION +1 -1
  6. data/app/assets/javascripts/lolita/menu/menu-items.js +13 -16
  7. data/app/assets/stylesheets/lolita/menu/application.css +9 -6
  8. data/app/controllers/menu_items_controller.rb +2 -44
  9. data/app/controllers/nested_trees_controller.rb +86 -0
  10. data/app/helpers/lolita/menu_helper.rb +31 -0
  11. data/app/models/menu.rb +15 -120
  12. data/app/models/menu_item.rb +33 -121
  13. data/app/views/components/lolita/menu/nested_tree/_columns.html.haml +2 -0
  14. data/app/views/components/lolita/menu/nested_tree/_columns_body.html.haml +13 -0
  15. data/app/views/components/lolita/menu/nested_tree/_display.html.haml +18 -0
  16. data/app/views/components/lolita/menu/nested_tree/_unscoped_body.html.haml +6 -0
  17. data/app/views/components/lolita/menu/nested_tree/branch_builder/_display.html.haml +5 -0
  18. data/app/views/components/lolita/menu/nested_tree/branch_builder/_fields.html.haml +4 -0
  19. data/app/views/components/lolita/menu/nested_tree/branch_builder/_row.html.haml +12 -0
  20. data/app/views/components/lolita/menu/nested_tree/branch_builder/_subtree.html.haml +2 -0
  21. data/app/views/components/lolita/menu_item/_display.html.haml +10 -0
  22. data/config/locales/en.yml +16 -1
  23. data/config/locales/lv.yml +21 -4
  24. data/config/routes.rb +12 -4
  25. data/lib/generators/lolita/menu/install_generator.rb +10 -6
  26. data/lib/generators/lolita/menu/templates/migrations/create_menu_items.rb +1 -1
  27. data/lib/generators/lolita/menu/templates/migrations/create_menus.rb +2 -0
  28. data/lib/lolita-menu.rb +4 -3
  29. data/lib/lolita-menu/nested_tree.rb +275 -0
  30. data/lib/lolita-menu/nested_tree/branch_builder.rb +70 -0
  31. data/lib/lolita-menu/nested_tree/configuration.rb +87 -0
  32. data/lib/lolita-menu/nested_tree/scope.rb +54 -0
  33. data/lib/lolita-menu/nested_tree/tree_builder.rb +38 -0
  34. data/lib/lolita-menu/rails.rb +17 -0
  35. data/lolita-menu.gemspec +47 -46
  36. data/spec/branch_builder_spec.rb +34 -0
  37. data/spec/models/menu_item_spec.rb +6 -6
  38. data/spec/models/menu_spec.rb +8 -7
  39. data/spec/nested_tree_spec.rb +115 -0
  40. data/spec/spec_helper.rb +10 -11
  41. data/spec/tree_builder_spec.rb +49 -0
  42. data/test_orm/active_record.rb +3 -3
  43. data/test_orm/db/migrate/03_create_categories.rb +25 -0
  44. data/test_orm/db/migrate/04_create_btrees.rb +16 -0
  45. data/test_orm/db/migrate/05_create_shops.rb +8 -0
  46. data/test_orm/rails/app/models/btree.rb +3 -0
  47. data/test_orm/rails/app/models/category.rb +8 -0
  48. data/test_orm/rails/app/models/shop.rb +5 -0
  49. data/test_orm/rails/config/application.rb +14 -2
  50. data/test_orm/rails/config/boot.rb +7 -0
  51. data/test_orm/rails/config/database.yml +3 -0
  52. data/test_orm/rails/config/enviroment.rb +1 -4
  53. metadata +97 -64
  54. data/app/assets/images/lolita/menu/jquery-ui/overcast/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  55. data/app/assets/images/lolita/menu/jquery-ui/overcast/images/ui-bg_flat_0_eeeeee_40x100.png +0 -0
  56. data/app/assets/images/lolita/menu/jquery-ui/overcast/images/ui-bg_flat_55_c0402a_40x100.png +0 -0
  57. data/app/assets/images/lolita/menu/jquery-ui/overcast/images/ui-bg_flat_55_eeeeee_40x100.png +0 -0
  58. data/app/assets/images/lolita/menu/jquery-ui/overcast/images/ui-bg_glass_100_f8f8f8_1x400.png +0 -0
  59. data/app/assets/images/lolita/menu/jquery-ui/overcast/images/ui-bg_glass_35_dddddd_1x400.png +0 -0
  60. data/app/assets/images/lolita/menu/jquery-ui/overcast/images/ui-bg_glass_60_eeeeee_1x400.png +0 -0
  61. data/app/assets/images/lolita/menu/jquery-ui/overcast/images/ui-bg_inset-hard_75_999999_1x100.png +0 -0
  62. data/app/assets/images/lolita/menu/jquery-ui/overcast/images/ui-bg_inset-soft_50_c9c9c9_1x100.png +0 -0
  63. data/app/assets/images/lolita/menu/jquery-ui/overcast/images/ui-icons_3383bb_256x240.png +0 -0
  64. data/app/assets/images/lolita/menu/jquery-ui/overcast/images/ui-icons_454545_256x240.png +0 -0
  65. data/app/assets/images/lolita/menu/jquery-ui/overcast/images/ui-icons_70b2e1_256x240.png +0 -0
  66. data/app/assets/images/lolita/menu/jquery-ui/overcast/images/ui-icons_999999_256x240.png +0 -0
  67. data/app/assets/images/lolita/menu/jquery-ui/overcast/images/ui-icons_fbc856_256x240.png +0 -0
  68. data/app/assets/stylesheets/lolita/menu/jquery-ui/overcast/jquery-ui-1.8.16.custom.css.erb +0 -568
  69. data/app/views/components/lolita/menu/_columns.html.haml +0 -2
  70. data/app/views/components/lolita/menu/_columns_body.html.haml +0 -10
  71. data/app/views/components/lolita/menu/_list.html.haml +0 -11
  72. data/app/views/components/lolita/menu_items/_display.html.haml +0 -7
  73. data/app/views/components/lolita/menu_items/_row.html.haml +0 -17
  74. data/app/views/components/lolita/menu_items/_subtree.html.haml +0 -2
  75. data/lib/lolita-menu/engine.rb +0 -5
  76. data/spec/controllers/menu_items_controller_spec.rb +0 -5
  77. data/test_orm/boot.rb +0 -9
  78. data/test_orm/config/active_record.yml +0 -2
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile CHANGED
@@ -1,14 +1,18 @@
1
1
  source "http://rubygems.org"
2
2
 
3
- gem 'lolita','~>3.2.0.rc.6'
3
+
4
+ if File.exist?(File.expand_path('../lolita'))
5
+ gem 'lolita', :path=>File.expand_path('../../lolita',__FILE__)
6
+ else
7
+ gem 'lolita','~>3.2.0.rc.9'
8
+ end
4
9
 
5
10
  group :development, :test do
6
- gem 'rspec', '~>2.6.0'
11
+ gem "rails", "~>3.2.0"
12
+ gem 'rspec', '~>2.9.0'
7
13
  gem "sqlite3"
8
- gem 'rspec-rails', '~>2.6.0'
14
+ gem 'rspec-rails', '~>2.9.0'
9
15
  gem 'haml-rails'
10
- gem "shoulda", ">= 0"
11
- gem "bundler", "~> 1.0.0"
12
16
  gem "jeweler", "~> 1.6.0"
13
- gem "rcov", ">= 0"
17
+ gem "database_cleaner", "~>0.6.7"
14
18
  end
data/README.rdoc CHANGED
@@ -7,7 +7,7 @@ In your project Gemfile put
7
7
  And run
8
8
  bundle install
9
9
  Like with other Lolita gems call
10
- rails g lolita_menu:install
10
+ rails g lolita:menu:install
11
11
  Since this gem comes with migrations
12
12
  rake db:migrate
13
13
  === Using autocomplete
data/Rakefile CHANGED
@@ -33,13 +33,6 @@ Rake::TestTask.new(:test) do |test|
33
33
  test.verbose = true
34
34
  end
35
35
 
36
- require 'rcov/rcovtask'
37
- Rcov::RcovTask.new do |test|
38
- test.libs << 'test'
39
- test.pattern = 'test/**/test_*.rb'
40
- test.verbose = true
41
- end
42
-
43
36
  task :default => :test
44
37
 
45
38
  require 'rake/rdoctask'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.6
1
+ 0.1.7
@@ -15,7 +15,7 @@ $(document).ready(function(){
15
15
  }
16
16
  }
17
17
 
18
- $("ol.menu-items-tree").nestedSortable({
18
+ $("ol.nested-tree-items-tree").nestedSortable({
19
19
  disableNesting: 'no-nest',
20
20
  forcePlaceholderSize: true,
21
21
  handle: 'div',
@@ -33,23 +33,23 @@ $(document).ready(function(){
33
33
  }
34
34
  })
35
35
 
36
- $("ol.menu-items-tree").each(function(){
36
+ $("ol.nested-tree-items-tree").each(function(){
37
37
  $(this).data("old_positions",$(this).nestedSortable("serialize"))
38
38
  })
39
39
 
40
40
  $(".openable-row").click(function(event){
41
41
  var that=this
42
42
  $(".subrow").hide(0)
43
- $("#menu_items_"+$(this).attr("data-id")).show(0);
43
+ $("#branch_"+$(this).attr("data-id")).show(0);
44
44
 
45
45
  //event.preventDefault();
46
46
  })
47
47
 
48
- $(".add_new_menu_item").click(function(){
48
+ $(".add_new_nested_tree_item").click(function(){
49
49
  $.ajax({
50
50
  url:$(this).attr("data-url"),
51
51
  type:"post",
52
- context: $("#menu_tree_"+$(this).attr("data-id")),
52
+ context: $("#nested_tree_"+$(this).attr("data-id")),
53
53
  dataType:"html",
54
54
  success:function(html_data){
55
55
  $(this).append(html_data)
@@ -57,7 +57,7 @@ $(document).ready(function(){
57
57
  })
58
58
  })
59
59
 
60
- $(".delete-menu-item").live("click",function(){
60
+ $(".delete-nested-tree-item").live("click",function(){
61
61
  var self = this;
62
62
  $.ajax({
63
63
  url:$(this).attr("data-url"),
@@ -65,29 +65,26 @@ $(document).ready(function(){
65
65
  dataType: "json",
66
66
  success:function(data){
67
67
  $($(self).attr("data-row")).remove();
68
- save_menu_tree($($(self).attr("data-menu")));
68
+ save_menu_tree($($(self).attr("data-scope")));
69
69
  }
70
70
  })
71
71
  })
72
72
 
73
- $(".save_menu_tree").click(function(){
74
- save_menu_tree($(this).attr("data-id"))
75
- })
76
-
77
- $(".menu-tree-content input").live("focus",function(){
73
+ $(".nested-tree-content input").live("focus",function(){
78
74
  $(this).data("value",$(this).val())
79
75
  })
80
76
 
81
- $(".menu-tree-content input").live("blur",function(){
77
+ $(".nested-tree-content input").live("blur",function(){
82
78
  var input=$(this);
83
79
  if(input.data("value")!=input.val()){
80
+ var match = input.attr("name").match(/\[(\w+)\]$/);
84
81
  input.data("value",input.val())
85
82
  $.ajax({
86
- url:input.attr("data-url"),
83
+ url: input.closest("form").attr("action"),
87
84
  type:"put",
88
85
  context:$(this),
89
86
  dataType:"json",
90
- data:{attribute:input.attr("name"),value:input.val()},
87
+ data:{attribute: match[1], value: input.val()},
91
88
  success:function(data){
92
89
  var color=(data.status=="error" ? "#ff5656" : "#aaff56");
93
90
  $(this).css("backgroundColor",color);
@@ -96,4 +93,4 @@ $(document).ready(function(){
96
93
  })
97
94
  }
98
95
  })
99
- })
96
+ })
@@ -1,13 +1,16 @@
1
- /*
2
- *=require_directory ./jquery-ui
3
- */
4
- ol.menu-items-tree li{
1
+ ol.nested-tree-items-tree li{
5
2
  list-style:none;
6
3
  width:390px;
7
4
  }
8
- div.menu-tree-content{
5
+ div.nested-tree-content{
9
6
  width:500px;
10
7
  }
8
+ #main div.nested-tree-content form {
9
+ background: none;
10
+ float: left;
11
+ padding: 0;
12
+ margin-right: 10px;
13
+ }
11
14
  li.placeholder{
12
15
  background-color:white;
13
16
  }
@@ -16,4 +19,4 @@ input.url-input{
16
19
  }
17
20
  .list table tbody tr.subrow:hover{
18
21
  background:none !important;
19
- }
22
+ }
@@ -1,53 +1,11 @@
1
1
  # encoding: utf-8
2
- class MenuItemsController < ActionController::Base
3
- include Lolita::Controllers::UserHelpers
4
- include Lolita::Controllers::InternalHelpers
2
+ class MenuItemsController < NestedTreesController
5
3
 
6
4
  before_filter :authenticate_lolita_user!
7
5
 
8
6
  def autocomplete_menu_item_url
7
+ authorization_proxy.authorize!(:read, Menu)
9
8
  urls = Lolita::Menu::Autocomplete::Collector.new(params[:term])
10
9
  render :json => urls.to_json
11
10
  end
12
-
13
- def create
14
- menu=Menu.find_by_id(params[:menu_id])
15
- item=MenuItem.create!(:name=>"new item",:url=>"/",:menu_id => params[:menu_id])
16
- menu.append(item)
17
- notice(I18n.t("lolita.menu.branch created"))
18
- render_component "lolita/menu_items", :row, :item => item, :menu => menu
19
- end
20
-
21
- def update
22
- if item=MenuItem.find_by_id(params[:id])
23
- item.send(:"#{params[:attribute]}=",params[:value])
24
- item.save
25
- render :json=>{:status=>item.errors.any? ? "error" : "saved"}
26
- else
27
- render :json=>{:status=>"error"}
28
- end
29
- end
30
-
31
- def update_tree
32
- menu=Menu.find_by_id(params[:menu_id])
33
-
34
- if menu && menu.update_whole_tree(params[:items])
35
- notice I18n.t("lolita.menu.notice")
36
- else
37
- error I18n.t("lolita.menu.error")
38
- end
39
-
40
- render :nothing=>true
41
- end
42
-
43
- def destroy
44
- item=MenuItem.find_by_id(params[:id])
45
- item.destroy
46
- notice I18n.t("lolita.menu.branch deleted")
47
- render :json=>{:id=>item.id}
48
- end
49
-
50
- def is_lolita_resource?
51
- true
52
- end
53
11
  end
@@ -0,0 +1,86 @@
1
+ class NestedTreesController < Lolita::RestController
2
+ include Lolita::ControllerAdditions
3
+
4
+ before_filter :authenticate_lolita_user!
5
+
6
+ def index
7
+ super
8
+ end
9
+
10
+ def create
11
+ authorization_proxy.authorize!(:create, tree_class)
12
+ item = tree_class.build_empty_branch(attributes.merge(scopes))
13
+ item.save!
14
+ item.reload
15
+ notice(I18n.t("lolita.nested_tree.branch created", :name => tree_class.model_name.human))
16
+ render_component "lolita/menu/nested_tree/branch_builder", :row, :item => item, :scope => scope
17
+ end
18
+
19
+ def update
20
+ authorization_proxy.authorize!(:update,tree_class)
21
+ if params[:attribute].present? && item = tree_class.find_by_id(params[:id])
22
+ item.send(:"#{params[:attribute]}=",params[:value])
23
+ item.save
24
+ render :json=>{:status=>item.errors.any? ? "error" : "saved"}
25
+ else
26
+ render :json=>{:status=>"error"}
27
+ end
28
+ end
29
+
30
+ def update_tree
31
+ authorization_proxy.authorize!(:update,tree_class)
32
+ if tree_class.update_whole_tree(params[:items], scopes)
33
+ notice I18n.t("lolita.nested_tree.notice", :name => tree_class.model_name.human)
34
+ else
35
+ error I18n.t("lolita.nested_tree.error", :name => tree_class.model_name.human)
36
+ end
37
+
38
+ render :nothing=>true
39
+ end
40
+
41
+ def destroy
42
+ authorization_proxy.authorize!(:destroy,tree_class)
43
+ item = tree_class.find_by_id(params[:id])
44
+ item.destroy
45
+ notice I18n.t("lolita.nested_tree.branch deleted", :name => tree_class.model_name.human)
46
+ render :json=>{:id=>item.id}
47
+ end
48
+
49
+ def lolita_mapping
50
+ @lolita_mapping ||= Lolita.mappings[resource_class.to_s.underscore.to_sym]
51
+ end
52
+
53
+ def resource_name
54
+ "nested_tree"
55
+ end
56
+
57
+ def resource_class
58
+ tree_class
59
+ end
60
+
61
+ private
62
+
63
+ # URL:
64
+ # /nested_trees?tree_class=MenuItem
65
+ def tree_class
66
+ @tree_class ||= params[:tree_class].constantize
67
+ end
68
+
69
+ def scopes
70
+ @scopes ||= tree_class.lolita_nested_tree.scope_keys.inject({}) do |result, key|
71
+ result[key] = params[key]
72
+ result
73
+ end
74
+ end
75
+
76
+ def scope
77
+ tree_class.lolita_nested_tree.scope_classes.first && tree_class.lolita_nested_tree.scope_classes.first.find_by_id(scopes.values.first)
78
+ end
79
+
80
+ def attributes
81
+ @attributes ||= tree_class.lolita.tabs.first.fields.inject({}) do |result, field|
82
+ result[field.name.to_sym] = params[field.name.to_sym]
83
+ result
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,31 @@
1
+ module Lolita
2
+ module MenuHelper
3
+ def lolita_menu_data_attributes_for_branch(scope)
4
+ if scope
5
+ key = self.resource_class.lolita_nested_tree.scope_key_for(scope.class)
6
+ {:"data-id" => scope.id, :"data-url" => nested_trees_path(key.to_sym => scope.id, :tree_class => resource_class.to_s)}
7
+ else
8
+ {:"data-id" => "", :"data-url" => nested_trees_path(:tree_class => resource_class.to_s)}
9
+ end
10
+ end
11
+
12
+ def lolita_menu_data_attributes_for_tree(scope)
13
+ if scope
14
+ key = self.resource_class.lolita_nested_tree.scope_key_for(scope.class)
15
+ {:id => "nested_tree_#{scope.id}", :"data-url" => update_tree_nested_trees_path(key.to_sym => scope.id, :tree_class => resource_class.to_s)}
16
+ else
17
+ {:id => "nested_tree_", :"data-url" => update_tree_nested_trees_path(:tree_class => resource_class.to_s)}
18
+ end
19
+ end
20
+
21
+ def lolita_menu_data_attributes_for_branch_delete(scope, item)
22
+ default = {:"data-url" => nested_tree_path(item.id, :tree_class => resource_class.to_s), :"data-row" => "#item-#{item.id}"}
23
+ if scope
24
+ key = self.resource_class.lolita_nested_tree.scope_key_for(scope.class)
25
+ default.merge({:"data-scope" => "#nested_tree_#{scope.id}"})
26
+ else
27
+ default.merge({:"data-scope" => "#nested_tree_"})
28
+ end
29
+ end
30
+ end
31
+ end
data/app/models/menu.rb CHANGED
@@ -1,140 +1,35 @@
1
1
  class Menu < ActiveRecord::Base
2
- set_table_name "lolita_menus"
3
2
 
4
3
  has_many :items, :class_name => "MenuItem", :dependent => :destroy
5
4
 
6
5
  validates :name, :presence => true
7
6
 
8
- after_create :create_root, :unless=>:have_root?
9
-
10
7
  include Lolita::Configuration
11
8
 
12
9
  lolita do
13
10
  list do
14
11
  column :name
15
- builder :name=>"/lolita/menu",:state=>"list", :if=>{:state=>:display}
16
- end
17
- tab(:content) do
18
- field :name
19
- end
20
- end
21
-
22
- POSITION_ATTRIBUTES = {:left => :lft,:right => :rgt,:depth => :depth,:parent_id => :parent_id}
23
- ROOT = "root"
24
- NONE = "none"
25
-
26
- def position_attributes
27
- POSITION_ATTRIBUTES
28
- end
29
-
30
- def root
31
- if item=self.items.first
32
- item.root
33
- end
34
- end
35
-
36
- def children
37
- self.root.children
38
- end
39
-
40
- def append(item)
41
- unless item.menu_id == self.id
42
- item.menu_id = self.id
43
- item.save!
44
- end
45
- self.root.append(item)
46
- item.reload
47
- item
48
- end
49
-
50
- def have_root?
51
- !!self.root
52
- end
53
-
54
- def update_whole_tree(items)
55
- begin
56
- self.class.transaction do
57
- update_all_items(items)
58
- true
12
+ column :system_name
13
+ action :edit do
14
+ title ::I18n.t("lolita.shared.edit")
15
+ url Proc.new{|view,record| view.send(:edit_lolita_resource_path, Lolita.mappings[:menu], :id => record.id)}
59
16
  end
60
- end
61
- end
62
-
63
- protected
64
-
65
-
66
- def update_all_items(items)
67
- items_ids=items_with_acumulated_ids(items) do |item|
68
- update_item(item)
69
- end
70
- remove_deleted_items(items_ids)
71
- end
72
17
 
73
- def items_with_acumulated_ids(items)
74
- item_ids=[]
75
- items.each do |key,item|
76
- item_ids << item[:item_id]
77
- yield item
78
- end
79
- return item_ids
80
- end
81
-
82
- def update_item(item)
83
- if is_root?(item)
84
- update_root(item)
85
- else
86
- update_branch(item)
87
- end
88
- end
89
-
90
- def is_root?(item)
91
- item[:item_id]==ROOT
92
- end
93
-
94
- def update_root(item)
95
- MenuItem.update_all(update_values_for(item),"id=#{root.id}")
96
- end
97
-
98
- def update_branch(item)
99
- MenuItem.update_all(update_values_for(item),"id=#{item[:item_id].to_i}")
100
- end
101
-
102
- def update_values_for(item)
103
- values=[]
104
- position_attributes.each do |attr_name,field|
105
- value = value_for_attribute(attr_name,item)
106
- values<<"#{field}=#{value}"
18
+ action :destroy do
19
+ title ::I18n.t("lolita.shared.delete")
20
+ url Proc.new{|view,record| view.send(:lolita_resource_path,Lolita.mappings[:menu],:id => record.id)}
21
+ html :method => :delete, :confirm => ::I18n.t("lolita.list.confirm")
22
+ end
107
23
  end
108
- values.join(", ")
109
- end
110
-
111
- def value_for_attribute(attr_name,item)
112
- if item[attr_name]==NONE || !item[attr_name]
113
- "NULL"
114
- elsif item[attr_name]==ROOT
115
- root.id
116
- else
117
- item[attr_name].to_i
24
+ tab(:content) do
25
+ field :name
26
+ field :system_name, :on => :create
118
27
  end
119
28
  end
120
29
 
121
- def remove_deleted_items(ids)
122
- deleted_ids=deleted_items_ids(ids)
123
- if deleted_ids.any?
124
- MenuItem.delete_all("id IN (#{deleted_ids.join(",")})")
30
+ class << self
31
+ def table_name
32
+ "lolita_menus"
125
33
  end
126
34
  end
127
-
128
- def deleted_items_ids(ids)
129
- ids = ids.map{|id| id=="root" ? root.id : id.to_i}
130
- all_ids = MenuItem.where(:menu_id=>self.id).map{|item| item.id}
131
- all_ids - ids
132
- end
133
-
134
- private
135
-
136
- def create_root
137
- MenuItem.create_root!(self)
138
- end
139
-
140
35
  end