quirkey-qadmin 0.1.1 → 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 (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 %>