qadmin 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. data/History.txt +9 -0
  2. data/LICENSE +20 -0
  3. data/Manifest.txt +52 -0
  4. data/PostInstall.txt +1 -0
  5. data/README.rdoc +39 -0
  6. data/Rakefile +31 -0
  7. data/init.rb +1 -0
  8. data/lib/qadmin.rb +20 -0
  9. data/lib/qadmin/assets/form_builder.rb +36 -0
  10. data/lib/qadmin/configuration.rb +48 -0
  11. data/lib/qadmin/controller.rb +139 -0
  12. data/lib/qadmin/form_builder.rb +23 -0
  13. data/lib/qadmin/helper.rb +128 -0
  14. data/lib/qadmin/option_set.rb +48 -0
  15. data/lib/qadmin/overlay.rb +31 -0
  16. data/lib/qadmin/page_titles.rb +34 -0
  17. data/lib/qadmin/templates.rb +52 -0
  18. data/lib/qadmin/views/content_forms/_attachments_form.erb +0 -0
  19. data/lib/qadmin/views/content_forms/_photos_form.erb +4 -0
  20. data/lib/qadmin/views/content_forms/_videos_form.erb +0 -0
  21. data/lib/qadmin/views/default/edit.erb +12 -0
  22. data/lib/qadmin/views/default/index.erb +9 -0
  23. data/lib/qadmin/views/default/new.erb +12 -0
  24. data/lib/qadmin/views/default/show.erb +7 -0
  25. data/rails/init.rb +5 -0
  26. data/rails_generators/qadmin/USAGE +5 -0
  27. data/rails_generators/qadmin/qadmin_generator.rb +111 -0
  28. data/rails_generators/qadmin/templates/_form.html.erb +7 -0
  29. data/rails_generators/qadmin/templates/_instance.html.erb +8 -0
  30. data/rails_generators/qadmin/templates/controller.rb +6 -0
  31. data/rails_generators/qadmin/templates/functional_test.rb +114 -0
  32. data/rails_generators/qadmin/templates/images/icon_asc.gif +0 -0
  33. data/rails_generators/qadmin/templates/images/icon_desc.gif +0 -0
  34. data/rails_generators/qadmin/templates/images/icon_destroy.png +0 -0
  35. data/rails_generators/qadmin/templates/images/icon_edit.png +0 -0
  36. data/rails_generators/qadmin/templates/images/icon_export.png +0 -0
  37. data/rails_generators/qadmin/templates/images/icon_find.png +0 -0
  38. data/rails_generators/qadmin/templates/images/icon_import.png +0 -0
  39. data/rails_generators/qadmin/templates/images/icon_list.png +0 -0
  40. data/rails_generators/qadmin/templates/images/icon_new.png +0 -0
  41. data/rails_generators/qadmin/templates/images/icon_next.gif +0 -0
  42. data/rails_generators/qadmin/templates/images/icon_prev.gif +0 -0
  43. data/rails_generators/qadmin/templates/images/icon_show.png +0 -0
  44. data/rails_generators/qadmin/templates/images/icon_sort.png +0 -0
  45. data/rails_generators/qadmin/templates/images/indicator_medium.gif +0 -0
  46. data/rails_generators/qadmin/templates/layout.html.erb +45 -0
  47. data/rails_generators/qadmin/templates/style.css +683 -0
  48. data/test/test_generator_helper.rb +29 -0
  49. data/test/test_helper.rb +83 -0
  50. data/test/test_qadmin_controller.rb +148 -0
  51. data/test/test_qadmin_generator.rb +76 -0
  52. data/test/test_qadmin_option_set.rb +86 -0
  53. metadata +162 -0
@@ -0,0 +1,9 @@
1
+ == 0.2.0 2009-03-20
2
+
3
+ * 1 major enhancement:
4
+ * First full release
5
+
6
+ == 0.0.1 2009-01-07
7
+
8
+ * 1 major enhancement:
9
+ * Initial release
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Aaron Quint, Quirkey NYC, LLC
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,52 @@
1
+ History.txt
2
+ LICENSE
3
+ Manifest.txt
4
+ PostInstall.txt
5
+ README.rdoc
6
+ Rakefile
7
+ init.rb
8
+ lib/qadmin.rb
9
+ lib/qadmin/assets/form_builder.rb
10
+ lib/qadmin/configuration.rb
11
+ lib/qadmin/controller.rb
12
+ lib/qadmin/form_builder.rb
13
+ lib/qadmin/helper.rb
14
+ lib/qadmin/option_set.rb
15
+ lib/qadmin/overlay.rb
16
+ lib/qadmin/page_titles.rb
17
+ lib/qadmin/templates.rb
18
+ lib/qadmin/views/content_forms/_attachments_form.erb
19
+ lib/qadmin/views/content_forms/_photos_form.erb
20
+ lib/qadmin/views/content_forms/_videos_form.erb
21
+ lib/qadmin/views/default/edit.erb
22
+ lib/qadmin/views/default/index.erb
23
+ lib/qadmin/views/default/new.erb
24
+ lib/qadmin/views/default/show.erb
25
+ rails/init.rb
26
+ rails_generators/qadmin/USAGE
27
+ rails_generators/qadmin/qadmin_generator.rb
28
+ rails_generators/qadmin/templates/_form.html.erb
29
+ rails_generators/qadmin/templates/_instance.html.erb
30
+ rails_generators/qadmin/templates/controller.rb
31
+ rails_generators/qadmin/templates/functional_test.rb
32
+ rails_generators/qadmin/templates/images/icon_asc.gif
33
+ rails_generators/qadmin/templates/images/icon_desc.gif
34
+ rails_generators/qadmin/templates/images/icon_destroy.png
35
+ rails_generators/qadmin/templates/images/icon_edit.png
36
+ rails_generators/qadmin/templates/images/icon_export.png
37
+ rails_generators/qadmin/templates/images/icon_find.png
38
+ rails_generators/qadmin/templates/images/icon_import.png
39
+ rails_generators/qadmin/templates/images/icon_list.png
40
+ rails_generators/qadmin/templates/images/icon_new.png
41
+ rails_generators/qadmin/templates/images/icon_next.gif
42
+ rails_generators/qadmin/templates/images/icon_prev.gif
43
+ rails_generators/qadmin/templates/images/icon_show.png
44
+ rails_generators/qadmin/templates/images/icon_sort.png
45
+ rails_generators/qadmin/templates/images/indicator_medium.gif
46
+ rails_generators/qadmin/templates/layout.html.erb
47
+ rails_generators/qadmin/templates/style.css
48
+ test/test_generator_helper.rb
49
+ test/test_helper.rb
50
+ test/test_qadmin_controller.rb
51
+ test/test_qadmin_generator.rb
52
+ test/test_qadmin_option_set.rb
@@ -0,0 +1 @@
1
+ For more information on qadmin, see http://code.quirkey.com/qadmin
@@ -0,0 +1,39 @@
1
+ = qadmin
2
+
3
+ http://github.com/quirkey/qadmin
4
+
5
+ == DESCRIPTION:
6
+
7
+ An [almost] one command solution for adding admin interfaces/resources to a Rails app.
8
+
9
+ == SYNOPSIS:
10
+
11
+ Qadmin is a partial extraction of 2+ years of building Rails admin systems. A lot of the code comes from a Rails plugin I wrote (private) called quirkey_tools.
12
+
13
+ The system consists currently of two parts: a generator, and a set of macros.
14
+
15
+ The generator is =~ the Rails resource generator, but instead of plopping all the code for the different standard resource actions into the controller and templates, it uses the #qadmin macro to include the standard resource actions.
16
+
17
+ For full details and usage please see the website at:
18
+
19
+ http://code.quirkey.com/qadmin
20
+
21
+ == INSTALL:
22
+
23
+ Qadmin can be installed as a gem or a plugin.
24
+
25
+ === As a gem
26
+
27
+ sudo gem install qadmin --source=http://gems.github.com
28
+
29
+ Then in your config/environment.rb
30
+
31
+ config.gem 'qadmin'
32
+
33
+ === As a plugin
34
+
35
+ ./script/plugin install git://github.com/quirkey/qadmin.git
36
+
37
+ == LICENSE:
38
+
39
+ MIT-LICENSE - See LICENSE
@@ -0,0 +1,31 @@
1
+ %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
+ require File.dirname(__FILE__) + '/lib/qadmin'
3
+
4
+ # Generate all the Rake tasks
5
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
+ $hoe = Hoe.new('qadmin', Qadmin::VERSION) do |p|
7
+ p.developer('Aaron Quint', 'aaron@quirkey.com')
8
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
+ p.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
10
+ p.rubyforge_name = 'quirkey'
11
+ p.summary = p.description = "An [almost] one command solution for adding admin interfaces/resources to a Rails app."
12
+ p.extra_deps = [
13
+ ['activesupport','>= 2.3.2'],
14
+ ['restful_query','>= 0.2.0']
15
+ ]
16
+ p.extra_dev_deps = [
17
+ ['newgem', ">= #{::Newgem::VERSION}"],
18
+ ['Shoulda', ">= 1.2.0"]
19
+ ]
20
+
21
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
22
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
23
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
24
+ p.rsync_args = '-av --delete --ignore-errors'
25
+ end
26
+
27
+ require 'newgem/tasks' # load /tasks/*.rake
28
+ Dir['tasks/**/*.rake'].each { |t| load t }
29
+
30
+ # TODO - want other tests/tasks run by default? Add them to the list
31
+ # task :default => [:spec, :features]
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), "rails", "init")
@@ -0,0 +1,20 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ unless defined?(ActiveSupport)
5
+ require 'active_support'
6
+ end
7
+
8
+ module Qadmin
9
+ VERSION = '0.2.0'
10
+ end
11
+
12
+ %w{
13
+ option_set
14
+ configuration
15
+ helper
16
+ overlay
17
+ page_titles
18
+ templates
19
+ controller
20
+ }.each {|lib| require "qadmin/#{lib}" }
@@ -0,0 +1,36 @@
1
+ module Qadmin
2
+ module Assets
3
+ module FormBuilder
4
+
5
+ def asset_selector(method, options = {})
6
+
7
+ id = "#{object_name}_#{method}"
8
+ form_name = "#{object_name}[#{method}]"
9
+
10
+ options.reverse_merge!({
11
+ :id => id,
12
+ :form_name => form_name,
13
+ :name => object_name,
14
+ :method => method,
15
+ :object => object,
16
+ :current => object.send(method),
17
+ :label => false,
18
+ :resize_type => object_name.tableize,
19
+ :multiple => true
20
+ })
21
+ @template.render(:partial => 'assets/asset_selector', :locals => options)
22
+ end
23
+
24
+ def asset_browser(id, options = {})
25
+ options.reverse_merge!({
26
+ :id => id,
27
+ :label => false,
28
+ :resize_type => ''
29
+ })
30
+ @template.render(:partial => 'shared/file_browser', :locals => options)
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,48 @@
1
+ module Qadmin
2
+ class Configuration
3
+
4
+ attr_accessor :controller_klass,
5
+ :model_name,
6
+ :model_instance_name,
7
+ :model_collection_name,
8
+ :model_human_name,
9
+ :available_actions,
10
+ :display_columns,
11
+ :column_headers,
12
+ :multipart_forms,
13
+ :default_scope,
14
+ :ports,
15
+ :controls
16
+
17
+ def initialize(options = {})
18
+ extract_model_from_options(options)
19
+ self.available_actions = Qadmin::OptionSet.new([:index, :show, :new, :create, :edit, :update, :destroy], options[:available_actions] || {})
20
+ self.display_columns = Qadmin::OptionSet.new(model_column_names, options[:display_columns] || {})
21
+ self.multipart_forms = options[:multipart_forms] || false
22
+ self.default_scope = options[:default_scope] || false
23
+ self.ports = options[:ports] || false
24
+ self.controls = options[:controls] || []
25
+ self.column_headers = HashWithIndifferentAccess.new(options[:column_headers] || {})
26
+ end
27
+
28
+ def model_klass
29
+ self.model_name.constantize
30
+ end
31
+
32
+ protected
33
+ def extract_model_from_options(options = {})
34
+ self.controller_klass = options[:controller_klass]
35
+ self.model_name = options[:model_name] || controller_klass.to_s.demodulize.gsub(/Controller/,'').singularize
36
+ self.model_instance_name = options[:model_instance_name] || model_name.underscore
37
+ self.model_collection_name = options[:model_collection_name] || model_instance_name.pluralize
38
+ self.model_human_name = options[:model_human_name] || model_instance_name.humanize
39
+ end
40
+
41
+ def model_column_names
42
+ model_klass.column_names
43
+ rescue
44
+ []
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,139 @@
1
+ module Qadmin
2
+ module Controller
3
+
4
+ module Macros
5
+
6
+
7
+ def qadmin(options = {})
8
+ self.cattr_accessor :qadmin_configuration
9
+ self.qadmin_configuration = Qadmin::Configuration.new({:controller_klass => self}.merge(options))
10
+ self.delegate :model_name, :model_klass, :model_collection_name, :model_instance_name, :model_human_name, :to => lambda { self.class.qadmin_configuration }
11
+ yield(self.qadmin_configuration) if block_given?
12
+ include Qadmin::Templates
13
+ include Qadmin::Overlay
14
+ self.append_view_path(File.join(File.dirname(__FILE__), 'views'))
15
+ define_admin_actions(qadmin_configuration.available_actions, options)
16
+ end
17
+
18
+ private
19
+
20
+ def define_admin_actions(actions, options = {})
21
+ config = self.qadmin_configuration
22
+ action_method_code = {
23
+ :index => %{
24
+ def index
25
+ logger.info 'Qadmin: Default /index'
26
+ scope = qadmin_configuration.model_klass
27
+ scope = scope.send(qadmin_configuration.default_scope) if qadmin_configuration.default_scope
28
+ scope = scope.restful_query(params[:query]) if #{config.model_name}.can_query?
29
+ @model_collection = @#{config.model_collection_name} = scope.paginate(:page => (params[:page] || 1), :per_page => (params[:per_page] || 25))
30
+ logger.warn 'controller params:' + params.inspect
31
+ respond_to do |format|
32
+ format.html { render_template_for_section }
33
+ format.xml
34
+ end
35
+ end
36
+ },
37
+ :show => %{
38
+ def show
39
+ logger.info 'Qadmin: Default /show'
40
+ @model_instance = @#{config.model_instance_name} = #{config.model_name}.find(params[:id])
41
+ respond_to do |format|
42
+ format.html { render_template_for_section }
43
+ format.xml
44
+ end
45
+ end
46
+ },
47
+ :new => %{
48
+ def new
49
+ logger.info 'Qadmin: Default /new'
50
+ @model_instance = @#{config.model_instance_name} = #{config.model_name}.new
51
+ respond_to do |format|
52
+ format.html { render_template_for_section }
53
+ format.xml { render :xml => @#{config.model_instance_name} }
54
+ end
55
+ end
56
+ },
57
+ :create => %{
58
+ def create
59
+ logger.info 'Qadmin: Default /create'
60
+ @model_instance = @#{config.model_instance_name} = #{config.model_name}.new(params[:#{config.model_instance_name}])
61
+ respond_to do |format|
62
+ if @#{config.model_instance_name}.save
63
+ flash[:message] = '#{config.model_human_name} was successfully created.'
64
+ format.html { redirect_to(#{config.model_instance_name}_path(@#{config.model_instance_name})) }
65
+ format.xml { render :xml => @#{config.model_instance_name}, :status => :created, :location => @#{config.model_instance_name} }
66
+ else
67
+ format.html { render_template_for_section('new') }
68
+ format.xml { render :xml => @#{config.model_instance_name}.errors }
69
+ end
70
+ end
71
+ end
72
+ },
73
+ :edit => %{
74
+ def edit
75
+ logger.info 'Qadmin: Default /edit'
76
+ @model_instance = @#{config.model_instance_name} = #{config.model_name}.find(params[:id])
77
+ respond_to do |format|
78
+ format.html { render_template_for_section }
79
+ format.xml { redirect_to #{config.model_instance_name}_path(@#{config.model_instance_name}) }
80
+ end
81
+ end
82
+ },
83
+ :update => %{
84
+ def update
85
+ logger.info 'Qadmin: Default /update'
86
+ @model_instance = @#{config.model_instance_name} = #{config.model_name}.find(params[:id])
87
+
88
+ respond_to do |format|
89
+ if @#{config.model_instance_name}.update_attributes(params[:#{config.model_instance_name}])
90
+ flash[:message] = '#{config.model_human_name} was successfully updated.'
91
+ format.html { redirect_to(#{config.model_instance_name}_path(@#{config.model_instance_name})) }
92
+ format.xml { head :ok }
93
+ else
94
+ format.html { render_template_for_section("edit") }
95
+ format.xml { render :xml => @#{config.model_instance_name}.errors }
96
+ end
97
+ end
98
+ end
99
+ },
100
+ :destroy => %{
101
+ def destroy
102
+ logger.info 'Qadmin: Default /destroy'
103
+ @model_instance = @#{config.model_instance_name} = #{config.model_name}.find(params[:id])
104
+ @#{config.model_instance_name}.destroy
105
+ flash[:message] = "#{config.model_human_name} \#{@#{config.model_instance_name}} was deleted"
106
+ respond_to do |format|
107
+ format.html { redirect_to(#{config.model_collection_name}_path) }
108
+ format.xml { head :ok }
109
+ end
110
+ end
111
+ }
112
+ }
113
+ action_code = actions.collect {|a| action_method_code[a.to_sym] }.join("\n")
114
+ helper_methods = %{
115
+ delegate :model_name, :model_klass, :model_collection_name, :model_instance_name, :model_human_name, :to => :qadmin_configuration
116
+ helper_method :qadmin_configuration, :model_name, :model_instance_name, :model_collection_name, :model_human_name, :available_actions
117
+ }
118
+ additional_methods = %{
119
+ def add_form
120
+ @origin_div = params[:from]
121
+ @num = params[:num]
122
+ @content_type = params[:content_type] || model_instance_name
123
+ obj = @origin_div.to_s.singularize
124
+ respond_to do |format|
125
+ format.js {
126
+ render :update do |page|
127
+ page.insert_html :bottom, @origin_div, :partial => "content_forms/\#{obj}_form", :locals => {obj => nil, :index => @num, :content_type => @content_type}
128
+ end
129
+ }
130
+ end
131
+ end
132
+ }
133
+ action_code = helper_methods << action_code << additional_methods
134
+ self.class_eval(action_code)
135
+ end
136
+ end
137
+
138
+ end
139
+ end
@@ -0,0 +1,23 @@
1
+ module Qadmin
2
+ class FormBuilder < ::ActionView::Helpers::FormBuilder
3
+ include Qadmin::Assets::FormBuilder
4
+
5
+ def content_form(form_name, options = {})
6
+ locals = options.reverse_merge({:content_type => object_name, :content => object, :f => self, :options => options})
7
+ @template.render(:partial => "content_forms/#{form_name}_form", :locals => locals)
8
+ end
9
+
10
+ def text_field_with_hint(method, options = {})
11
+ if object.send(method).blank?
12
+ options[:class] = if options[:class]
13
+ options[:class] << ' hinted'
14
+ else
15
+ 'hinted'
16
+ end
17
+ options[:value] = options.delete(:hint)
18
+ end
19
+ text_field(method, options)
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,128 @@
1
+ module Qadmin
2
+ module Helper
3
+
4
+ def fieldset(legend = nil, options = {}, &block)
5
+ concat(content_tag(:fieldset, options) do
6
+ html = ''
7
+ html << content_tag(:legend, legend) if legend
8
+ html << capture(&block)
9
+ html
10
+ end)
11
+ end
12
+
13
+ def admin_controls(name, options = {}, &block)
14
+ return if respond_to?(:overlay?) && overlay?
15
+ controller = options[:controller] || name.to_s.tableize
16
+ assumed_object = self.instance_variable_get "@#{name}"
17
+ obj = options[:object] || assumed_object || nil
18
+ parent = options[:parent] || false
19
+
20
+ parent_link_attributes = parent ? {parent.class.to_s.foreign_key => parent.id} : {}
21
+ general_link_attributes = {:controller => controller}.merge(parent_link_attributes)
22
+
23
+ control_links = {
24
+ :index => link_to(image_tag('admin/icon_list.png') + " Back to List", general_link_attributes.merge(:action => 'index')),
25
+ :new => link_to(image_tag('admin/icon_new.png') + " New", general_link_attributes.merge(:action => 'new')),
26
+ :edit => link_to(image_tag('admin/icon_edit.png') + " Edit", general_link_attributes.merge(:action => 'edit', :id => obj)),
27
+ :show => link_to(image_tag('admin/icon_show.png') + " View", general_link_attributes.merge(:action => 'show', :id => obj)),
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),
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'))
31
+ }
32
+
33
+ control_sets = {
34
+ :index => [:new],
35
+ :new => [:index],
36
+ :edit => [:index,:new,:show,:destroy],
37
+ :show => [:index,:new,:edit,:destroy]
38
+ }
39
+
40
+ control_set = (options[:controls] || []).dup
41
+ control_set.unshift(control_sets[options[:for]]) if options[:for]
42
+ control_set << :ports if options[:ports]
43
+ controls = [control_set].flatten.collect {|c| control_links[c] }.compact
44
+
45
+ html = ""
46
+ html << %{<ul class="admin_controls">}
47
+ controls.each {|control| html << li(control) }
48
+ if block_given?
49
+ html << capture(&block)
50
+ html << %{</ul>}
51
+ concat(html)
52
+ else
53
+ html << %{</ul>}
54
+ html
55
+ end
56
+ end
57
+
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)
75
+ end
76
+
77
+ def admin_table(collection, options = {})
78
+ html = '<table>'
79
+ html << '<tr>'
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
86
+ attributes.each_with_index do |attribute, i|
87
+ html << (i == 0 ? '<th class="first_col">' : '<th>')
88
+ html << sortable_column_header(attribute)
89
+ html << '</th>'
90
+ end
91
+ html << %{
92
+ <th>View</th>
93
+ <th>Edit</th>
94
+ <th>Delete</th>
95
+ </tr>
96
+ }
97
+ collection.each do |instance|
98
+ html << %{<tr id="#{dom_id(instance)}" #{alt_rows}>}
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
109
+ if i == 0
110
+ html << %{<td class="first_col">#{link_to(value, send("#{model_instance_name}_path", instance))}</td>}
111
+ else
112
+ html << %{<td>#{value}</td>}
113
+ end
114
+ end
115
+ html << %{<td>#{link_to(image_tag('admin/icon_show.png'), send("#{model_instance_name}_path", instance))}</td>}
116
+ html << %{<td>#{link_to(image_tag('admin/icon_edit.png'), send("edit_#{model_instance_name}_path", instance))}</td>}
117
+ html << %{<td>#{link_to(image_tag('admin/icon_destroy.png'), send("#{model_instance_name}_path", instance), :confirm => 'Are you sure?', :method => :delete)}</td>}
118
+ html << '</tr>'
119
+ end
120
+ html << '</table>'
121
+ end
122
+
123
+ def alt_rows
124
+ %{class="#{cycle('alt', '')}"}
125
+ end
126
+
127
+ end
128
+ end