lolita-menu 0.1.6 → 0.1.7

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.
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