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.
Files changed (42) hide show
  1. data/History.txt +5 -0
  2. data/LICENSE +20 -0
  3. data/Manifest.txt +20 -12
  4. data/PostInstall.txt +1 -1
  5. data/README.rdoc +4 -29
  6. data/Rakefile +5 -3
  7. data/lib/qadmin.rb +4 -2
  8. data/lib/qadmin/assets/form_builder.rb +36 -0
  9. data/lib/qadmin/configuration.rb +48 -0
  10. data/lib/qadmin/controller.rb +64 -34
  11. data/lib/qadmin/form_builder.rb +23 -0
  12. data/lib/qadmin/helper.rb +46 -15
  13. data/lib/qadmin/option_set.rb +48 -0
  14. data/lib/qadmin/overlay.rb +31 -0
  15. data/lib/qadmin/page_titles.rb +34 -0
  16. data/lib/qadmin/templates.rb +52 -0
  17. data/lib/qadmin/views/content_forms/_attachments_form.erb +0 -0
  18. data/lib/qadmin/views/content_forms/_photos_form.erb +4 -0
  19. data/lib/qadmin/views/content_forms/_videos_form.erb +0 -0
  20. data/lib/qadmin/views/default/edit.erb +12 -0
  21. data/lib/qadmin/views/default/index.erb +9 -0
  22. data/lib/qadmin/views/default/new.erb +12 -0
  23. data/lib/qadmin/views/default/show.erb +7 -0
  24. data/rails/init.rb +2 -1
  25. data/rails_generators/qadmin/qadmin_generator.rb +36 -19
  26. data/rails_generators/qadmin/templates/_form.html.erb +7 -0
  27. data/rails_generators/qadmin/templates/_instance.html.erb +8 -0
  28. data/rails_generators/qadmin/templates/controller.rb +1 -1
  29. data/rails_generators/qadmin/templates/functional_test.rb +102 -65
  30. data/rails_generators/qadmin/templates/images/{icon_up.gif → icon_asc.gif} +0 -0
  31. data/rails_generators/qadmin/templates/images/{icon_down.gif → icon_desc.gif} +0 -0
  32. data/rails_generators/qadmin/templates/layout.html.erb +45 -0
  33. data/test/test_helper.rb +8 -0
  34. data/test/test_qadmin_controller.rb +16 -6
  35. data/test/test_qadmin_generator.rb +17 -2
  36. data/test/test_qadmin_option_set.rb +86 -0
  37. metadata +46 -14
  38. data/rails_generators/qadmin/templates/shoulda_functional_test.rb +0 -33
  39. data/script/console +0 -10
  40. data/script/destroy +0 -14
  41. data/script/generate +0 -14
  42. data/script/txt2html +0 -71
@@ -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(content_tag_for(:fieldset, options) do
7
- content_tag(:legend, legend) if legend
8
- capture(&block)
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[:for] ? control_sets[options[:for]] : options[:controls])
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 = Array(control_set).collect {|c| control_links[c] }.compact
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,block.binding)
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] || model_klass.column_names
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(instance.send(attribute), send("#{model_instance_name}_path", instance))}</td>}
110
+ html << %{<td class="first_col">#{link_to(value, send("#{model_instance_name}_path", instance))}</td>}
80
111
  else
81
- html << %{<td>#{h(instance.send(attribute))}</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
@@ -0,0 +1,4 @@
1
+ <fieldset>
2
+ <legend>Photos</legend>
3
+ <%= f.asset_selector(:photos, options) %>
4
+ </fieldset>
@@ -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 %>
@@ -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
- m.directory(File.join('app','controllers', controller_class_path))
36
- m.directory(File.join('app', 'helpers', controller_class_path))
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
- # Layout and stylesheet.
45
- m.template('layout.erb', File.join('app','views','layouts', "admin.erb"))
46
- m.template('style.css', 'public/stylesheets/admin.css')
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
- m.template(
49
- 'controller.rb', File.join('app','controllers', controller_class_path, "#{controller_file_name}_controller.rb")
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
- m.route_resources controller_file_name
61
+ if !after_scaffold
62
+ m.route_resources controller_file_name
55
63
 
56
- # Copy Icons
57
- Dir[File.join(File.dirname(__FILE__),'templates','images/*')].each do |image|
58
- m.file File.join('images',File.basename(image)), File.join('public','images','admin',File.basename(image))
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
@@ -0,0 +1,7 @@
1
+ <%% fieldset do %>
2
+ <% attributes.each do |attribute| -%>
3
+ <% unless ignore_attributes.include?(attribute.name) -%>
4
+ <p><label><%= attribute.human_name %></label><%%= f.text_field :<%= attribute.name %> %></p>
5
+ <% end -%>
6
+ <% end -%>
7
+ <%% end %>