lolita-menu 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +15 -0
- data/History.rdoc +24 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +17 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/app/controllers/menu_items_controller.rb +41 -0
- data/app/models/menu.rb +139 -0
- data/app/models/menu_item.rb +130 -0
- data/app/views/components/lolita/menu/_columns.html.haml +2 -0
- data/app/views/components/lolita/menu/_columns_body.html.haml +11 -0
- data/app/views/components/lolita/menu/_list.html.haml +11 -0
- data/app/views/components/lolita/menu_items/_display.html.haml +7 -0
- data/app/views/components/lolita/menu_items/_row.html.haml +10 -0
- data/app/views/components/lolita/menu_items/_subtree.html.haml +2 -0
- data/config/locales/en.yml +5 -0
- data/config/locales/lv.yml +5 -0
- data/config/routes.rb +8 -0
- data/lib/generators/lolita_menu/assets_generator.rb +13 -0
- data/lib/generators/lolita_menu/install_generator.rb +19 -0
- data/lib/generators/lolita_menu/templates/migrations/create_menu_items.rb +27 -0
- data/lib/generators/lolita_menu/templates/migrations/create_menus.rb +14 -0
- data/lib/lolita-menu.rb +13 -0
- data/lib/lolita-menu/module.rb +1 -0
- data/lib/lolita-menu/rails.rb +5 -0
- data/lolita-menu.gemspec +113 -0
- data/public/javascripts/jquery-ui-nested-sortables.js +356 -0
- data/public/javascripts/lolita/menu-items.js +86 -0
- data/public/stylesheets/lolita/menu/style.css +16 -0
- data/spec/controllers/menu_items_controller_spec.rb +5 -0
- data/spec/models/menu_item_spec.rb +47 -0
- data/spec/models/menu_spec.rb +79 -0
- data/spec/spec_helper.rb +22 -0
- data/test_orm/active_record.rb +9 -0
- data/test_orm/boot.rb +9 -0
- data/test_orm/config/active_record.yml +2 -0
- data/test_orm/db/migrate/01_create_lolita_menus.rb +14 -0
- data/test_orm/db/migrate/02_create_lolita_menu_items.rb +27 -0
- data/test_orm/rails/config/application.rb +8 -0
- data/test_orm/rails/config/enviroment.rb +5 -0
- metadata +213 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem 'lolita','~>3.1.6'
|
4
|
+
gem 'haml', :require=>true
|
5
|
+
|
6
|
+
group :development, :test do
|
7
|
+
gem 'rspec', '~>2.6.0'
|
8
|
+
gem "sqlite3"
|
9
|
+
gem 'rspec-rails', '~>2.6.0'
|
10
|
+
gem 'haml-rails'
|
11
|
+
gem "shoulda", ">= 0"
|
12
|
+
gem "bundler", "~> 1.0.0"
|
13
|
+
gem "jeweler", "~> 1.5.2"
|
14
|
+
gem "rcov", ">= 0"
|
15
|
+
end
|
data/History.rdoc
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
=== Version 0.0.6 / 2011-05-19
|
2
|
+
* Bug fixes
|
3
|
+
* Can't recognize HAML files in projects without haml.
|
4
|
+
|
5
|
+
=== Version 0.0.5 / 2011-05-19
|
6
|
+
* Bug fixes
|
7
|
+
* HAML dependencies not supported
|
8
|
+
|
9
|
+
=== Version 0.0.4 / 2011-05-19
|
10
|
+
* Bug fixes
|
11
|
+
* Wrong table names for models
|
12
|
+
|
13
|
+
=== Version 0.0.3 / 2011-05-19
|
14
|
+
* Enhancements
|
15
|
+
* README updated
|
16
|
+
|
17
|
+
=== Version 0.0.2 / 2011-05-19
|
18
|
+
* Bug fixes
|
19
|
+
* migrations have one timestamp
|
20
|
+
* migration names does not match class names
|
21
|
+
|
22
|
+
=== Version 0.0.1 / 2011-05-19
|
23
|
+
* Basic models, controllers, views
|
24
|
+
* JavaScripts, Style, Migrations
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 ITHouse, Arturs Meisters
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
= Lolita Menu
|
2
|
+
Create, sort and publish menus with Lolita.
|
3
|
+
|
4
|
+
==Instalation
|
5
|
+
In your project Gemfile put
|
6
|
+
gem 'lolita-menu'
|
7
|
+
And run
|
8
|
+
bundle install
|
9
|
+
Like with other Lolita gems call
|
10
|
+
rails g lolita_menu:install
|
11
|
+
Since this gem comes with migrations
|
12
|
+
rake db:migrate
|
13
|
+
|
14
|
+
Enjoy!
|
15
|
+
|
16
|
+
==Copyright
|
17
|
+
Copyright © 2011 ITHouse and Arturs Meisters. See LICENSE.txt for further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "lolita-menu"
|
16
|
+
gem.homepage = "http://github.com/ithouse/lolita-menu"
|
17
|
+
gem.license = "MIT"
|
18
|
+
gem.summary = %Q{Menu managing plugin for Lolita.}
|
19
|
+
gem.description = %Q{Manage public menus for each project inside Lolita.}
|
20
|
+
gem.email = "support@ithouse.lv"
|
21
|
+
gem.authors = ["ITHouse","Arturs Meisters"]
|
22
|
+
# Include your dependencies below. Runtime dependencies are required when using your gem,
|
23
|
+
# and development dependencies are only needed for development (ie running rake tasks, tests, etc)
|
24
|
+
# gem.add_runtime_dependency 'jabber4r', '> 0.1'
|
25
|
+
# gem.add_development_dependency 'rspec', '> 1.2.3'
|
26
|
+
end
|
27
|
+
Jeweler::RubygemsDotOrgTasks.new
|
28
|
+
|
29
|
+
require 'rake/testtask'
|
30
|
+
Rake::TestTask.new(:test) do |test|
|
31
|
+
test.libs << 'lib' << 'test'
|
32
|
+
test.pattern = 'test/**/test_*.rb'
|
33
|
+
test.verbose = true
|
34
|
+
end
|
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
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "lolita-menu #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.6
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
class MenuItemsController < ActionController::Base
|
3
|
+
include Lolita::Controllers::UserHelpers
|
4
|
+
|
5
|
+
before_filter :authenticate_lolita_user!
|
6
|
+
|
7
|
+
def create
|
8
|
+
menu=Menu.find_by_id(params[:menu_id])
|
9
|
+
item=MenuItem.create!(:name=>"new item",:url=>"/",:menu_id=>params[:menu_id])
|
10
|
+
menu.append(item)
|
11
|
+
render :partial=>"row", :locals=>{:item=>item}
|
12
|
+
end
|
13
|
+
|
14
|
+
def update
|
15
|
+
if item=MenuItem.find_by_id(params[:id])
|
16
|
+
item.send(:"#{params[:attribute]}=",params[:value])
|
17
|
+
item.save
|
18
|
+
render :json=>{:status=>item.errors.any? ? "error" : "saved"}
|
19
|
+
else
|
20
|
+
render :json=>{:status=>"error"}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def update_tree
|
25
|
+
menu=Menu.find_by_id(params[:menu_id])
|
26
|
+
|
27
|
+
if menu && menu.update_whole_tree(params[:items])
|
28
|
+
response.headers["Lolita-Notice"] = I18n.t("lolita.menu.notice")
|
29
|
+
else
|
30
|
+
response.headers["Lolita-Error"] = I18n.t("lolita.menu.error")
|
31
|
+
end
|
32
|
+
|
33
|
+
render :nothing=>true
|
34
|
+
end
|
35
|
+
|
36
|
+
def destroy
|
37
|
+
item=MenuItem.find_by_id(params[:id])
|
38
|
+
item.destroy
|
39
|
+
render :json=>{:id=>item.id}
|
40
|
+
end
|
41
|
+
end
|
data/app/models/menu.rb
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
class Menu < ActiveRecord::Base
|
2
|
+
set_table_name "lolita_menus"
|
3
|
+
|
4
|
+
has_many :items, :class_name => "MenuItem", :dependent => :destroy
|
5
|
+
|
6
|
+
validates :name, :presence => true
|
7
|
+
|
8
|
+
after_create :create_root, :unless=>:have_root?
|
9
|
+
|
10
|
+
include Lolita::Configuration
|
11
|
+
|
12
|
+
lolita do
|
13
|
+
list do
|
14
|
+
column :name
|
15
|
+
builder :name=>"lolita/menu",:state=>"list"
|
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
|
+
end
|
48
|
+
|
49
|
+
def have_root?
|
50
|
+
!!self.root
|
51
|
+
end
|
52
|
+
|
53
|
+
def update_whole_tree(items)
|
54
|
+
begin
|
55
|
+
self.class.transaction do
|
56
|
+
update_all_items(items)
|
57
|
+
true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
protected
|
63
|
+
|
64
|
+
|
65
|
+
def update_all_items(items)
|
66
|
+
items_ids=items_with_acumulated_ids(items) do |item|
|
67
|
+
update_item(item)
|
68
|
+
end
|
69
|
+
remove_deleted_items(items_ids)
|
70
|
+
end
|
71
|
+
|
72
|
+
def items_with_acumulated_ids(items)
|
73
|
+
item_ids=[]
|
74
|
+
items.each do |key,item|
|
75
|
+
item_ids << item[:item_id]
|
76
|
+
yield item
|
77
|
+
end
|
78
|
+
return item_ids
|
79
|
+
end
|
80
|
+
|
81
|
+
def update_item(item)
|
82
|
+
if is_root?(item)
|
83
|
+
update_root(item)
|
84
|
+
else
|
85
|
+
update_branch(item)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def is_root?(item)
|
90
|
+
item[:item_id]==ROOT
|
91
|
+
end
|
92
|
+
|
93
|
+
def update_root(item)
|
94
|
+
MenuItem.update_all(update_values_for(item),"id=#{root.id}")
|
95
|
+
end
|
96
|
+
|
97
|
+
def update_branch(item)
|
98
|
+
MenuItem.update_all(update_values_for(item),"id=#{item[:item_id].to_i}")
|
99
|
+
end
|
100
|
+
|
101
|
+
def update_values_for(item)
|
102
|
+
values=[]
|
103
|
+
position_attributes.each do |attr_name,field|
|
104
|
+
value = value_for_attribute(attr_name,item)
|
105
|
+
values<<"#{field}=#{value}"
|
106
|
+
end
|
107
|
+
values.join(", ")
|
108
|
+
end
|
109
|
+
|
110
|
+
def value_for_attribute(attr_name,item)
|
111
|
+
if item[attr_name]==NONE || !item[attr_name]
|
112
|
+
"NULL"
|
113
|
+
elsif item[attr_name]==ROOT
|
114
|
+
root.id
|
115
|
+
else
|
116
|
+
item[attr_name].to_i
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def remove_deleted_items(ids)
|
121
|
+
deleted_ids=deleted_items_ids(ids)
|
122
|
+
if deleted_ids.any?
|
123
|
+
MenuItem.delete_all("id IN (#{deleted_ids.join(",")})")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def deleted_items_ids(ids)
|
128
|
+
ids = ids.map{|id| id=="root" ? root.id : id.to_i}
|
129
|
+
all_ids = MenuItem.where(:menu_id=>self.id).map{|item| item.id}
|
130
|
+
all_ids - ids
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def create_root
|
136
|
+
MenuItem.create_root!(self)
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
class MenuItem < ActiveRecord::Base
|
2
|
+
set_table_name "lolita_menu_items"
|
3
|
+
|
4
|
+
attr_accessor :place
|
5
|
+
|
6
|
+
belongs_to :menu, :class_name => "Menu"
|
7
|
+
|
8
|
+
validates :name,:presence => true
|
9
|
+
validates :url, :format => {:with => /^\/.*/}, :unless=>:root?
|
10
|
+
|
11
|
+
before_create :set_default_positions
|
12
|
+
after_create :put_in_place
|
13
|
+
before_validation :set_default_values, :if=>:new_record?
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def create_root!(menu)
|
17
|
+
new_item = self.create!({:menu_id => menu.id}.merge(default_root_position))
|
18
|
+
menu.items << new_item
|
19
|
+
end
|
20
|
+
|
21
|
+
def default_root_position
|
22
|
+
{
|
23
|
+
:lft=>1,
|
24
|
+
:rgt=>2,
|
25
|
+
:depth=>0,
|
26
|
+
:parent_id=>nil
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
# instance methods
|
31
|
+
|
32
|
+
def visible?
|
33
|
+
self.is_visible
|
34
|
+
end
|
35
|
+
|
36
|
+
def root?
|
37
|
+
self.parent_id.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
def parent
|
41
|
+
@parent||=self.class.find_by_id(self.parent_id)
|
42
|
+
@parent
|
43
|
+
end
|
44
|
+
|
45
|
+
def parent=(parent_item)
|
46
|
+
@parent=parent_item
|
47
|
+
end
|
48
|
+
|
49
|
+
def children
|
50
|
+
@children||=self.class.where("lft>:left AND rgt<:right AND depth=:depth AND menu_id=:menu",{
|
51
|
+
:left => self.lft,:right => self.rgt,:depth => self.depth+1, :menu=>self.menu_id
|
52
|
+
}).order("lft asc")
|
53
|
+
@children
|
54
|
+
end
|
55
|
+
|
56
|
+
def root
|
57
|
+
if self.parent_id.nil?
|
58
|
+
self
|
59
|
+
else
|
60
|
+
self.class.where(:menu_id=>self.menu_id,:parent_id=>nil).first
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def append(item)
|
65
|
+
append_item(item)
|
66
|
+
recalculate_positions_after(:append)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def append_item(item)
|
72
|
+
position=position_for_append
|
73
|
+
self.class.update_all(positions_to_update_string(position),"id=#{item.id}")
|
74
|
+
end
|
75
|
+
|
76
|
+
def recalculate_positions_after(action)
|
77
|
+
if action==:append
|
78
|
+
self.class.update_all("rgt=#{self.rgt+2}","id=#{self.id}")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def positions_to_update_string(positions)
|
83
|
+
result=[]
|
84
|
+
positions.each do |field,value|
|
85
|
+
result<<"#{field}=#{value}"
|
86
|
+
end
|
87
|
+
result.join(", ")
|
88
|
+
end
|
89
|
+
|
90
|
+
def position_for_append
|
91
|
+
{
|
92
|
+
:lft => self.rgt,
|
93
|
+
:rgt => self.rgt+1,
|
94
|
+
:depth => self.depth+1,
|
95
|
+
:parent_id => self.id
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
def set_default_positions
|
100
|
+
if am_i_new_root? || !menu_id
|
101
|
+
set_root_position
|
102
|
+
else
|
103
|
+
self.place=:append
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def am_i_new_root?
|
108
|
+
self.menu_id && Menu.exists?(menu_id) && !MenuItem.where(:menu_id=>menu_id).first
|
109
|
+
end
|
110
|
+
|
111
|
+
def set_root_position
|
112
|
+
self.class.default_root_position.each do |method,value|
|
113
|
+
unless self.send(method)
|
114
|
+
self.send(:"#{method}=",value)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def put_in_place
|
120
|
+
if place==:append
|
121
|
+
self.menu.root.append(self)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def set_default_values
|
126
|
+
self.name||="root"
|
127
|
+
self.url||="/"
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|