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.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +20 -0
  3. data/LICENSE +165 -0
  4. data/README.md +19 -0
  5. data/Rakefile +33 -0
  6. data/lib/admin_bits.rb +50 -0
  7. data/lib/admin_bits/admin_resource.rb +96 -0
  8. data/lib/admin_bits/admin_resource/paginator.rb +14 -0
  9. data/lib/admin_bits/admin_resource/path_handler.rb +34 -0
  10. data/lib/admin_bits/base_config.rb +38 -0
  11. data/lib/admin_bits/engine.rb +4 -0
  12. data/lib/admin_bits/helpers.rb +44 -0
  13. data/lib/admin_bits/scopes.rb +52 -0
  14. data/lib/admin_bits/utils.rb +16 -0
  15. data/lib/generators/admin_bits_generator.rb +52 -0
  16. data/lib/generators/templates/controller.rb.erb +35 -0
  17. data/lib/generators/templates/index.html.erb +0 -0
  18. data/lib/generators/templates/layout.html.erb +3 -0
  19. data/test/admin_bits_test.rb +7 -0
  20. data/test/dummy/Rakefile +7 -0
  21. data/test/dummy/app/assets/stylesheets/admin_bits.css +0 -0
  22. data/test/dummy/app/controllers/admin/items_controller.rb +40 -0
  23. data/test/dummy/app/controllers/application_controller.rb +3 -0
  24. data/test/dummy/app/helpers/application_helper.rb +2 -0
  25. data/test/dummy/app/models/basic_admin_panel.rb +65 -0
  26. data/test/dummy/app/models/item.rb +7 -0
  27. data/test/dummy/app/views/admin/items/index.html.erb +30 -0
  28. data/test/dummy/app/views/admin_bits_modules/basic_admin_panel/edit.html.erb +4 -0
  29. data/test/dummy/app/views/admin_bits_modules/basic_admin_panel/index.html.erb +30 -0
  30. data/test/dummy/app/views/layouts/admin_bits_modules/basic_admin_panel/layout.html.erb +13 -0
  31. data/test/dummy/config.ru +4 -0
  32. data/test/dummy/config/application.rb +45 -0
  33. data/test/dummy/config/boot.rb +10 -0
  34. data/test/dummy/config/database.yml +22 -0
  35. data/test/dummy/config/environment.rb +5 -0
  36. data/test/dummy/config/environments/development.rb +27 -0
  37. data/test/dummy/config/environments/production.rb +50 -0
  38. data/test/dummy/config/environments/test.rb +36 -0
  39. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  40. data/test/dummy/config/initializers/inflections.rb +10 -0
  41. data/test/dummy/config/initializers/mime_types.rb +5 -0
  42. data/test/dummy/config/initializers/secret_token.rb +7 -0
  43. data/test/dummy/config/initializers/session_store.rb +8 -0
  44. data/test/dummy/config/locales/en.yml +5 -0
  45. data/test/dummy/config/routes.rb +57 -0
  46. data/test/dummy/db/development.sqlite3 +0 -0
  47. data/test/dummy/db/migrate/20131110141830_create_items.rb +15 -0
  48. data/test/dummy/db/schema.rb +25 -0
  49. data/test/dummy/db/test.sqlite3 +0 -0
  50. data/test/dummy/log/development.log +2368 -0
  51. data/test/dummy/log/test.log +672 -0
  52. data/test/dummy/public/404.html +26 -0
  53. data/test/dummy/public/422.html +26 -0
  54. data/test/dummy/public/500.html +26 -0
  55. data/test/dummy/public/favicon.ico +0 -0
  56. data/test/dummy/public/javascripts/application.js +2 -0
  57. data/test/dummy/public/javascripts/controls.js +965 -0
  58. data/test/dummy/public/javascripts/dragdrop.js +974 -0
  59. data/test/dummy/public/javascripts/effects.js +1123 -0
  60. data/test/dummy/public/javascripts/prototype.js +6001 -0
  61. data/test/dummy/public/javascripts/rails.js +202 -0
  62. data/test/dummy/script/rails +6 -0
  63. data/test/integration/ordering_test.rb +14 -0
  64. data/test/support/integration_case.rb +5 -0
  65. data/test/test_helper.rb +22 -0
  66. data/test/unit/path_handler_test.rb +17 -0
  67. data/test/unit/sorting_test.rb +49 -0
  68. 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,4 @@
1
+ module AdminBits
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ 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
@@ -0,0 +1,3 @@
1
+ Layout template
2
+
3
+ <%= yield %>
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class AdminBitsTest < ActiveSupport::TestCase
4
+ test "truth" do
5
+ assert_kind_of Module, AdminBits
6
+ end
7
+ end
@@ -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,3 @@
1
+ class ApplicationController < ActionController::Base
2
+ protect_from_forgery
3
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ 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,7 @@
1
+ class Item < ActiveRecord::Base
2
+
3
+ def self.having_name(name)
4
+ name = "%#{name}%"
5
+ where(["name LIKE ?", name])
6
+ end
7
+ 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>
@@ -0,0 +1,4 @@
1
+ <%= simple_form_for [:admin, @item] do |f| %>
2
+ <%= f.input :name %>
3
+ <%= f.button :submit %>
4
+ <% end %>