taxis 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/Gemfile +5 -0
- data/LICENSE +20 -0
- data/README.md +42 -0
- data/Rakefile +2 -0
- data/app/controllers/admin/base_controller.rb +25 -0
- data/app/controllers/admin/taxonomies_controller.rb +58 -0
- data/app/controllers/admin/taxons_controller.rb +94 -0
- data/app/controllers/application_controller.rb +3 -0
- data/app/models/taxon.rb +62 -0
- data/app/models/taxonomy.rb +24 -0
- data/app/views/admin/taxonomies/_form.html.erb +4 -0
- data/app/views/admin/taxonomies/_js_head.html.erb +9 -0
- data/app/views/admin/taxonomies/_list.html.erb +20 -0
- data/app/views/admin/taxonomies/edit.erb +29 -0
- data/app/views/admin/taxonomies/index.html.erb +7 -0
- data/app/views/admin/taxonomies/new.html.erb +11 -0
- data/app/views/admin/taxons/_form.html.erb +5 -0
- data/app/views/admin/taxons/_taxon_table.html.erb +23 -0
- data/app/views/admin/taxons/edit.html.erb +10 -0
- data/app/views/layouts/admin.html.erb +30 -0
- data/config/routes.rb +16 -0
- data/lib/generators/taxis/install_generator.rb +67 -0
- data/lib/generators/taxis/migration_generator.rb +28 -0
- data/lib/generators/taxis/public/jsTree/jquery.jstree.js +3510 -0
- data/lib/generators/taxis/public/jsTree/themes/apple/bg.jpg +0 -0
- data/lib/generators/taxis/public/jsTree/themes/apple/d.png +0 -0
- data/lib/generators/taxis/public/jsTree/themes/apple/dot_for_ie.gif +0 -0
- data/lib/generators/taxis/public/jsTree/themes/apple/style.css +60 -0
- data/lib/generators/taxis/public/jsTree/themes/apple/throbber.gif +0 -0
- data/lib/generators/taxis/public/taxonomy.js +203 -0
- data/lib/generators/taxis/templates/create_taxonomies.rb +13 -0
- data/lib/generators/taxis/templates/create_taxons.rb +18 -0
- data/lib/taxis.rb +3 -0
- data/lib/taxis/engine.rb +10 -0
- data/lib/taxis/version.rb +3 -0
- data/taxis.gemspec +25 -0
- metadata +114 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (C) 2011 by End Point Corporation
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
20
|
+
|
data/README.md
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# Taxis
|
2
|
+
Taxis is a simple Rails 3 plugin that will give you a taxonomy structure for your rails application. It was written with the intent of providing a category tree for e-commerce solutions. It is in early development right now so please feel free to submit issues and provide any feedback.
|
3
|
+
|
4
|
+
# Installation
|
5
|
+
|
6
|
+
gem install taxis
|
7
|
+
|
8
|
+
rails g taxis:install
|
9
|
+
|
10
|
+
# Dependencies
|
11
|
+
Taxis provides a very simple interface for administrating the taxonomy. This interface uses the jsTree javascript library, which is a plugin for jQuery. As such, the taxis:install generator installs the jquery-rails gem which removes the prototype framework from your application. If this is not desired, use the --skip-jquery option when you run the generator. The gem also depends on:
|
12
|
+
|
13
|
+
* stringex
|
14
|
+
* nested_set
|
15
|
+
|
16
|
+
# License
|
17
|
+
|
18
|
+
Copyright (C) 2011 by End Point Corporation
|
19
|
+
|
20
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
21
|
+
of this software and associated documentation files (the "Software"), to deal
|
22
|
+
in the Software without restriction, including without limitation the rights
|
23
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
24
|
+
copies of the Software, and to permit persons to whom the Software is
|
25
|
+
furnished to do so, subject to the following conditions:
|
26
|
+
|
27
|
+
The above copyright notice and this permission notice shall be included in
|
28
|
+
all copies or substantial portions of the Software.
|
29
|
+
|
30
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
31
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
32
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
33
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
34
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
35
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
36
|
+
THE SOFTWARE.
|
37
|
+
|
38
|
+
|
39
|
+
# Contributing
|
40
|
+
Fork, modify, send me a pull request
|
41
|
+
|
42
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
class Admin::BaseController < ApplicationController
|
2
|
+
layout 'admin'
|
3
|
+
|
4
|
+
# For the gem
|
5
|
+
unloadable
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
|
12
|
+
def tree_children(taxon)
|
13
|
+
children = []
|
14
|
+
taxon.children.each do |taxon|
|
15
|
+
children << {
|
16
|
+
:attr => {:id => taxon.id.to_s},
|
17
|
+
:data => taxon.name,
|
18
|
+
:state => taxon.children.empty? ? "" : "closed"
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
return children
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
class Admin::TaxonomiesController < Admin::BaseController
|
2
|
+
|
3
|
+
|
4
|
+
def index
|
5
|
+
@taxonomies = Taxonomy.all
|
6
|
+
end
|
7
|
+
|
8
|
+
def show
|
9
|
+
@taxonomy = Taxonomy.find(params[:id])
|
10
|
+
end
|
11
|
+
|
12
|
+
def new
|
13
|
+
@taxonomy = Taxonomy.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def create
|
17
|
+
@taxonomy = Taxonomy.new(params[:taxonomy])
|
18
|
+
if @taxonomy.save
|
19
|
+
redirect_to edit_admin_taxonomy_url(@taxonomy), :notice => "Successfully created taxonomy."
|
20
|
+
else
|
21
|
+
render :action => 'new'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def edit
|
26
|
+
@taxonomy = Taxonomy.find(params[:id])
|
27
|
+
@tree = root_tree(@taxonomy)
|
28
|
+
end
|
29
|
+
|
30
|
+
def update
|
31
|
+
@taxonomy = Taxonomy.find(params[:id])
|
32
|
+
if @taxonomy.update_attributes(params[:taxonomy])
|
33
|
+
redirect_to admin_taxonomies_url, :notice => "Successfully updated taxonomy."
|
34
|
+
else
|
35
|
+
render :action => 'edit'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def destroy
|
40
|
+
@taxonomy = Taxonomy.find(params[:id])
|
41
|
+
@taxonomy.destroy
|
42
|
+
redirect_to admin_taxonomies_url, :notice => "Successfully destroyed taxonomy."
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def root_tree(taxonomy)
|
49
|
+
tree = {
|
50
|
+
:attr => {:id => taxonomy.root.id.to_s, :rel => "root"},
|
51
|
+
:data => taxonomy.root.name,
|
52
|
+
:state => "open",
|
53
|
+
:children => tree_children(taxonomy.root)
|
54
|
+
}
|
55
|
+
return tree
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
class Admin::TaxonsController < Admin::BaseController
|
2
|
+
|
3
|
+
before_filter :find_taxonomy, :except => [:children]
|
4
|
+
|
5
|
+
def index
|
6
|
+
|
7
|
+
if @taxonomy
|
8
|
+
@taxons = @taxonomy.children.order(:pos)
|
9
|
+
else
|
10
|
+
@taxons = Taxon.all
|
11
|
+
end
|
12
|
+
|
13
|
+
respond_to do |format|
|
14
|
+
format.html # index.html.erb
|
15
|
+
format.json { render :json => @taxons}
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
def show
|
22
|
+
@taxon = Taxon.find(params[:id])
|
23
|
+
end
|
24
|
+
|
25
|
+
def new
|
26
|
+
@taxon = Taxon.new
|
27
|
+
end
|
28
|
+
|
29
|
+
def create
|
30
|
+
@taxon = Taxon.new(params[:taxon])
|
31
|
+
if @taxon.save
|
32
|
+
redirect_to edit_admin_taxonomy_url(@taxon.taxonomy), :notice => "Successfully created taxon."
|
33
|
+
else
|
34
|
+
render :action => 'new'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def edit
|
39
|
+
@taxon = Taxon.find(params[:id])
|
40
|
+
@taxonomy = @taxon.taxonomy
|
41
|
+
end
|
42
|
+
|
43
|
+
def update
|
44
|
+
@taxon = Taxon.find(params[:id])
|
45
|
+
if @taxon.update_attributes(params[:taxon])
|
46
|
+
|
47
|
+
# Move the taxon to the correct position
|
48
|
+
if params[:left_of_id] != params[:parent_id]
|
49
|
+
@right_taxon = Taxon.find(params[:left_of_id])
|
50
|
+
@taxon.move_to_left_of(@right_taxon) if @right_taxon && @taxon.siblings.include?(@right_taxon)
|
51
|
+
end
|
52
|
+
|
53
|
+
if params[:format] == :json
|
54
|
+
render :json => "ok"
|
55
|
+
else
|
56
|
+
redirect_to edit_admin_taxonomy_url(@taxon.taxonomy), :notice => "Successfully updated taxon."
|
57
|
+
end
|
58
|
+
else
|
59
|
+
render :action => 'edit'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def destroy
|
64
|
+
@taxon = Taxon.find(params[:id])
|
65
|
+
@taxon.destroy
|
66
|
+
redirect_to edit_admin_taxonomy_url(@taxon.taxonomy), :notice => "Successfully destroyed taxon."
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# Action for getting the children of a taxon
|
71
|
+
# right now it only responds to json requests
|
72
|
+
def children
|
73
|
+
@taxon = Taxon.find params[:id]
|
74
|
+
@children = @taxon.children
|
75
|
+
@tree = tree_children(@taxon)
|
76
|
+
respond_to do |format|
|
77
|
+
format.html
|
78
|
+
format.json { render :json => @tree }
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def find_taxonomy
|
87
|
+
if params[:taxonomy_id]
|
88
|
+
@taxonomy = Taxonomy.find(params[:taxonomy_id])
|
89
|
+
else
|
90
|
+
@taxonomy = nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
data/app/models/taxon.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
class Taxon < ActiveRecord::Base
|
2
|
+
|
3
|
+
acts_as_nested_set :dependent => :destroy
|
4
|
+
|
5
|
+
acts_as_url :name, :sync_url => true
|
6
|
+
|
7
|
+
|
8
|
+
belongs_to :taxonomy
|
9
|
+
|
10
|
+
before_create :set_path, :set_taxonomy
|
11
|
+
after_create :set_root
|
12
|
+
before_update :set_path
|
13
|
+
|
14
|
+
|
15
|
+
# TODO: I don't love this implementation as it doesn't allow for effective navigation up the tree
|
16
|
+
# but it does provide a nice url breadcrumb trail
|
17
|
+
|
18
|
+
|
19
|
+
# Creates path based on .to_url method provided by stringx gem
|
20
|
+
def set_path
|
21
|
+
|
22
|
+
if self.root?
|
23
|
+
self.path = '/'
|
24
|
+
else
|
25
|
+
ancestor_path = parent_taxon.path rescue "/"
|
26
|
+
sep = ancestor_path == "/" ? "" : "/"
|
27
|
+
self.path = ancestor_path + sep + self.url
|
28
|
+
end
|
29
|
+
|
30
|
+
#if parent_id.nil?
|
31
|
+
#self.path = self.url if self.path.blank?
|
32
|
+
#else
|
33
|
+
#parent_taxon = Taxon.find(parent_id)
|
34
|
+
#self.path = [parent_taxon.path, (self.path.blank? ? name.to_url : self.path.split("/").last)].join('/')
|
35
|
+
#end
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_taxonomy
|
39
|
+
if ! self.root?
|
40
|
+
self.root_id = parent_taxon.root_id
|
41
|
+
self.taxonomy_id = parent_taxon.taxonomy_id
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def set_root
|
46
|
+
self.root_id = self.id if self.root?
|
47
|
+
save
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def parent_taxon
|
55
|
+
@parent_taxon ||= Taxon.find(self.parent_id)
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Taxonomy < ActiveRecord::Base
|
2
|
+
has_many :taxons
|
3
|
+
has_one :root, :class_name => 'Taxon', :conditions => "parent_id is null"
|
4
|
+
|
5
|
+
|
6
|
+
after_create :create_root_taxon
|
7
|
+
before_destroy :delete_taxons
|
8
|
+
|
9
|
+
def create_root_taxon
|
10
|
+
self.taxons.create(:name => self.name + "__root")
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
# Doing this through a callback because it doesn't
|
15
|
+
# rely on the destroy conditions of the taxons and
|
16
|
+
# makes deleting much more efficient
|
17
|
+
def delete_taxons
|
18
|
+
# TODO: More to do here.
|
19
|
+
# We probably will want to ensure that any items
|
20
|
+
# assigned to the taxons get reassigned or cleaned
|
21
|
+
# up appropriately.
|
22
|
+
Taxon.destroy_all(:taxonomy_id => self.id)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<% content_for :head do %>
|
2
|
+
<%= javascript_tag "var taxonomy_id = #{@taxonomy.id};
|
3
|
+
var loading = '#{escape_javascript t('loading')}';
|
4
|
+
var new_taxon = '#{escape_javascript t('new_taxon')}';
|
5
|
+
var server_error = '#{escape_javascript t('server_error')}';
|
6
|
+
var taxonomy_tree_error = '#{escape_javascript t('taxonomy_tree_error')}';"
|
7
|
+
%>
|
8
|
+
<%= javascript_include_tag 'taxonomy', 'jsTree/jquery.jstree.js' %>
|
9
|
+
<% end %>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<table class="index" id='listing_taxonomies'>
|
2
|
+
<tr>
|
3
|
+
<th><%= "Name" %></th>
|
4
|
+
<th> </th>
|
5
|
+
</tr>
|
6
|
+
<% for taxonomy in @taxonomies %>
|
7
|
+
<tr id="<%= dom_id taxonomy %>">
|
8
|
+
<td>
|
9
|
+
<%= taxonomy.name %>
|
10
|
+
</td>
|
11
|
+
<td class="actions">
|
12
|
+
<%= link_to "Edit", edit_admin_taxonomy_url(taxonomy.id), :class => 'edit' %>
|
13
|
+
|
14
|
+
<%= link_to "Delete", admin_taxonomy_path(taxonomy), :confirm => 'Are you sure?', :method => :delete %>
|
15
|
+
|
16
|
+
</td>
|
17
|
+
</tr>
|
18
|
+
<% end %>
|
19
|
+
</table>
|
20
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<%= render :partial => "js_head" %>
|
2
|
+
|
3
|
+
<h1><%= t("taxonomy_edit")%></h1>
|
4
|
+
|
5
|
+
<p id="ajax_error" class="errorExplanation" style="display:none;"></p>
|
6
|
+
|
7
|
+
<%= form_for(:taxon, :url => admin_taxonomy_url, :html => { :method => :put }) do |f| %>
|
8
|
+
<%= render :partial => 'form', :locals => {:f => f} %>
|
9
|
+
<div>
|
10
|
+
<label>Taxonomy Tree</label><br />
|
11
|
+
<div id="taxonomy_tree" class="tree"></div>
|
12
|
+
</div>
|
13
|
+
<p id="progress" style="display:none;">
|
14
|
+
<%= image_tag('spinner.gif', :alt => "Spinner", :style => "vertical-align:bottom") %>
|
15
|
+
<%= t('updating') %>..
|
16
|
+
</p>
|
17
|
+
|
18
|
+
<p class="form-buttons">
|
19
|
+
<%= f.submit %> <%= link_to "Back to Taxonomies", admin_taxonomies_path %>
|
20
|
+
</p>
|
21
|
+
<% end %>
|
22
|
+
|
23
|
+
|
24
|
+
<% content_for :head do %>
|
25
|
+
<script type="text/javascript">
|
26
|
+
var initial = <%= raw @tree.to_json %>;
|
27
|
+
|
28
|
+
</script>
|
29
|
+
<% end %>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
|
2
|
+
<h1><%= t("new_taxonomy") %></h1>
|
3
|
+
|
4
|
+
<%= form_for(:taxonomy, :url => '/admin/taxonomies') do |f| %>
|
5
|
+
|
6
|
+
<%= render :partial => "form", :locals => { :f => f } %>
|
7
|
+
|
8
|
+
<p class="form-buttons">
|
9
|
+
<%= f.submit %> or <%= link_to "Cancel", admin_taxonomies_url %>
|
10
|
+
</p>
|
11
|
+
<% end %>
|