qadmin 0.2.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 (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