quirkey-qadmin 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +5 -0
- data/LICENSE +20 -0
- data/Manifest.txt +20 -12
- data/PostInstall.txt +1 -1
- data/README.rdoc +4 -29
- data/Rakefile +5 -3
- data/lib/qadmin.rb +4 -2
- data/lib/qadmin/assets/form_builder.rb +36 -0
- data/lib/qadmin/configuration.rb +48 -0
- data/lib/qadmin/controller.rb +64 -34
- data/lib/qadmin/form_builder.rb +23 -0
- data/lib/qadmin/helper.rb +46 -15
- data/lib/qadmin/option_set.rb +48 -0
- data/lib/qadmin/overlay.rb +31 -0
- data/lib/qadmin/page_titles.rb +34 -0
- data/lib/qadmin/templates.rb +52 -0
- data/lib/qadmin/views/content_forms/_attachments_form.erb +0 -0
- data/lib/qadmin/views/content_forms/_photos_form.erb +4 -0
- data/lib/qadmin/views/content_forms/_videos_form.erb +0 -0
- data/lib/qadmin/views/default/edit.erb +12 -0
- data/lib/qadmin/views/default/index.erb +9 -0
- data/lib/qadmin/views/default/new.erb +12 -0
- data/lib/qadmin/views/default/show.erb +7 -0
- data/rails/init.rb +2 -1
- data/rails_generators/qadmin/qadmin_generator.rb +36 -19
- data/rails_generators/qadmin/templates/_form.html.erb +7 -0
- data/rails_generators/qadmin/templates/_instance.html.erb +8 -0
- data/rails_generators/qadmin/templates/controller.rb +1 -1
- data/rails_generators/qadmin/templates/functional_test.rb +102 -65
- data/rails_generators/qadmin/templates/images/{icon_up.gif → icon_asc.gif} +0 -0
- data/rails_generators/qadmin/templates/images/{icon_down.gif → icon_desc.gif} +0 -0
- data/rails_generators/qadmin/templates/layout.html.erb +45 -0
- data/test/test_helper.rb +8 -0
- data/test/test_qadmin_controller.rb +16 -6
- data/test/test_qadmin_generator.rb +17 -2
- data/test/test_qadmin_option_set.rb +86 -0
- metadata +46 -14
- data/rails_generators/qadmin/templates/shoulda_functional_test.rb +0 -33
- data/script/console +0 -10
- data/script/destroy +0 -14
- data/script/generate +0 -14
- data/script/txt2html +0 -71
data/lib/qadmin/helper.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
module Qadmin
|
2
2
|
module Helper
|
3
|
-
include ::Qadmin::Options
|
4
3
|
|
5
4
|
def fieldset(legend = nil, options = {}, &block)
|
6
|
-
concat(
|
7
|
-
|
8
|
-
|
5
|
+
concat(content_tag(:fieldset, options) do
|
6
|
+
html = ''
|
7
|
+
html << content_tag(:legend, legend) if legend
|
8
|
+
html << capture(&block)
|
9
|
+
html
|
9
10
|
end)
|
10
11
|
end
|
11
12
|
|
@@ -25,7 +26,8 @@ module Qadmin
|
|
25
26
|
:edit => link_to(image_tag('admin/icon_edit.png') + " Edit", general_link_attributes.merge(:action => 'edit', :id => obj)),
|
26
27
|
:show => link_to(image_tag('admin/icon_show.png') + " View", general_link_attributes.merge(:action => 'show', :id => obj)),
|
27
28
|
:destroy => link_to(image_tag('admin/icon_destroy.png') + " Delete", general_link_attributes.merge(:action => 'destroy', :id => obj), :confirm => 'Are you sure?', :method => :delete),
|
28
|
-
:ports => link_to(image_tag('admin/icon_export.png') + " Import/Export", general_link_attributes.merge(:action => 'ports'))
|
29
|
+
:ports => link_to(image_tag('admin/icon_export.png') + " Import/Export", general_link_attributes.merge(:action => 'ports')),
|
30
|
+
:export => link_to(image_tag('admin/icon_export.png') + " Export", general_link_attributes.merge(:action => 'export'))
|
29
31
|
}
|
30
32
|
|
31
33
|
control_sets = {
|
@@ -34,10 +36,11 @@ module Qadmin
|
|
34
36
|
:edit => [:index,:new,:show,:destroy],
|
35
37
|
:show => [:index,:new,:edit,:destroy]
|
36
38
|
}
|
37
|
-
|
38
|
-
control_set = (options[:
|
39
|
+
|
40
|
+
control_set = (options[:controls] || []).dup
|
41
|
+
control_set.unshift(control_sets[options[:for]]) if options[:for]
|
39
42
|
control_set << :ports if options[:ports]
|
40
|
-
controls =
|
43
|
+
controls = [control_set].flatten.collect {|c| control_links[c] }.compact
|
41
44
|
|
42
45
|
html = ""
|
43
46
|
html << %{<ul class="admin_controls">}
|
@@ -45,22 +48,41 @@ module Qadmin
|
|
45
48
|
if block_given?
|
46
49
|
html << capture(&block)
|
47
50
|
html << %{</ul>}
|
48
|
-
concat(html
|
51
|
+
concat(html)
|
49
52
|
else
|
50
53
|
html << %{</ul>}
|
51
54
|
html
|
52
55
|
end
|
53
56
|
end
|
54
57
|
|
55
|
-
def sortable_column_header(attribute_name, options = {})
|
56
|
-
|
58
|
+
def sortable_column_header(attribute_name, text = nil, options = {})
|
59
|
+
link_text = text || self.qadmin_configuration.column_headers[attribute_name] || attribute_name.to_s.humanize
|
60
|
+
return link_text unless qadmin_configuration.model_klass.can_query?
|
61
|
+
query_parser = model_restful_query_parser(options)
|
62
|
+
query_param = options[:query_param] || :query
|
63
|
+
logger.warn 'params:' + self.params[query_param].inspect
|
64
|
+
logger.warn 'parser:' + query_parser.inspect
|
65
|
+
sorting_this = query_parser.sort(attribute_name)
|
66
|
+
logger.warn "sorting #{attribute_name}:" + sorting_this.inspect
|
67
|
+
link_text << " #{image_tag("admin/icon_#{sorting_this.direction.downcase}.gif")}" if sorting_this
|
68
|
+
query_parser.set_sort(attribute_name, sorting_this ? sorting_this.next_direction : 'desc')
|
69
|
+
link_to link_text, self.params.dup.merge(query_param => query_parser.to_query_hash), :class => 'sortable_column_header'
|
70
|
+
end
|
71
|
+
|
72
|
+
def model_restful_query_parser(options = {})
|
73
|
+
query_param = options[:query_param] || :query
|
74
|
+
qadmin_configuration.model_klass.restful_query_parser(params[query_param], options)
|
57
75
|
end
|
58
76
|
|
59
|
-
|
60
77
|
def admin_table(collection, options = {})
|
61
78
|
html = '<table>'
|
62
79
|
html << '<tr>'
|
63
|
-
attributes = options[:attributes] ||
|
80
|
+
attributes = options[:attributes] || self.qadmin_configuration.display_columns
|
81
|
+
model_column_types = SuperHash.new
|
82
|
+
attributes.each do |attribute_name|
|
83
|
+
column = self.qadmin_configuration.model_klass.columns.detect {|c| c.name == attribute_name.to_s }
|
84
|
+
model_column_types[attribute_name] = column.type if column
|
85
|
+
end
|
64
86
|
attributes.each_with_index do |attribute, i|
|
65
87
|
html << (i == 0 ? '<th class="first_col">' : '<th>')
|
66
88
|
html << sortable_column_header(attribute)
|
@@ -75,10 +97,19 @@ module Qadmin
|
|
75
97
|
collection.each do |instance|
|
76
98
|
html << %{<tr id="#{dom_id(instance)}" #{alt_rows}>}
|
77
99
|
attributes.each_with_index do |attribute, i|
|
100
|
+
raw_value = instance.send(attribute)
|
101
|
+
value = case model_column_types[attribute]
|
102
|
+
when :boolean
|
103
|
+
yes?(raw_value)
|
104
|
+
when :text
|
105
|
+
truncate_words(raw_value, 10, ". . . #{link_to('More', send("#{model_instance_name}_path", instance))}")
|
106
|
+
else
|
107
|
+
h(raw_value)
|
108
|
+
end
|
78
109
|
if i == 0
|
79
|
-
html << %{<td class="first_col">#{link_to(
|
110
|
+
html << %{<td class="first_col">#{link_to(value, send("#{model_instance_name}_path", instance))}</td>}
|
80
111
|
else
|
81
|
-
html << %{<td>#{
|
112
|
+
html << %{<td>#{value}</td>}
|
82
113
|
end
|
83
114
|
end
|
84
115
|
html << %{<td>#{link_to(image_tag('admin/icon_show.png'), send("#{model_instance_name}_path", instance))}</td>}
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Qadmin
|
2
|
+
class OptionSet < Array
|
3
|
+
|
4
|
+
def initialize(*args)
|
5
|
+
first = args.shift
|
6
|
+
if first.is_a?(Array)
|
7
|
+
self.default = first
|
8
|
+
options = args.shift
|
9
|
+
else
|
10
|
+
options = first
|
11
|
+
end
|
12
|
+
if options.is_a?(Hash)
|
13
|
+
options.each do |option, value|
|
14
|
+
self.send("#{option}=", value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def current
|
20
|
+
[self].flatten.dup
|
21
|
+
end
|
22
|
+
|
23
|
+
[:exclude, :only, :default].each do |meth|
|
24
|
+
class_eval <<-EOT
|
25
|
+
def #{meth}
|
26
|
+
@#{meth} ||= []
|
27
|
+
end
|
28
|
+
|
29
|
+
def #{meth}=(#{meth})
|
30
|
+
@#{meth} = [#{meth}].flatten if #{meth}
|
31
|
+
reset_current
|
32
|
+
end
|
33
|
+
EOT
|
34
|
+
end
|
35
|
+
alias_method :except, :exclude
|
36
|
+
alias_method :except=, :exclude=
|
37
|
+
|
38
|
+
protected
|
39
|
+
def reset_current
|
40
|
+
new_current = if !only.empty?
|
41
|
+
only
|
42
|
+
else
|
43
|
+
default - exclude
|
44
|
+
end
|
45
|
+
self.replace(new_current)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Qadmin
|
2
|
+
module Overlay
|
3
|
+
|
4
|
+
def self.included(other)
|
5
|
+
other.module_eval do
|
6
|
+
helper_method :overlay?
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
def layout_or_overlay(options = {})
|
12
|
+
@_overlay = false
|
13
|
+
fallback_layout = options[:default] || 'admin'
|
14
|
+
if (options[:only] && !Array(options[:only]).include?(action_name)) || (options[:except] && Array(options[:except]).include?(action_name))
|
15
|
+
return fallback_layout
|
16
|
+
end
|
17
|
+
if params[:_overlay]
|
18
|
+
@_overlay = true
|
19
|
+
false
|
20
|
+
else
|
21
|
+
fallback_layout
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
def overlay?
|
27
|
+
@_overlay && @_overlay == true
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Qadmin
|
2
|
+
module PageTitles
|
3
|
+
|
4
|
+
def self.included(other)
|
5
|
+
other.module_eval do
|
6
|
+
include ControllerMethods
|
7
|
+
extend MacroMethods
|
8
|
+
helper_method :get_page_title, :set_page_title
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module MacroMethods
|
13
|
+
def page_title(add_title)
|
14
|
+
before_filter do |controller|
|
15
|
+
controller.set_page_title(add_title)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module ControllerMethods
|
21
|
+
|
22
|
+
def get_page_title(delimeter = ' : ')
|
23
|
+
@page_title ||= []
|
24
|
+
@page_title.join(delimeter)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def set_page_title(add_this)
|
29
|
+
get_page_title
|
30
|
+
@page_title << "#{add_this}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Qadmin
|
2
|
+
module Templates
|
3
|
+
|
4
|
+
def self.included(klass)
|
5
|
+
if klass.respond_to?(:helper_method)
|
6
|
+
klass.module_eval do
|
7
|
+
helper_method :template_for_section, :partial_for_section
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
def render_template_for_section(action = nil, options = {})
|
14
|
+
action ||= action_name
|
15
|
+
render({:template => template_for_section(action)}.merge(options))
|
16
|
+
end
|
17
|
+
|
18
|
+
def template_for_section(template_name, file_name = nil, options = {})
|
19
|
+
file_name ||= template_name
|
20
|
+
section_specific_template?(file_name, options) ? section_specific_template(template_name, options) : default_section_template(template_name, options)
|
21
|
+
end
|
22
|
+
|
23
|
+
def partial_for_section(partial_name, options = {})
|
24
|
+
template_for_section(partial_name, "_#{partial_name}", options)
|
25
|
+
end
|
26
|
+
|
27
|
+
def section_specific_template?(template_name, options = {})
|
28
|
+
template_exists?(section_specific_template(template_name, options))
|
29
|
+
end
|
30
|
+
|
31
|
+
def section_specific_template(template_name, options = {})
|
32
|
+
"#{current_section_name(options)}/#{template_name}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def default_section_template(template_name, options = {})
|
36
|
+
"default/#{template_name}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def current_section_name(options = {})
|
40
|
+
options[:section_name] ? options[:section_name] : (@section ? @section.name : controller_name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def template_exists?(template_path)
|
44
|
+
logger.info "Checking for template: #{template_path}"
|
45
|
+
self.view_paths.find_template(template_path)
|
46
|
+
rescue ActionView::MissingTemplate
|
47
|
+
logger.info "Template not found: #{template_path}"
|
48
|
+
false
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
File without changes
|
File without changes
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<h2><%= model_human_name %>: Edit</h2>
|
2
|
+
|
3
|
+
<%= admin_controls model_collection_name, :for => :edit %>
|
4
|
+
|
5
|
+
<%= error_messages_for model_instance_name %>
|
6
|
+
|
7
|
+
<% form_for(@model_instance, :html => {:multipart => qadmin_configuration.multipart_forms}) do |f| %>
|
8
|
+
<%= render :partial => 'form', :locals => {:f => f, model_instance_name.to_sym => @model_instance} %>
|
9
|
+
<p><%= f.submit "Update" %></p>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<%= admin_controls model_collection_name, :for => :edit %>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<h2><%= model_human_name.pluralize %></h2>
|
2
|
+
|
3
|
+
<%= admin_controls model_collection_name, :for => :index, :ports => qadmin_configuration.ports, :controls => qadmin_configuration.controls %>
|
4
|
+
|
5
|
+
<%= will_paginate(@model_collection) %>
|
6
|
+
<%= admin_table(@model_collection) %>
|
7
|
+
<%= will_paginate(@model_collection) %>
|
8
|
+
|
9
|
+
<%= admin_controls model_collection_name, :for => :index, :ports => qadmin_configuration.ports, :controls => qadmin_configuration.controls %>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<h2><%= model_human_name %>: New</h2>
|
2
|
+
|
3
|
+
<%= admin_controls model_collection_name, :for => :new %>
|
4
|
+
|
5
|
+
<%= error_messages_for model_instance_name %>
|
6
|
+
|
7
|
+
<% form_for(@model_instance, :html => {:multipart => qadmin_configuration.multipart_forms}) do |f| %>
|
8
|
+
<%= render :partial => 'form', :locals => {:f => f, model_instance_name.to_sym => @model_instance} %>
|
9
|
+
<p><%= f.submit "Create" %></p>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<%= admin_controls model_collection_name, :for => :new %>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<h2><%= model_human_name.pluralize %>: <%= @model_instance.to_s %></h2>
|
2
|
+
|
3
|
+
<%= admin_controls model_collection_name, :for => :show, :object => @model_instance %>
|
4
|
+
|
5
|
+
<%= render :partial => model_instance_name, :object => @model_instance %>
|
6
|
+
|
7
|
+
<%= admin_controls model_collection_name, :for => :show, :object => @model_instance %>
|
data/rails/init.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), '..', 'lib', 'qadmin')
|
2
2
|
|
3
3
|
ActionController::Base.send(:extend, Qadmin::Controller::Macros)
|
4
|
-
ActionView::Base.send(:include, Qadmin::Helper)
|
4
|
+
ActionView::Base.send(:include, Qadmin::Helper)
|
5
|
+
ActionView::Base.default_form_builder = Qadmin::FormBuilder
|
@@ -10,6 +10,8 @@ class QadminGenerator < Rails::Generator::NamedBase
|
|
10
10
|
alias_method :controller_file_name, :controller_singular_name
|
11
11
|
alias_method :controller_table_name, :controller_plural_name
|
12
12
|
|
13
|
+
attr_accessor :after_scaffold
|
14
|
+
|
13
15
|
def initialize(runtime_args, runtime_options = {})
|
14
16
|
super
|
15
17
|
|
@@ -23,6 +25,7 @@ class QadminGenerator < Rails::Generator::NamedBase
|
|
23
25
|
else
|
24
26
|
@controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
|
25
27
|
end
|
28
|
+
extract_options
|
26
29
|
end
|
27
30
|
|
28
31
|
def manifest
|
@@ -32,35 +35,41 @@ class QadminGenerator < Rails::Generator::NamedBase
|
|
32
35
|
m.class_collisions(controller_class_path, "#{controller_class_name}Controller")
|
33
36
|
|
34
37
|
# Controller, helper, views, and test directories.
|
35
|
-
|
36
|
-
|
38
|
+
if !after_scaffold
|
39
|
+
m.directory(File.join('app','controllers', controller_class_path))
|
40
|
+
m.directory(File.join('app', 'helpers', controller_class_path))
|
41
|
+
m.directory(File.join('public','images','admin'))
|
42
|
+
end
|
43
|
+
|
37
44
|
m.directory(File.join('app', 'views', controller_class_path, controller_file_name))
|
38
45
|
m.directory(File.join('test', 'functional', controller_class_path))
|
39
|
-
m.directory(File.join('public','images','admin'))
|
40
46
|
|
41
47
|
#copy form over too
|
42
|
-
m.template("_form.erb",File.join('app','views', controller_class_path, controller_file_name, "_form.erb"))
|
48
|
+
m.template("_form.html.erb",File.join('app','views', controller_class_path, controller_file_name, "_form.html.erb"))
|
49
|
+
m.template("_instance.html.erb", File.join('app','views', controller_class_path, controller_file_name, "_#{file_name}.html.erb"))
|
43
50
|
|
44
|
-
|
45
|
-
|
46
|
-
|
51
|
+
if !after_scaffold
|
52
|
+
# Layout and stylesheet.
|
53
|
+
m.template('layout.html.erb', File.join('app','views','layouts', "admin.erb"))
|
54
|
+
m.template('style.css', 'public/stylesheets/admin.css')
|
47
55
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
m.template('shoulda_functional_test.rb', File.join('test','functional', controller_class_path, "#{controller_file_name}_controller_test.rb"))
|
56
|
+
m.template('controller.rb', File.join('app','controllers', controller_class_path, "#{controller_file_name}_controller.rb"))
|
57
|
+
end
|
58
|
+
|
59
|
+
m.template('functional_test.rb', File.join('test','functional', controller_class_path, "#{controller_file_name}_controller_test.rb"))
|
53
60
|
|
54
|
-
|
61
|
+
if !after_scaffold
|
62
|
+
m.route_resources controller_file_name
|
55
63
|
|
56
|
-
|
57
|
-
|
58
|
-
|
64
|
+
# Copy Icons
|
65
|
+
Dir[File.join(File.dirname(__FILE__),'templates','images/*')].each do |image|
|
66
|
+
m.file File.join('images',File.basename(image)), File.join('public','images','admin',File.basename(image))
|
67
|
+
end
|
59
68
|
end
|
60
|
-
|
69
|
+
|
61
70
|
end
|
62
71
|
end
|
63
|
-
|
72
|
+
|
64
73
|
protected
|
65
74
|
# Override with your own usage banner.
|
66
75
|
def banner
|
@@ -71,7 +80,7 @@ class QadminGenerator < Rails::Generator::NamedBase
|
|
71
80
|
%w[ index show new edit ]
|
72
81
|
end
|
73
82
|
|
74
|
-
def model_name
|
83
|
+
def model_name
|
75
84
|
class_name.demodulize
|
76
85
|
end
|
77
86
|
|
@@ -91,4 +100,12 @@ class QadminGenerator < Rails::Generator::NamedBase
|
|
91
100
|
def ignore_attributes
|
92
101
|
%w{created_at updated_at}.push klass.protected_attributes
|
93
102
|
end
|
103
|
+
|
104
|
+
def add_options!(opts)
|
105
|
+
opts.on('--after-scaffold', "For use after generating a scaffold, generates the _form and the functional test") {|o| options[:after_scaffold] = o }
|
106
|
+
end
|
107
|
+
|
108
|
+
def extract_options
|
109
|
+
self.after_scaffold = options[:after_scaffold]
|
110
|
+
end
|
94
111
|
end
|