admin_widgets 0.0.3
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.
- data/.gitignore +11 -0
- data/Gemfile +4 -0
- data/Rakefile +1 -0
- data/admin_widgets.gemspec +26 -0
- data/lib/admin_widgets.rb +8 -0
- data/lib/admin_widgets/base_form_widget.rb +65 -0
- data/lib/admin_widgets/base_widget.rb +33 -0
- data/lib/admin_widgets/delegation.rb +20 -0
- data/lib/admin_widgets/engine.rb +22 -0
- data/lib/admin_widgets/extensions/action_view_ext.rb +14 -0
- data/lib/admin_widgets/extensions/simple_form_ext.rb +16 -0
- data/lib/admin_widgets/filters_widget.rb +59 -0
- data/lib/admin_widgets/form/fieldset_widget.rb +102 -0
- data/lib/admin_widgets/form_widget.rb +24 -0
- data/lib/admin_widgets/helper.rb +11 -0
- data/lib/admin_widgets/list_widget.rb +210 -0
- data/lib/admin_widgets/memoization.rb +15 -0
- data/lib/admin_widgets/scopes_widget.rb +62 -0
- data/lib/admin_widgets/show/fieldset_widget.rb +27 -0
- data/lib/admin_widgets/show_widget.rb +35 -0
- data/lib/admin_widgets/version.rb +3 -0
- data/lib/admin_widgets/view_proxy.rb +49 -0
- data/lib/admin_widgets/wizard_widget.rb +79 -0
- metadata +80 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "admin_widgets/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "admin_widgets"
|
7
|
+
s.version = AdminWidgets::VERSION
|
8
|
+
s.authors = ["DanX~"]
|
9
|
+
s.email = ["danx.exe@gmail.com"]
|
10
|
+
s.homepage = "http://www.mobvox.com.br"
|
11
|
+
s.summary = "Awesome Admin Widgets"
|
12
|
+
s.description = "Super Awesome Admin Widgets"
|
13
|
+
|
14
|
+
s.rubyforge_project = "admin_widgets"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
|
25
|
+
s.add_runtime_dependency "apotomo"
|
26
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module AdminWidgets
|
2
|
+
class BaseFormWidget < BaseWidget
|
3
|
+
|
4
|
+
attr_reader :form
|
5
|
+
|
6
|
+
# TODO: WTF? Who the hell is overriding the 'form' method?
|
7
|
+
def builder
|
8
|
+
form
|
9
|
+
end
|
10
|
+
|
11
|
+
memoize :resource_class, proc { helper.resource_class }
|
12
|
+
memoize :resource, proc { helper.resource }
|
13
|
+
memoize :params, proc { helper.params }
|
14
|
+
memoize :as, nil
|
15
|
+
memoize :url, proc { '' }
|
16
|
+
memoize :cancel_url, proc { helper.respond_to?(:collection_path) ? helper.collection_path : false }
|
17
|
+
memoize :css_class, 'form'
|
18
|
+
|
19
|
+
delegate :object, :to => :form
|
20
|
+
|
21
|
+
def content
|
22
|
+
rawtext around_form
|
23
|
+
end
|
24
|
+
|
25
|
+
def around_form
|
26
|
+
form_method = @form ? :simple_fields_for : :simple_form_for
|
27
|
+
|
28
|
+
helper.send(form_method, resource, :url => url, :as => as, :class => css_class, :html => @html) do |f|
|
29
|
+
@form = f # IMPORTANT!
|
30
|
+
|
31
|
+
capture do
|
32
|
+
form_content
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def form_content
|
38
|
+
content_block
|
39
|
+
buttons
|
40
|
+
end
|
41
|
+
|
42
|
+
# FIXME: Beware, arcane magic below. We are polluting the root widget with a instance variable, is there a better way to do this?
|
43
|
+
def autofocus_done?
|
44
|
+
root.instance_variable_get(:@autofocus_done)
|
45
|
+
end
|
46
|
+
def autofocus!(options = {})
|
47
|
+
root.instance_variable_set(:@autofocus_done, true)
|
48
|
+
{ autofocus: true }.merge(options)
|
49
|
+
end
|
50
|
+
|
51
|
+
# DSL methods
|
52
|
+
|
53
|
+
def field(name, options = {})
|
54
|
+
options = autofocus!(options) unless autofocus_done?
|
55
|
+
|
56
|
+
condition = options[:if]
|
57
|
+
return if (condition.present? && !resource.instance_eval(&condition))
|
58
|
+
|
59
|
+
form = (options[:nested] === false && self.respond_to?(:parent)) ? parent.form : self.form
|
60
|
+
|
61
|
+
rawtext form.input(name, options)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module AdminWidgets
|
2
|
+
class BaseWidget < Erector::Widget
|
3
|
+
extend AdminWidgets::Memoization
|
4
|
+
extend AdminWidgets::Delegation
|
5
|
+
|
6
|
+
# Outputs to a new buffer
|
7
|
+
def capture(&block)
|
8
|
+
original, @_output = output, Erector::Output.new
|
9
|
+
instance_eval &block
|
10
|
+
original.widgets.concat(output.widgets)
|
11
|
+
output.to_s
|
12
|
+
ensure
|
13
|
+
@_output = original
|
14
|
+
end
|
15
|
+
|
16
|
+
def root
|
17
|
+
parent and parent.root or self
|
18
|
+
end
|
19
|
+
|
20
|
+
def helper
|
21
|
+
@controller.view_context
|
22
|
+
end
|
23
|
+
|
24
|
+
def method_missing(method_name, *args, &block)
|
25
|
+
rawtext helper.send(method_name, *args, &block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def content_block
|
29
|
+
instance_eval &@block if @block
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module AdminWidgets
|
2
|
+
module Delegation
|
3
|
+
def delegate(*methods)
|
4
|
+
options = methods.last
|
5
|
+
keys = methods[0..-2]
|
6
|
+
|
7
|
+
if options.is_a?(Hash) and options[:hash]
|
8
|
+
keys.each do |key|
|
9
|
+
define_method key do
|
10
|
+
hash = self.send(options[:to])
|
11
|
+
hash.send(:[], key)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
else
|
15
|
+
super *methods
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module AdminWidgets
|
2
|
+
class Engine < Rails::Engine
|
3
|
+
config.to_prepare do
|
4
|
+
require_dependency 'admin_widgets/helper'
|
5
|
+
require_dependency 'admin_widgets/memoization'
|
6
|
+
require_dependency 'admin_widgets/delegation'
|
7
|
+
require_dependency 'admin_widgets/base_widget'
|
8
|
+
require_dependency 'admin_widgets/base_form_widget'
|
9
|
+
require_dependency 'admin_widgets/form_widget'
|
10
|
+
require_dependency 'admin_widgets/form/fieldset_widget'
|
11
|
+
require_dependency 'admin_widgets/wizard_widget'
|
12
|
+
require_dependency 'admin_widgets/list_widget'
|
13
|
+
require_dependency 'admin_widgets/scopes_widget'
|
14
|
+
require_dependency 'admin_widgets/filters_widget'
|
15
|
+
require_dependency 'admin_widgets/show_widget'
|
16
|
+
require_dependency 'admin_widgets/show/fieldset_widget'
|
17
|
+
|
18
|
+
ActionView::Base.send :include, AdminWidgets::Helper
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module ActionView::Helpers::FormOptionsHelper
|
2
|
+
def options_from_collection_for_select(collection, value_method, text_method, selected = nil)
|
3
|
+
options = collection.map do |element|
|
4
|
+
option_html_attributes = (Array === element && element.size == 3 ? element.last : nil)
|
5
|
+
[element.send(text_method), element.send(value_method), option_html_attributes].compact
|
6
|
+
end
|
7
|
+
selected, disabled = extract_selected_and_disabled(selected)
|
8
|
+
select_deselect = {}
|
9
|
+
select_deselect[:selected] = extract_values_from_collection(collection, value_method, selected)
|
10
|
+
select_deselect[:disabled] = extract_values_from_collection(collection, value_method, disabled)
|
11
|
+
|
12
|
+
options_for_select(options, select_deselect)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class SimpleForm::Inputs::CollectionInput
|
2
|
+
def detect_common_display_methods
|
3
|
+
collection_classes = detect_collection_classes
|
4
|
+
|
5
|
+
if collection_classes.include?(Array)
|
6
|
+
{ :label => :first, :value => :second }
|
7
|
+
elsif collection_includes_basic_objects?(collection_classes)
|
8
|
+
{ :label => :to_s, :value => :to_s }
|
9
|
+
else
|
10
|
+
sample = collection.first || collection.last
|
11
|
+
|
12
|
+
{ :label => SimpleForm.collection_label_methods.find { |m| sample.respond_to?(m) },
|
13
|
+
:value => SimpleForm.collection_value_methods.find { |m| sample.respond_to?(m) } }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module AdminWidgets
|
2
|
+
class FiltersWidget < BaseFormWidget
|
3
|
+
|
4
|
+
memoize :resource, nil
|
5
|
+
memoize :as, 'search'
|
6
|
+
memoize :resource, 'search'
|
7
|
+
memoize :url, proc { helper.search_resources_path }
|
8
|
+
memoize :method, 'post'
|
9
|
+
|
10
|
+
def form_content
|
11
|
+
hidden_fields
|
12
|
+
content_block
|
13
|
+
buttons
|
14
|
+
end
|
15
|
+
|
16
|
+
# DSL methods
|
17
|
+
|
18
|
+
def field(name, operator, options = {})
|
19
|
+
field_name = "#{name}_#{operator}"
|
20
|
+
field_label = resource_class.human_attribute_name(name)
|
21
|
+
field_value = params[as][field_name] rescue ''
|
22
|
+
|
23
|
+
multiple = [:in, :all].include?(operator.to_sym)
|
24
|
+
field_value = field_value.to_s.split(',') if multiple && field_value && !field_value.is_a?(Array)
|
25
|
+
|
26
|
+
if options[:collection].present?
|
27
|
+
value = nil
|
28
|
+
selected = field_value
|
29
|
+
include_blank = true
|
30
|
+
else
|
31
|
+
value = field_value
|
32
|
+
selected = nil
|
33
|
+
include_blank = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
default_options = { :required => false, :label => field_label, :input_html => { :value => value, :multiple => multiple }, :selected => selected, :include_blank => include_blank, :hidden_field => false }
|
37
|
+
rawtext form.input(field_name, default_options.merge(options))
|
38
|
+
end
|
39
|
+
|
40
|
+
def hidden_fields
|
41
|
+
div :class => ['hidden-fields'] do
|
42
|
+
%w[scope sort_field sort_direction].each do |hidden_field|
|
43
|
+
rawtext form.input(hidden_field, :input_html => { :name => hidden_field, :value => params[hidden_field] }, :as => :hidden)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def buttons
|
49
|
+
div :class => ['group', 'navform', 'wat-cf'] do
|
50
|
+
rawtext helper.button_tag(:class => 'button', :name => 'filter', :value => as) {
|
51
|
+
helper.image_tag('search-button.png') +
|
52
|
+
helper.t('resources.actions.filter')
|
53
|
+
}
|
54
|
+
rawtext helper.link_to(helper.t('resources.actions.reset_filter'), cancel_url, :class => "text_button_padding link_button") if cancel_url
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module AdminWidgets::Form
|
2
|
+
class FieldsetWidget < AdminWidgets::FormWidget
|
3
|
+
|
4
|
+
attr_reader :parent
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def resource
|
8
|
+
form.object
|
9
|
+
end
|
10
|
+
|
11
|
+
delegate :helper, :to => :parent
|
12
|
+
|
13
|
+
memoize :repeatable, false
|
14
|
+
memoize :nested, true
|
15
|
+
memoize :legend, proc { resource_class.human_attribute_name(name) }
|
16
|
+
memoize :wrapper_html, {}
|
17
|
+
|
18
|
+
def visible
|
19
|
+
return @visible = true if @visible.nil?
|
20
|
+
return @visible = @visible.call(resource) if @visible.respond_to? :call
|
21
|
+
@visible
|
22
|
+
end
|
23
|
+
|
24
|
+
def content
|
25
|
+
return simple_fieldset unless nested
|
26
|
+
|
27
|
+
around_form do
|
28
|
+
around_repeatable_collection do
|
29
|
+
parent.form.simple_fields_for(name) do |form|
|
30
|
+
@form = form # IMPORTANT!
|
31
|
+
|
32
|
+
around_repeatable_group do
|
33
|
+
content_block
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def before
|
41
|
+
@before = capture do
|
42
|
+
div :class => 'before' do
|
43
|
+
yield
|
44
|
+
end
|
45
|
+
end
|
46
|
+
nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def after
|
50
|
+
@after = capture do
|
51
|
+
div :class => 'after' do
|
52
|
+
yield
|
53
|
+
end
|
54
|
+
end
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def simple_fieldset
|
59
|
+
@form = parent.form
|
60
|
+
around_form do
|
61
|
+
content_block
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def around_form
|
66
|
+
wrapper_attrs = { :class => 'fieldset-wrapper' }
|
67
|
+
wrapper_attrs.merge! :style => 'display: none' unless visible
|
68
|
+
wrapper_attrs.merge! wrapper_html
|
69
|
+
|
70
|
+
div wrapper_attrs do
|
71
|
+
if legend
|
72
|
+
element('fieldset') do
|
73
|
+
element('legend', legend)
|
74
|
+
inside = capture { yield }
|
75
|
+
rawtext @before
|
76
|
+
rawtext inside
|
77
|
+
rawtext @after
|
78
|
+
end
|
79
|
+
else
|
80
|
+
yield
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def around_repeatable_collection
|
86
|
+
return yield unless repeatable
|
87
|
+
|
88
|
+
div :class => 'repeatable-collection', :'data-repeatable' => repeatable do
|
89
|
+
yield
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def around_repeatable_group
|
94
|
+
return yield unless repeatable
|
95
|
+
|
96
|
+
div :class => ['repeatable-group', form.object.class.name.underscore], :id => form.object._id do
|
97
|
+
yield
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module AdminWidgets
|
2
|
+
class FormWidget < BaseFormWidget
|
3
|
+
|
4
|
+
memoize :url, proc { helper.respond_to?(:resource_or_collection_path) ? helper.resource_or_collection_path : '' }
|
5
|
+
memoize :save_button, true
|
6
|
+
|
7
|
+
# DSL methods
|
8
|
+
|
9
|
+
def fieldset(name, options = {}, &block)
|
10
|
+
widget AdminWidgets::Form::FieldsetWidget.new(options.merge(:name => name, :parent => self, :block => block))
|
11
|
+
end
|
12
|
+
|
13
|
+
def buttons
|
14
|
+
div :class => ['group', 'navform', 'wat-cf'] do
|
15
|
+
rawtext helper.button_tag(:class => 'button') {
|
16
|
+
helper.image_tag('icons/tick.png') +
|
17
|
+
helper.t('resources.actions.save')
|
18
|
+
} if save_button
|
19
|
+
rawtext helper.link_to(helper.t('resources.actions.cancel'), cancel_url, :class => "text_button_padding link_button") if cancel_url
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module AdminWidgets
|
2
|
+
module Helper
|
3
|
+
|
4
|
+
def admin_widget(name, options = {}, &block)
|
5
|
+
widget_class = "::AdminWidgets::#{name.to_s.camelize}Widget".constantize
|
6
|
+
options = options.merge(:controller => controller, :block => block)
|
7
|
+
widget_class.new(options).to_html
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
module AdminWidgets
|
2
|
+
class ListWidget < BaseWidget
|
3
|
+
|
4
|
+
attr_accessor :table_class
|
5
|
+
attr_reader :fields
|
6
|
+
|
7
|
+
# Options
|
8
|
+
|
9
|
+
memoize :table_id, proc { "#{resource_name}-table" }
|
10
|
+
memoize :table_class, 'table'
|
11
|
+
memoize :th_class, 'table-column'
|
12
|
+
memoize :pagination_class, ['actions-bar', 'wat-cf']
|
13
|
+
memoize :row_class, ActionView::Helpers::TextHelper::Cycle.new(:odd, :even)
|
14
|
+
memoize :resource_class, proc { helper.resource_class }
|
15
|
+
memoize :resource_name, proc { resource_class.name.underscore.pluralize }
|
16
|
+
memoize :params, proc { helper.params }
|
17
|
+
|
18
|
+
memoize :row_actions, true
|
19
|
+
|
20
|
+
memoize :page_param, :page
|
21
|
+
memoize :per_page_param, :per_page
|
22
|
+
memoize :page, proc { params[page_param].presence || 1 }
|
23
|
+
memoize :per_page, proc { params[per_page_param].presence || 25 }
|
24
|
+
|
25
|
+
memoize :column_sorting, true
|
26
|
+
memoize :sort_field_param, :sort_field
|
27
|
+
memoize :sort_direction_param, :sort_direction
|
28
|
+
memoize :sort_field, proc { params[sort_field_param].presence || :created_at }
|
29
|
+
memoize :sort_direction, proc { params[sort_direction_param].presence || :desc }
|
30
|
+
|
31
|
+
memoize :search_param, :search
|
32
|
+
memoize :search, proc { params[search_param] }
|
33
|
+
|
34
|
+
memoize :collection, proc { helper.collection }
|
35
|
+
memoize :scoped_collection, proc { collection.send(sort_direction, sort_field).page(page).per(per_page) }
|
36
|
+
|
37
|
+
|
38
|
+
delegate :edit_resource_path, :to => :helper
|
39
|
+
delegate :resource_path, :to => :helper
|
40
|
+
|
41
|
+
def initialize(*attrs)
|
42
|
+
super(*attrs)
|
43
|
+
|
44
|
+
@fields = []
|
45
|
+
end
|
46
|
+
|
47
|
+
def content
|
48
|
+
content_block
|
49
|
+
div :class => 'table-wrapper' do
|
50
|
+
div :class => 'table-controls'
|
51
|
+
div :class => 'table-content' do
|
52
|
+
table :class => table_class, :id => table_id, :'data-highlight-id' => helper.flash[:highlight_id] do
|
53
|
+
header
|
54
|
+
body
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
pagination
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# Content methods
|
63
|
+
|
64
|
+
def header
|
65
|
+
thead do
|
66
|
+
tr do
|
67
|
+
th :class => 'first'
|
68
|
+
fields.each do |field|
|
69
|
+
th :class => th_class, :'data-field-name' => field.name do
|
70
|
+
header = Header.new(self, field)
|
71
|
+
rawtext(column_sorting ? helper.link_to(header.label, header.url, :class => ['sortable', header.css_class]) : header.label)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
th :class => 'last'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def body
|
80
|
+
tbody do
|
81
|
+
scoped_collection.each do |object|
|
82
|
+
tr :class => row_class, :'data-id' => object.id do
|
83
|
+
td :class => 'first'
|
84
|
+
fields.each do |field|
|
85
|
+
td field.value_for(object)
|
86
|
+
end
|
87
|
+
td :class => 'last' do
|
88
|
+
row_actions_for(object) if row_actions
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def pagination
|
96
|
+
div :class => pagination_class do
|
97
|
+
div :class => 'results' do
|
98
|
+
count = [scoped_collection.count(true), scoped_collection.total_count].join(I18n.t('of', :scope => 'views.pagination'))
|
99
|
+
label = helper.t('views.pagination.results')
|
100
|
+
rawtext "#{label} #{count}"
|
101
|
+
end
|
102
|
+
rawtext helper.paginate scoped_collection, :outer_window => 1, :inner_window => 5, :params => { :search => nil }, :param_name => page_param
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def row_actions_for(object)
|
107
|
+
rawtext helper.link_to(label = helper.t('resources.actions.edit'), edit_resource_path(object), :class => 'edit', :alt => label)
|
108
|
+
rawtext helper.link_to(label = helper.t('resources.actions.destroy'), resource_path(object), :method => :delete, :confirm => helper.t('resources.destroy.confirm'), :class => 'destroy', :alt => label)
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
# DSL methods
|
113
|
+
|
114
|
+
def field(name, options = {}, &block)
|
115
|
+
|
116
|
+
value_callback = lambda do |name, options|
|
117
|
+
attribute_path = name.to_s.split('.')
|
118
|
+
value = attribute_path.inject(self) {|r, v| r.try(v) rescue '' }
|
119
|
+
|
120
|
+
# FIXME: This is bad code and I should feel bad. Extract it to a presenter maybe?
|
121
|
+
if value.is_a? Time
|
122
|
+
I18n.l(value, :format => :short)
|
123
|
+
elsif value.is_a? Date
|
124
|
+
I18n.l(value, :format => :default)
|
125
|
+
elsif value.is_a? Array
|
126
|
+
value.join(', ')
|
127
|
+
elsif options[:i18n]
|
128
|
+
I18n.t(value, :scope => options[:i18n])
|
129
|
+
else
|
130
|
+
value
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
@fields << Field.new(self, name, options, value_callback)
|
135
|
+
|
136
|
+
# Haml support hack
|
137
|
+
''
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
# Helper classes
|
142
|
+
|
143
|
+
class Field
|
144
|
+
attr_accessor :parent, :name, :options, :value_callback
|
145
|
+
|
146
|
+
def initialize(parent, name, options, value_callback)
|
147
|
+
@parent, @name, @options, @value_callback = parent, name, options, value_callback
|
148
|
+
end
|
149
|
+
|
150
|
+
def value_for(object)
|
151
|
+
object.instance_exec(name, options, &value_callback)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class Header
|
156
|
+
extend AdminWidgets::Delegation
|
157
|
+
|
158
|
+
attr_accessor :parent, :field
|
159
|
+
|
160
|
+
def initialize(parent, field)
|
161
|
+
@parent, @field = parent, field
|
162
|
+
end
|
163
|
+
|
164
|
+
delegate :helper, :params, :resource_class, :to => :parent
|
165
|
+
with_options :to => :params, :hash => true do |c|
|
166
|
+
c.delegate :sort_direction
|
167
|
+
c.delegate :per_page
|
168
|
+
c.delegate :page
|
169
|
+
c.delegate :where
|
170
|
+
c.delegate :scope
|
171
|
+
end
|
172
|
+
|
173
|
+
def sort_field
|
174
|
+
field.name
|
175
|
+
end
|
176
|
+
|
177
|
+
def current_sort_field?
|
178
|
+
helper.params[:sort_field] == sort_field.to_s
|
179
|
+
end
|
180
|
+
|
181
|
+
def next_sort_direction
|
182
|
+
(current_sort_field? && sort_direction == 'asc') ? 'desc' : 'asc'
|
183
|
+
end
|
184
|
+
|
185
|
+
def sort_params
|
186
|
+
{
|
187
|
+
:sort_field => sort_field,
|
188
|
+
:sort_direction => next_sort_direction,
|
189
|
+
:per_page => per_page,
|
190
|
+
:page => page,
|
191
|
+
:where => where,
|
192
|
+
:scope => scope
|
193
|
+
}
|
194
|
+
end
|
195
|
+
|
196
|
+
def label
|
197
|
+
resource_class.human_attribute_name(field.name)
|
198
|
+
end
|
199
|
+
|
200
|
+
def url
|
201
|
+
helper.collection_path(sort_params)
|
202
|
+
end
|
203
|
+
|
204
|
+
def css_class
|
205
|
+
sort_direction if current_sort_field?
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module AdminWidgets
|
2
|
+
module Memoization
|
3
|
+
def memoize(attribute, val_or_callback)
|
4
|
+
ivar = "@#{attribute}"
|
5
|
+
|
6
|
+
define_method attribute do
|
7
|
+
if (current_val = instance_variable_get(ivar)).nil?
|
8
|
+
value = val_or_callback.respond_to?(:call) ? instance_eval(&val_or_callback) : val_or_callback
|
9
|
+
current_val = instance_variable_set(ivar, value)
|
10
|
+
end
|
11
|
+
current_val
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module AdminWidgets
|
2
|
+
class ScopesWidget < BaseWidget
|
3
|
+
|
4
|
+
def content
|
5
|
+
div :class => 'scopes' do
|
6
|
+
content_block
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
# DSL methods
|
12
|
+
|
13
|
+
def scope(name, options = {})
|
14
|
+
rawtext Scope.new(self, name, options).to_html
|
15
|
+
|
16
|
+
# Haml support hack
|
17
|
+
''
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
# Options
|
22
|
+
|
23
|
+
memoize :collection, proc { helper.collection }
|
24
|
+
memoize :resource_class, proc { helper.resource_class }
|
25
|
+
memoize :current_scope, proc { helper.current_scope }
|
26
|
+
memoize :params, proc { helper.params.reject{ |k,v| k == 'search' } }
|
27
|
+
memoize :i18n_scope, proc { "mongoid.scopes.#{resource_class.to_s.underscore}" }
|
28
|
+
|
29
|
+
|
30
|
+
# Helper classes
|
31
|
+
|
32
|
+
class Scope < BaseWidget
|
33
|
+
attr_accessor :parent, :name, :options
|
34
|
+
|
35
|
+
def initialize(parent, name, options = {})
|
36
|
+
super options.merge(:parent => parent, :name => name)
|
37
|
+
end
|
38
|
+
|
39
|
+
delegate :helper, :collection, :current_scope, :i18n_scope, :to => :parent
|
40
|
+
|
41
|
+
memoize :label, proc { I18n.t(name, :scope => i18n_scope) }
|
42
|
+
memoize :full_label, proc { label }
|
43
|
+
memoize :default, false
|
44
|
+
memoize :scope, proc { default ? nil : name }
|
45
|
+
memoize :current_css_class, proc { 'current' if current? }
|
46
|
+
memoize :css_class, proc { ['scope', current_css_class] }
|
47
|
+
|
48
|
+
def current?
|
49
|
+
(current_scope.nil? && default) || (current_scope.to_s == name.to_s)
|
50
|
+
end
|
51
|
+
|
52
|
+
def params
|
53
|
+
parent.params.merge(:scope => scope)
|
54
|
+
end
|
55
|
+
|
56
|
+
def content
|
57
|
+
rawtext helper.link_to(full_label, params, :class => css_class)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module AdminWidgets::Show
|
2
|
+
class FieldsetWidget < AdminWidgets::ShowWidget
|
3
|
+
|
4
|
+
attr_reader :parent
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
memoize :resource, proc { parent.resource.send(name) }
|
8
|
+
memoize :legend, proc { parent.resource_class.human_attribute_name(name) }
|
9
|
+
|
10
|
+
delegate :helper, :to => :parent
|
11
|
+
|
12
|
+
def content
|
13
|
+
rawtext(around_fieldset do
|
14
|
+
super
|
15
|
+
end)
|
16
|
+
end
|
17
|
+
|
18
|
+
def around_fieldset
|
19
|
+
element('fieldset') do
|
20
|
+
element('legend', legend)
|
21
|
+
|
22
|
+
yield
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module AdminWidgets
|
2
|
+
class ShowWidget < BaseWidget
|
3
|
+
|
4
|
+
attr_reader :builder
|
5
|
+
|
6
|
+
memoize :resource, proc { helper.resource }
|
7
|
+
memoize :resource_class, proc { resource.class }
|
8
|
+
|
9
|
+
def content
|
10
|
+
rawtext show
|
11
|
+
end
|
12
|
+
|
13
|
+
def show
|
14
|
+
helper.show_for(resource) do |builder|
|
15
|
+
@builder = builder
|
16
|
+
|
17
|
+
capture do
|
18
|
+
content_block
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def field(name, options = {})
|
24
|
+
condition = options[:if]
|
25
|
+
return if (condition.present? && !resource.instance_eval(&condition))
|
26
|
+
|
27
|
+
rawtext resource.reflect_on_association(name) ? builder.association(name, options) : builder.attribute(name, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def fieldset(name, options = {}, &block)
|
31
|
+
widget AdminWidgets::Show::FieldsetWidget.new(options.merge(:name => name, :parent => self, :block => block))
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module AdminWidgets
|
2
|
+
class ViewProxy < ActiveSupport::BasicObject
|
3
|
+
|
4
|
+
attr_accessor :widget
|
5
|
+
|
6
|
+
def initialize(view, widget)
|
7
|
+
@widget = widget
|
8
|
+
@view = buffered_view(view)
|
9
|
+
end
|
10
|
+
|
11
|
+
def method_missing(method_name, *args, &block)
|
12
|
+
target = case
|
13
|
+
when widget.dsl_methods.include?(method_name.to_sym) then @widget
|
14
|
+
else @view
|
15
|
+
end
|
16
|
+
|
17
|
+
target.send(method_name, *args, &block)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# Manually initialize output buffers
|
23
|
+
# This is needed for ActionView::Helpers::CaptureHelper
|
24
|
+
def buffered_view(view)
|
25
|
+
@view || begin
|
26
|
+
init_output_buffer!(view)
|
27
|
+
init_haml_buffer!(view)
|
28
|
+
|
29
|
+
view
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def init_output_buffer!(view)
|
34
|
+
view.output_buffer = ::ActionView::OutputBuffer.new
|
35
|
+
end
|
36
|
+
|
37
|
+
def init_haml_buffer!(view)
|
38
|
+
return unless defined? ::Haml
|
39
|
+
|
40
|
+
class << view
|
41
|
+
include ::Haml::Helpers unless included_modules.to_a.include?(::Haml::Helpers)
|
42
|
+
end
|
43
|
+
|
44
|
+
view.init_haml_helpers
|
45
|
+
view.instance_variable_set :@haml_buffer, ::Haml::Buffer.new(nil, :preserve => [], :encoding => 'UTF-8')
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module AdminWidgets
|
2
|
+
class WizardWidget < BaseFormWidget
|
3
|
+
|
4
|
+
memoize :url, proc { helper.resource_or_collection_path }
|
5
|
+
memoize :resource, proc { helper.resource }
|
6
|
+
memoize :resource_plural_name, proc { resource.class.name.underscore.pluralize }
|
7
|
+
memoize :display_finish_button, proc { true }
|
8
|
+
|
9
|
+
attr_reader :current_step
|
10
|
+
|
11
|
+
# DSL methods
|
12
|
+
|
13
|
+
def fieldset(name, options = {}, &block)
|
14
|
+
widget AdminWidgets::Form::FieldsetWidget.new(options.merge(:name => name, :parent => self, :block => block))
|
15
|
+
end
|
16
|
+
|
17
|
+
def steps_header
|
18
|
+
|
19
|
+
# Default button
|
20
|
+
rawtext helper.button_tag(:class => "default-step-button", :style => 'border:0;display:block;height:0;overflow:hidden;padding:0;', :name => 'change_step', :value => (@current_step.to_i + 1)) { 'Next' }
|
21
|
+
|
22
|
+
ul :class => 'steps' do
|
23
|
+
@steps.each_with_index do |step, index|
|
24
|
+
li do
|
25
|
+
active = @current_step == index + 1 ? ' active' : ''
|
26
|
+
rawtext helper.button_tag(:class => "step#{active}", :name => 'change_step', :value => index + 1) {
|
27
|
+
helper.t(step, :scope => "wizards.#{resource_plural_name}.steps", :index => index + 1)
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def form_content
|
35
|
+
content_block
|
36
|
+
steps_header
|
37
|
+
rawtext @content_buffer
|
38
|
+
buttons
|
39
|
+
end
|
40
|
+
|
41
|
+
def buttons
|
42
|
+
div :class => ['group', 'navform', 'wat-cf'] do
|
43
|
+
rawtext helper.button_tag(:class => 'big button finish', :name => 'change_step', :value => @steps.size + 1) {
|
44
|
+
helper.image_tag('icons/tick.png') +
|
45
|
+
helper.t('resources.actions.finish')
|
46
|
+
} if display_finish_button && @current_step == @steps.count
|
47
|
+
rawtext helper.button_tag(:class => 'big button next', :name => 'change_step', :value => @current_step + 1) {
|
48
|
+
helper.image_tag('icons/next.png') +
|
49
|
+
helper.t('resources.actions.next')
|
50
|
+
} if @current_step < @steps.count
|
51
|
+
rawtext helper.button_tag(:class => 'big button previous', :name => 'change_step', :value => @current_step - 1) {
|
52
|
+
helper.image_tag('icons/previous.png') +
|
53
|
+
helper.t('resources.actions.previous')
|
54
|
+
} if @current_step > 1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def step(name, &block)
|
59
|
+
@current_step ||= 1
|
60
|
+
@content_buffer ||= ''
|
61
|
+
@steps = [] if !@steps
|
62
|
+
@steps << name
|
63
|
+
@content_buffer += capture do
|
64
|
+
div :class => 'step' do
|
65
|
+
instance_eval &block if block
|
66
|
+
end if @current_step == @steps.count
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def view(&block)
|
71
|
+
@content_buffer ||= ''
|
72
|
+
|
73
|
+
@content_buffer += capture do
|
74
|
+
instance_eval &block if block
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: admin_widgets
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- DanX~
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-10-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: apotomo
|
16
|
+
requirement: &2157956000 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2157956000
|
25
|
+
description: Super Awesome Admin Widgets
|
26
|
+
email:
|
27
|
+
- danx.exe@gmail.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
34
|
+
- Rakefile
|
35
|
+
- admin_widgets.gemspec
|
36
|
+
- lib/admin_widgets.rb
|
37
|
+
- lib/admin_widgets/base_form_widget.rb
|
38
|
+
- lib/admin_widgets/base_widget.rb
|
39
|
+
- lib/admin_widgets/delegation.rb
|
40
|
+
- lib/admin_widgets/engine.rb
|
41
|
+
- lib/admin_widgets/extensions/action_view_ext.rb
|
42
|
+
- lib/admin_widgets/extensions/simple_form_ext.rb
|
43
|
+
- lib/admin_widgets/filters_widget.rb
|
44
|
+
- lib/admin_widgets/form/fieldset_widget.rb
|
45
|
+
- lib/admin_widgets/form_widget.rb
|
46
|
+
- lib/admin_widgets/helper.rb
|
47
|
+
- lib/admin_widgets/list_widget.rb
|
48
|
+
- lib/admin_widgets/memoization.rb
|
49
|
+
- lib/admin_widgets/scopes_widget.rb
|
50
|
+
- lib/admin_widgets/show/fieldset_widget.rb
|
51
|
+
- lib/admin_widgets/show_widget.rb
|
52
|
+
- lib/admin_widgets/version.rb
|
53
|
+
- lib/admin_widgets/view_proxy.rb
|
54
|
+
- lib/admin_widgets/wizard_widget.rb
|
55
|
+
homepage: http://www.mobvox.com.br
|
56
|
+
licenses: []
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ! '>='
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
requirements: []
|
74
|
+
rubyforge_project: admin_widgets
|
75
|
+
rubygems_version: 1.8.10
|
76
|
+
signing_key:
|
77
|
+
specification_version: 3
|
78
|
+
summary: Awesome Admin Widgets
|
79
|
+
test_files: []
|
80
|
+
has_rdoc:
|