admin_bits 0.4.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.
- checksums.yaml +7 -0
- data/Gemfile +20 -0
- data/LICENSE +165 -0
- data/README.md +19 -0
- data/Rakefile +33 -0
- data/lib/admin_bits.rb +50 -0
- data/lib/admin_bits/admin_resource.rb +96 -0
- data/lib/admin_bits/admin_resource/paginator.rb +14 -0
- data/lib/admin_bits/admin_resource/path_handler.rb +34 -0
- data/lib/admin_bits/base_config.rb +38 -0
- data/lib/admin_bits/engine.rb +4 -0
- data/lib/admin_bits/helpers.rb +44 -0
- data/lib/admin_bits/scopes.rb +52 -0
- data/lib/admin_bits/utils.rb +16 -0
- data/lib/generators/admin_bits_generator.rb +52 -0
- data/lib/generators/templates/controller.rb.erb +35 -0
- data/lib/generators/templates/index.html.erb +0 -0
- data/lib/generators/templates/layout.html.erb +3 -0
- data/test/admin_bits_test.rb +7 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/stylesheets/admin_bits.css +0 -0
- data/test/dummy/app/controllers/admin/items_controller.rb +40 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/basic_admin_panel.rb +65 -0
- data/test/dummy/app/models/item.rb +7 -0
- data/test/dummy/app/views/admin/items/index.html.erb +30 -0
- data/test/dummy/app/views/admin_bits_modules/basic_admin_panel/edit.html.erb +4 -0
- data/test/dummy/app/views/admin_bits_modules/basic_admin_panel/index.html.erb +30 -0
- data/test/dummy/app/views/layouts/admin_bits_modules/basic_admin_panel/layout.html.erb +13 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +45 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +22 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +27 -0
- data/test/dummy/config/environments/production.rb +50 -0
- data/test/dummy/config/environments/test.rb +36 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +57 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20131110141830_create_items.rb +15 -0
- data/test/dummy/db/schema.rb +25 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +2368 -0
- data/test/dummy/log/test.log +672 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/public/javascripts/application.js +2 -0
- data/test/dummy/public/javascripts/controls.js +965 -0
- data/test/dummy/public/javascripts/dragdrop.js +974 -0
- data/test/dummy/public/javascripts/effects.js +1123 -0
- data/test/dummy/public/javascripts/prototype.js +6001 -0
- data/test/dummy/public/javascripts/rails.js +202 -0
- data/test/dummy/script/rails +6 -0
- data/test/integration/ordering_test.rb +14 -0
- data/test/support/integration_case.rb +5 -0
- data/test/test_helper.rb +22 -0
- data/test/unit/path_handler_test.rb +17 -0
- data/test/unit/sorting_test.rb +49 -0
- metadata +123 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
module AdminBits
|
|
2
|
+
class BaseConfig
|
|
3
|
+
def initialize
|
|
4
|
+
@options = {}.with_indifferent_access
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def [](name)
|
|
8
|
+
@options[name]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.rw_method(name)
|
|
12
|
+
define_method name do |value = nil, &block|
|
|
13
|
+
throw_error if block && value
|
|
14
|
+
@options[name] = value || block
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
define_method "get_#{name}" do
|
|
18
|
+
@options[name]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def inspect
|
|
23
|
+
@options.inspect
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
rw_method :path
|
|
27
|
+
rw_method :filters
|
|
28
|
+
rw_method :ordering
|
|
29
|
+
rw_method :default_order
|
|
30
|
+
rw_method :default_direction
|
|
31
|
+
rw_method :layout # :off | :default | "layout_name"
|
|
32
|
+
rw_method :mods # [BasicAdminPanel]
|
|
33
|
+
private
|
|
34
|
+
def throw_error
|
|
35
|
+
raise "Please provide either block of value"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module AdminBits
|
|
2
|
+
module Helpers
|
|
3
|
+
def admin_link(attrib, name)
|
|
4
|
+
link_content = name.html_safe
|
|
5
|
+
|
|
6
|
+
if admin_resource.request_params[:order] == attrib.to_s
|
|
7
|
+
ascending = admin_resource.request_params[:asc] == "true" ? true : false
|
|
8
|
+
klass = ascending ? "sort_asc" : "sort_desc"
|
|
9
|
+
ascending = !ascending
|
|
10
|
+
else
|
|
11
|
+
klass = nil
|
|
12
|
+
ascending = true
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
link_to link_content, admin_resource.url(:order => attrib, :asc => ascending.to_s), :class => klass
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def admin_form(options = {}, &block)
|
|
19
|
+
form_tag(admin_resource.original_url, options) do
|
|
20
|
+
content = capture(&block)
|
|
21
|
+
|
|
22
|
+
tags = [
|
|
23
|
+
hidden_field_tag("order", admin_resource.request_params[:order]),
|
|
24
|
+
hidden_field_tag("asc", admin_resource.request_params[:asc]),
|
|
25
|
+
content
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
tags.join("").html_safe
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def admin_select_filter(attribute, options, html_options)
|
|
33
|
+
select_tag "filters[#{attribute}]", options, html_options
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def admin_text_filter(attribute)
|
|
37
|
+
text_field_tag "filters[#{attribute}]", admin_resource.filter_params[attribute]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def admin_date_filter(attribute)
|
|
41
|
+
text_field_tag "filters[#{attribute}]", admin_resource.filter_params[attribute], :class => "datepicker"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module AdminBits
|
|
2
|
+
module Scopes
|
|
3
|
+
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.extend(ClassMethods)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
def admin_extension_scopes
|
|
10
|
+
@@admin_extension_scopes || {}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def declare_time_range_scope(name, options = {})
|
|
14
|
+
@@admin_extension_scopes ||= {}
|
|
15
|
+
@@admin_extension_scopes[name] = :time_range
|
|
16
|
+
|
|
17
|
+
scope name, ->(date_from, date_to) do
|
|
18
|
+
column = options.fetch(:on)
|
|
19
|
+
date_from = Time.parse(date_from) rescue nil
|
|
20
|
+
date_to = Time.parse(date_to) rescue nil
|
|
21
|
+
|
|
22
|
+
result_scope = where(nil)
|
|
23
|
+
|
|
24
|
+
if date_from
|
|
25
|
+
result_scope = result_scope.where(arel_table[column].gteq(date_from))
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
if date_to
|
|
29
|
+
result_scope = result_scope.where(arel_table[column].lteq(date_to))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
result_scope
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def declare_text_search_scope(name, options = {})
|
|
37
|
+
@@admin_extension_scopes ||= {}
|
|
38
|
+
@@admin_extension_scopes[name] = :text
|
|
39
|
+
|
|
40
|
+
scope name, ->(text) do
|
|
41
|
+
if text.present?
|
|
42
|
+
columns = options.fetch(:on)
|
|
43
|
+
where(AdminExtension::Utils.create_search_conditions(text, columns))
|
|
44
|
+
else
|
|
45
|
+
where(nil)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module AdminBits
|
|
2
|
+
class Utils
|
|
3
|
+
def self.split_text(text)
|
|
4
|
+
text.strip.split(/\s+/)
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# Returns array of confitions for text search
|
|
8
|
+
def self.create_search_conditions(text, columns)
|
|
9
|
+
text = split_text(text).join("%")
|
|
10
|
+
text = "%" + text + "%"
|
|
11
|
+
conditions = [columns.map {|c| "#{c} LIKE ?"}.join(" OR ")]
|
|
12
|
+
columns.length.times { conditions << text }
|
|
13
|
+
conditions
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'rails/generators'
|
|
2
|
+
require 'rbconfig'
|
|
3
|
+
|
|
4
|
+
class AdminBitsGenerator < Rails::Generators::Base
|
|
5
|
+
|
|
6
|
+
class_option :layout,
|
|
7
|
+
:type => :string,
|
|
8
|
+
:desc => "Name of the generated layout eg. 'admin' will be placed in 'app/views/layouts/admin.html.erb'",
|
|
9
|
+
:aliases => '-L', :default => 'admin'
|
|
10
|
+
class_option :namespace,
|
|
11
|
+
:type => :string,
|
|
12
|
+
:desc => "Name of the namespace for the generated controller eg. 'admin'",
|
|
13
|
+
:aliases => '-NS', :default => 'admin'
|
|
14
|
+
class_option :resource,
|
|
15
|
+
:type => :string,
|
|
16
|
+
:required => true,
|
|
17
|
+
:desc => "Name of the resource eg. 'products' will create 'namespace/products_controller.rb'",
|
|
18
|
+
:aliases => '-R'
|
|
19
|
+
class_option :unify, # TODO
|
|
20
|
+
:type => :boolean,
|
|
21
|
+
:default => false,
|
|
22
|
+
:desc => "Create special BaseController in the selected namespace",
|
|
23
|
+
:aliases => '-U'
|
|
24
|
+
|
|
25
|
+
self.source_paths << File.join(File.dirname(__FILE__), 'templates')
|
|
26
|
+
|
|
27
|
+
def create_layout
|
|
28
|
+
template "layout.html.erb", "app/views/layouts/#{ layout }.html.erb"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def create_controller
|
|
32
|
+
template "controller.rb.erb", "app/controllers/#{ namespace }/#{ resource }_controller.rb"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
protected
|
|
36
|
+
|
|
37
|
+
def layout
|
|
38
|
+
options[:layout]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def namespace
|
|
42
|
+
options[:namespace]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def resource
|
|
46
|
+
options[:resource]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def controller_name
|
|
50
|
+
(resource + '_controller')
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
class <%= namespace.camelcase %>::<%= controller_name.camelcase %> < ActionController::Base
|
|
2
|
+
include AdminBits
|
|
3
|
+
|
|
4
|
+
declare_resource :<%= resource %> do
|
|
5
|
+
# This should be path to your index action - you can create any path you like
|
|
6
|
+
path :<%= namespace %>_<%= resource %>_path
|
|
7
|
+
# Ordering contains key - sort order definitions in SQL.
|
|
8
|
+
# This is just the simplest example, for more information visit...[page]
|
|
9
|
+
ordering({
|
|
10
|
+
id: "<%= resource %>.id"
|
|
11
|
+
})
|
|
12
|
+
default_order :id
|
|
13
|
+
default_direction :asc
|
|
14
|
+
# Conditions
|
|
15
|
+
filters({
|
|
16
|
+
# name_of_the_scope: [:name_of_the_param, :name_of_another_param_passed_to_the_scope],
|
|
17
|
+
# arbitrary_filter_name: [:from, :to]
|
|
18
|
+
id_between: lambda { |f| where("items.id BETWEEN ? AND ?", f[:from], f[:to]) }
|
|
19
|
+
})
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
<% klass = resource.singularize.camelcase %>
|
|
23
|
+
|
|
24
|
+
def index
|
|
25
|
+
@<%= resource %> = <%= klass %>
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def edit
|
|
29
|
+
@<%= resource %> = <%= klass %>.find(params[:id])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def update
|
|
33
|
+
@<%= resource %> = <%= klass %>.find(params[:id])
|
|
34
|
+
end
|
|
35
|
+
end
|
|
File without changes
|
data/test/dummy/Rakefile
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
|
2
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
|
3
|
+
|
|
4
|
+
require File.expand_path('../config/application', __FILE__)
|
|
5
|
+
require 'rake'
|
|
6
|
+
|
|
7
|
+
Dummy::Application.load_tasks
|
|
File without changes
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
class Admin::ItemsController < ApplicationController
|
|
2
|
+
include AdminBits
|
|
3
|
+
|
|
4
|
+
declare_resource :items do
|
|
5
|
+
path { admin_items_path }
|
|
6
|
+
ordering({
|
|
7
|
+
:name => "items.name",
|
|
8
|
+
:price => "items.price"
|
|
9
|
+
})
|
|
10
|
+
default_order :price
|
|
11
|
+
default_direction :desc
|
|
12
|
+
filters({
|
|
13
|
+
# Points to Item#having_name, passes params[:filters][:name] as the only param
|
|
14
|
+
:having_name => [:name],
|
|
15
|
+
# One can define own filter criteria of arbitrary name using lambdas
|
|
16
|
+
:price_between => lambda { |f|
|
|
17
|
+
from = f[:from].present? ? f[:from].to_i : nil
|
|
18
|
+
to = f[:to].present? ? f[:to].to_i : nil
|
|
19
|
+
|
|
20
|
+
ret = where(nil)
|
|
21
|
+
ret = ret.where(["price <= ?", to]) if to
|
|
22
|
+
ret = ret.where(["price >= ?", from]) if from
|
|
23
|
+
ret
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
mods BasicAdminPanel
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def index
|
|
30
|
+
@items = Item
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def edit
|
|
34
|
+
@item = Item.find(params[:id])
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def update
|
|
38
|
+
@item = Item.find(params[:id])
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
class BasicAdminPanel
|
|
2
|
+
def initialize(controller_class, options = {})
|
|
3
|
+
controller_class.instance_eval do
|
|
4
|
+
layout "admin_bits_modules/basic_admin_panel/layout"
|
|
5
|
+
|
|
6
|
+
def columns_for_index(*columns)
|
|
7
|
+
@columns_for_index = columns
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def redefine_action(action)
|
|
11
|
+
unless instance_variable_get("@#{action}_defined")
|
|
12
|
+
alias_method :"original_#{action}", action
|
|
13
|
+
remove_method action
|
|
14
|
+
instance_variable_set("@#{action}_defined", true)
|
|
15
|
+
|
|
16
|
+
define_method action do
|
|
17
|
+
send(:"original_#{action}")
|
|
18
|
+
begin
|
|
19
|
+
render "admin_bits_modules/basic_admin_panel/#{action}"
|
|
20
|
+
rescue AbstractController::DoubleRenderError
|
|
21
|
+
# Do nothing - render view specified by user
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def redefine_update_action
|
|
28
|
+
action = :update
|
|
29
|
+
unless instance_variable_get("@#{action}_defined")
|
|
30
|
+
alias_method :"original_#{action}", action
|
|
31
|
+
remove_method action
|
|
32
|
+
instance_variable_set("@#{action}_defined", true)
|
|
33
|
+
|
|
34
|
+
define_method action do
|
|
35
|
+
resource = admin_resource.name.to_s.singularize
|
|
36
|
+
send(:"original_#{action}")
|
|
37
|
+
ivar = instance_variable_get("@#{resource}")
|
|
38
|
+
ivar.attributes = params[resource]
|
|
39
|
+
begin
|
|
40
|
+
if ivar.save
|
|
41
|
+
redirect_to :action => :index
|
|
42
|
+
else
|
|
43
|
+
render "admin_bits_modules/basic_admin_panel/edit"
|
|
44
|
+
end
|
|
45
|
+
rescue AbstractController::DoubleRenderError
|
|
46
|
+
# Do nothing - render view specified by user
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def method_added(method_name)
|
|
53
|
+
case method_name
|
|
54
|
+
when :index, :edit, :show
|
|
55
|
+
redefine_action method_name
|
|
56
|
+
when :update
|
|
57
|
+
redefine_update_action
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<div id="filtering">
|
|
2
|
+
<%= admin_form :method => :get do %>
|
|
3
|
+
Name: <%= admin_text_filter :name %>
|
|
4
|
+
<br>
|
|
5
|
+
Price from <%= text_field_tag("filters[from]", admin_filter(:from)) %> and <%= text_field_tag("filters[to]", admin_filter(:to)) %>
|
|
6
|
+
|
|
7
|
+
<button>Filter!</button>
|
|
8
|
+
<% end %>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
<table>
|
|
12
|
+
<thead>
|
|
13
|
+
<th>
|
|
14
|
+
<%= admin_link(:name, "Name") %>
|
|
15
|
+
<%= admin_link(:price, "Total price") %>
|
|
16
|
+
</th>
|
|
17
|
+
</thead>
|
|
18
|
+
<tbody>
|
|
19
|
+
<% items.each do |item| %>
|
|
20
|
+
<tr>
|
|
21
|
+
<td>
|
|
22
|
+
<%= item.name %>
|
|
23
|
+
</td>
|
|
24
|
+
<td>
|
|
25
|
+
<%= item.price %>
|
|
26
|
+
</td>
|
|
27
|
+
</tr>
|
|
28
|
+
<% end %>
|
|
29
|
+
</tbody>
|
|
30
|
+
</table>
|