fullstack-admin 0.1.18 → 0.1.19

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/Gemfile +2 -0
  2. data/Gemfile.lock +6 -0
  3. data/VERSION +1 -1
  4. data/app/assets/javascripts/support/forms.js.coffee +16 -1
  5. data/app/assets/stylesheets/support/forms.css +9 -0
  6. data/app/controllers/admin/base_controller.rb +33 -1
  7. data/app/controllers/admin/scaffold_controller.rb +63 -0
  8. data/app/helpers/admin_form_helper.rb +47 -1
  9. data/app/helpers/scaffold_helper.rb +19 -2
  10. data/app/inputs/boolean_input.rb +110 -1
  11. data/app/inputs/daterange_input.rb +1 -1
  12. data/app/inputs/datetime_input.rb +3 -7
  13. data/app/inputs/image_input.rb +5 -4
  14. data/{lib/generators/fullstack/admin/templates/root/app/views/admin/shared → app/views/admin}/_nav.html.erb +10 -6
  15. data/app/views/admin/base/_form.html.erb +13 -0
  16. data/app/views/admin/base/_index.html.erb +21 -0
  17. data/app/views/admin/base/edit.html.erb +13 -5
  18. data/app/views/admin/base/index.html.erb +24 -6
  19. data/app/views/layouts/admin.html.erb +1 -1
  20. data/config/initializers/formtastic_bootstrap_timeish_hack.rb +35 -0
  21. data/config/routes.rb +15 -0
  22. data/fullstack-admin.gemspec +15 -8
  23. data/lib/fullstack/admin.rb +4 -0
  24. data/lib/fullstack/admin/resources.rb +133 -0
  25. data/lib/generators/fullstack/admin/scaffold_generator.rb +4 -5
  26. data/lib/generators/fullstack/admin/templates/scaffold/{views/_filter.html.erb.tt → _filter.html.erb} +0 -0
  27. data/lib/generators/fullstack/admin/templates/scaffold/views/_form.html.erb.tt +3 -6
  28. data/lib/generators/fullstack/admin/templates/scaffold/views/_index.html.erb.tt +18 -17
  29. data/locales/en.yml +1 -0
  30. data/locales/it.yml +1 -0
  31. metadata +42 -9
  32. data/app/helpers/resources_helper.rb +0 -21
  33. data/app/inputs/checkbox_input.rb +0 -109
  34. data/app/inputs/datepicker_input.rb +0 -9
  35. data/app/inputs/photo_chooser_input.rb +0 -8
data/Gemfile CHANGED
@@ -13,6 +13,8 @@ gem "therubyracer"
13
13
  gem "meta_search"
14
14
  gem "plupload-rails"
15
15
  gem "fullstack"
16
+ gem 'bootstrap-datepicker-rails'
17
+ gem "select2-rails"
16
18
 
17
19
  group :development do
18
20
  gem "jeweler"
data/Gemfile.lock CHANGED
@@ -34,6 +34,8 @@ GEM
34
34
  auto_strip_attributes (2.0.2)
35
35
  activerecord (>= 3.0)
36
36
  bcrypt-ruby (3.0.1)
37
+ bootstrap-datepicker-rails (0.6.16)
38
+ railties (>= 3.0)
37
39
  bootstrap-helpers (0.1.1)
38
40
  rails
39
41
  bootstrap-wysihtml5-rails (0.3.0)
@@ -195,6 +197,8 @@ GEM
195
197
  net-ssh
196
198
  rails (~> 3.0)
197
199
  remotipart (1.0.2)
200
+ select2-rails (3.0.0)
201
+ thor (~> 0.14)
198
202
  sprockets (2.1.3)
199
203
  hike (~> 1.2)
200
204
  rack (~> 1.0)
@@ -218,6 +222,7 @@ PLATFORMS
218
222
  ruby
219
223
 
220
224
  DEPENDENCIES
225
+ bootstrap-datepicker-rails
221
226
  bootstrap-helpers
222
227
  bootstrap-wysihtml5-rails
223
228
  chosen-rails
@@ -231,4 +236,5 @@ DEPENDENCIES
231
236
  meta_search
232
237
  plupload-rails
233
238
  rails (~> 3.2)
239
+ select2-rails
234
240
  therubyracer
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.18
1
+ 0.1.19
@@ -17,12 +17,27 @@
17
17
  $(document).ready ->
18
18
 
19
19
  $("input[data-limit],textarea[data-limit]").limit()
20
- $("select:not([data-remote])").chosen()
20
+ $("select:not([data-remote]):not(.datetime-selector)").chosen()
21
21
 
22
22
  $("select[data-remote]").each ->
23
23
  $(this).ajaxChosen {method: "GET", url:$(this).data('remote'), dataType: 'json'}, (data) ->
24
24
  data
25
25
 
26
+ # $("select:not([data-remote]):not(.datetime-selector)").select2()
27
+ #
28
+ # $("select[data-remote]").each ->
29
+ # $(@).select2
30
+ # placeholder: $(@).data('placeholder')
31
+ # minimumInputLength: 3
32
+ # ajax:
33
+ # url: $(@).data('remote')
34
+ # dataType: "json"
35
+ # data: (term) ->
36
+ # q: term
37
+ #
38
+ # results: (data) ->
39
+ # results: data
40
+
26
41
  $("input.taglist").each ->
27
42
  taglist = $(this)
28
43
  autocomplete_url = taglist.data("autocomplete")
@@ -130,12 +130,14 @@ input.datepicker {
130
130
  background-position: 5px center;
131
131
  cursor: pointer;
132
132
  background-color: white;
133
+ width: auto;
133
134
  }
134
135
 
135
136
  a.close.datepicker-cancel {
136
137
  float: none;
137
138
  margin-left: -18px;
138
139
  margin-right: 5px;
140
+ vertical-align: top;
139
141
  }
140
142
 
141
143
  .daterange input.datepicker {
@@ -159,3 +161,10 @@ select,
159
161
  padding: 4px 0.5%;
160
162
  }
161
163
 
164
+ .datetime > .input > select, .time > .input > select, .date > .input > select {
165
+ width: auto;
166
+ }
167
+
168
+ .input {
169
+ margin-bottom: 18px;
170
+ }
@@ -20,5 +20,37 @@ class Admin::BaseController < ApplicationController
20
20
  end
21
21
  end
22
22
 
23
+ helper_method :singular_name,
24
+ :plural_name,
25
+ :resource_name,
26
+ :collection_name,
27
+ :current_resource_class,
28
+ :current_resource,
29
+ :current_collection
30
+
31
+
32
+ def current_resource_class
33
+ @current_resource_class ||= controller_name.singularize.camelize.constantize
34
+ end
35
+
36
+ def resource_name
37
+ current_resource_class.name.demodulize.underscore
38
+ end
39
+
40
+ def collection_name
41
+ resource_name.pluralize
42
+ end
43
+
44
+ alias :singular_name :resource_name
45
+ alias :plural_name :collection_name
46
+
47
+
48
+ def current_resource
49
+ instance_variable_get("@#{resource_name}")
50
+ end
51
+
52
+ def current_collection
53
+ instance_variable_get("@#{collection_name}")
54
+ end
23
55
 
24
- end
56
+ end
@@ -0,0 +1,63 @@
1
+ class Admin::ScaffoldController < Admin::BaseController
2
+ respond_to :html, :js
3
+
4
+ def index
5
+ @search = current_resource_class.search(params[:search])
6
+ set_collection @search.page(params[:page] || 1)
7
+ end
8
+
9
+ def new
10
+ set_object current_resource_class.new
11
+ end
12
+
13
+ def edit
14
+ end
15
+
16
+ def create
17
+ set_object current_resource_class.new(params[:"#{resource_name}"])
18
+
19
+ if current_resource.respond_to?(:author)
20
+ current_resource.author ||= current_user
21
+ end
22
+
23
+ current_resource.save
24
+ respond_with(current_resource)
25
+ end
26
+
27
+ def update
28
+ current_resource.attributes = params[:"#{resource_name}"]
29
+ current_resource.save
30
+ respond_with(current_resource)
31
+ end
32
+
33
+ def destroy
34
+ current_resource.destroy
35
+ respond_with(current_resource)
36
+ end
37
+
38
+ protected
39
+
40
+ # overrides checkin default
41
+ def fetch_object
42
+ if params[:id]
43
+ set_object(current_resource_class.find(params[:id]))
44
+ end
45
+ end
46
+
47
+ # helpers overrides
48
+ def current_resource_class
49
+ @current_resource_class ||= params[:_admin_resource_type].classify.constantize
50
+ end
51
+
52
+ private
53
+
54
+ def set_object(value)
55
+ instance_variable_set("@#{resource_name}", value)
56
+ end
57
+
58
+ def set_collection(value)
59
+ instance_variable_set("@#{collection_name}", value)
60
+ end
61
+
62
+
63
+ end
@@ -34,8 +34,54 @@ module AdminFormHelper
34
34
  options[:type] ||= !!options[:primary] ? :primary : nil
35
35
  @target.template.button((options.delete(:label) || default_label), options)
36
36
  end
37
+
38
+
39
+ def resource_inputs(res, *args)
40
+ model = res.class
41
+ options = args.extract_options!
42
+
43
+ only_attributes = options[:only] || []
44
+ except_attributes = options[:except] || model.protected_attributes.to_a + %W(created_at updated_at slug slugs lat lng)
45
+
46
+ only_attributes.map! {|a| :"#{a}"}
47
+ except_attributes.map! {|a| :"#{a}"}
48
+
49
+ columns = model.attribute_names.map! {|a| :"#{a}"}
50
+
51
+ if only_attributes.any?
52
+ columns = columns.select {|k| only_attributes.include?(k)}
53
+ elsif except_attributes.any?
54
+ columns = columns.delete_if {|k| except_attributes.include?(k)}
55
+ end
56
+
57
+
58
+ buff = ""
59
+
60
+ columns.each {|k|
61
+ k = "#{k}".gsub(/_ids?$/, "").to_sym
62
+ assoc = model.reflect_on_association(k)
63
+ if assoc && assoc.belongs_to?
64
+ buff << @target.input(k, :as => :select)
65
+ else
66
+ buff << @target.input(k)
67
+ end
68
+
69
+ }
70
+
71
+ buff.html_safe
72
+ end
73
+
74
+ def resource_submit(res)
75
+ @target.template.button (res.persisted? ? I18n.t('fullstack.admin.update', :default => "Update") : I18n.t('fullstack.admin.create', :default => "Create")),
76
+ :type => :primary,
77
+ :size => :large
78
+ end
37
79
 
38
- end
80
+ def actions(&block)
81
+ @target.template.form_actions(&block)
82
+ end
83
+
84
+ end # ~
39
85
 
40
86
  def admin_form_for(record_or_name_or_array, *args)
41
87
  options = args.extract_options!
@@ -29,5 +29,22 @@ module ScaffoldHelper
29
29
  def app_name
30
30
  Rails.application.class.to_s.split("::").first.underscore.humanize
31
31
  end
32
-
33
- end
32
+
33
+ def has_timestamps?(model)
34
+ model.columns_hash["created_at"]
35
+ end
36
+
37
+ def title_column(model)
38
+ ( model.column_names & %W(title name label browser_title seo_title seo_name key claim email) ).first
39
+ end
40
+
41
+
42
+ def skip_filter!
43
+ @skip_filter = true
44
+ end
45
+
46
+ def skip_filter
47
+ @skip_filter
48
+ end
49
+
50
+ end
@@ -1,3 +1,112 @@
1
- class BooleanInput < CheckboxInput
1
+ class BooleanInput
2
+
3
+
4
+ include Formtastic::Inputs::Base
5
+ include FormtasticBootstrap::Inputs::Base::Labelling
6
+ include FormtasticBootstrap::Inputs::Base::Wrapping
7
+ include FormtasticBootstrap::Inputs::Base::Errors
8
+ include FormtasticBootstrap::Inputs::Base::Hints
9
+
10
+
11
+ def wrapper_html_options
12
+ super.merge(:class => "mb1")
13
+ end
14
+
15
+
16
+ def to_html
17
+
18
+ generic_input_wrapping do
19
+
20
+ hidden_field_html <<
21
+ check_box_html
22
+ end
23
+
24
+
25
+ end
26
+
27
+ def hidden_field_html
28
+ template.hidden_field_tag(input_html_options[:name], unchecked_value, :id => nil, :disabled => input_html_options[:disabled] )
29
+ end
30
+
31
+ def label_with_nested_checkbox
32
+ builder.label(
33
+ method,
34
+ label_text_with_embedded_checkbox,
35
+ label_html_options
36
+ )
37
+ end
38
+
39
+ def label_html_options
40
+ prev = super
41
+ prev[:class] = prev[:class] - ['label']
42
+
43
+ input_html_options.merge(
44
+ prev.merge(
45
+ :id => nil,
46
+ :name => nil,
47
+ :for => input_html_options[:id]
48
+ )
49
+ )
50
+ end
51
+
52
+ def label_text_with_embedded_checkbox
53
+ check_box_html << "" << label_text
54
+ end
55
+
56
+ def check_box_html
57
+ template.check_box_tag("#{object_name}[#{method}]", checked_value, checked?, input_html_options)
58
+ end
59
+
60
+ def unchecked_value
61
+ options[:unchecked_value] || '0'
62
+ end
63
+
64
+ def checked_value
65
+ options[:checked_value] || '1'
66
+ end
67
+
68
+ def responds_to_global_required?
69
+ false
70
+ end
71
+
72
+ def input_html_options
73
+ {:name => input_html_options_name}.merge(super)
74
+ end
75
+
76
+ def input_html_options_name
77
+ if builder.options.key?(:index)
78
+ "#{object_name}[#{builder.options[:index]}][#{method}]"
79
+ else
80
+ "#{object_name}[#{method}]"
81
+ end
82
+ end
83
+
84
+ def checked?
85
+ if defined? ActionView::Helpers::InstanceTag
86
+ object && ActionView::Helpers::InstanceTag.check_box_checked?(object.send(method), checked_value)
87
+ else
88
+ object && boolean_checked?(object.send(method), checked_value)
89
+ end
90
+ end
91
+
92
+ private
93
+
94
+ def boolean_checked?(value, checked_value)
95
+ case value
96
+ when TrueClass, FalseClass
97
+ value
98
+ when NilClass
99
+ false
100
+ when Integer
101
+ value != 0
102
+ when String
103
+ value == checked_value
104
+ when Array
105
+ value.include?(checked_value)
106
+ else
107
+ value.to_i != 0
108
+ end
109
+ end
110
+
2
111
 
3
112
  end
@@ -3,7 +3,7 @@ class DaterangeInput < FormtasticBootstrap::Inputs::StringInput
3
3
  def to_html
4
4
  generic_input_wrapping do
5
5
  [ builder.text_field(gt_input_name, input_html_options(gt_input_name)),
6
- template.content_tag(:span, "-", :class => "seperator"),
6
+ template.content_tag(:span, "-", :class => "date-range-input-separator"),
7
7
  builder.text_field(lt_input_name, input_html_options(lt_input_name)),
8
8
  ].join("\n").html_safe
9
9
  end
@@ -5,14 +5,10 @@ class DatetimeInput
5
5
  include FormtasticBootstrap::Inputs::Base::Errors
6
6
  include FormtasticBootstrap::Inputs::Base::Hints
7
7
 
8
- # def wrapper_html_options
9
- # # super.merge(:class => "mb1")
10
- # end
11
-
12
8
  def to_html
13
- generic_input_wrapping do
14
- builder.datetime_select(method)
9
+ generic_input_wrapping do
10
+ builder.datetime_select(method, {}, {:class => "datetime-selector"})
15
11
  end
16
12
  end
17
13
 
18
- end
14
+ end
@@ -1,10 +1,11 @@
1
1
  class ImageInput < Formtastic::Inputs::FileInput
2
- include Base
2
+
3
3
 
4
4
  def to_html
5
- generic_input_wrapping do
6
- builder.file_field(method, input_html_options)
7
- end
5
+ raise "not implemented yet"
6
+ # generic_input_wrapping do
7
+ # builder.file_field(method, input_html_options)
8
+ # end
8
9
  end
9
10
 
10
11
  end
@@ -17,12 +17,16 @@
17
17
 
18
18
  <div class="tabbable tabs-left float right">
19
19
  <%= nav_list :class => "nav-tabs" do %>
20
- <!-- FULLSTACK_PLACEHOLDER -->
21
-
22
- <!-- Please do not delete the comment above.
23
- It is used by fullstack generators
24
- to attach new items to this menu.
25
- -->
20
+
21
+ <% Fullstack::Admin.resources.each do |rog| %>
22
+ <% if rog.type == :group %>
23
+ <%= nav_header rog.name %>
24
+
25
+ <% elsif rog.type == :resource %>
26
+ <%= nav_item rog.name, [:admin, rog.name] %>
27
+ <% end %>
28
+ <% end %>
29
+
26
30
  <% end %>
27
31
  </div>
28
32
 
@@ -0,0 +1,13 @@
1
+ <%= admin_form_for [:"admin", current_resource], :html => {:multipart => true} do |f| -%>
2
+
3
+ <%= f.errors %>
4
+
5
+ <%= f.inputs do %>
6
+ <%= f.resource_inputs(current_resource) %>
7
+ <% end -%>
8
+
9
+ <%= f.actions do %>
10
+ <%= f.resource_submit(current_resource) %>
11
+ <% end %>
12
+
13
+ <% end -%>
@@ -0,0 +1,21 @@
1
+ <% title_column_or_id = title_column(current_resource_class) || "id" %>
2
+
3
+ <% if thead -%>
4
+ <th><%= sort_link title_column_or_id %></th>
5
+
6
+ <% if has_timestamps?(current_resource_class) %>
7
+ <th><%= sort_link :created_at %></th>
8
+ <% end %>
9
+
10
+ <th><%= t('fullstack.admin.actions', :default => "Actions") %></th>
11
+ <% end -%>
12
+
13
+ <% if tbody -%>
14
+ <td><%= link_to (content.send(title_column_or_id)), [:edit, :admin, content] %></td>
15
+
16
+ <% if has_timestamps?(current_resource_class) %>
17
+ <td><%= l content.created_at.to_date, :format => :long %></td>
18
+ <% end %>
19
+
20
+ <td><%= default_collection_actions_for(content) %></td>
21
+ <% end -%>
@@ -1,8 +1,16 @@
1
- <% if content_for? :title -%>
2
- <div class="page-header"><h1><%= yield :title %></h1></div>
3
- <% else -%>
4
- <div class="page-header"><h1><%= t('fullstack.admin.edit', :default => "Edit") %> `<%= title_for(current_resource) %>`</h1></div>
5
- <% end -%>
1
+ <div class="page-header">
2
+ <h1>
3
+ <% if content_for? :title -%>
4
+ <%= yield :title %>
5
+ <% else -%>
6
+ <%= t('fullstack.admin.edit', :default => "Edit") %> `<%= title_for(current_resource) %>`
7
+ <% end -%>
8
+ </h1>
9
+ <div>
10
+ <i><%= current_resource.respond_to?(:updated_at) ? l(current_resource.updated_at, :format => :long) : "" %></i>
11
+ </div>
12
+ </div>
13
+
6
14
 
7
15
  <%= render :partial => 'form' %>
8
16
 
@@ -1,22 +1,22 @@
1
1
  <% if content_for? :title -%>
2
2
  <div class="page-header"><h1><%= yield :title %></h1></div>
3
3
  <% else -%>
4
- <div class="page-header"><h1><%= t(plural_name, :scope => "activerecord.models") %></h1></div>
4
+ <div class="page-header"><h1><%= t(collection_name, :scope => "activerecord.models") %></h1></div>
5
5
  <% end -%>
6
6
 
7
7
  <% if partial?('collection') %>
8
8
  <%= render :partial => "collection",
9
9
  :locals => {
10
- :collection => instance_variable_get("@#{controller_name}"),
11
- :"#{controller_name}" => instance_variable_get("@#{controller_name}")
10
+ :collection => current_collection,
11
+ :"#{controller_name}" => current_collection
12
12
  }
13
13
  %>
14
14
  <% else %>
15
15
 
16
16
  <div class="mb1">
17
- <% if subject.can_create?(controller_name) && controller.action_methods.include?("new") %>
17
+ <% if subject.can_create?(collection_name) && controller.action_methods.include?("new") %>
18
18
  <%= button t('fullstack.admin.new', :default => "New"),
19
- send("new_admin_#{controller_name.singularize}_path"),
19
+ send("new_admin_#{resource_name}_path"),
20
20
  :type => :primary, :icon => :plus, :icon_color => :white %>
21
21
  <% end %>
22
22
 
@@ -46,18 +46,36 @@
46
46
 
47
47
  <% content_for :aside do -%>
48
48
 
49
- <% if partial?('filter') %>
49
+ <% if (!@skip_filter) && (partial?('filter') || title_column(current_resource_class) || has_timestamps?(current_resource_class)) %>
50
50
  <div class="well">
51
51
  <div class="mb1">
52
52
  <h4><%= t('fullstack.admin.filter', :default => "Filter") %></h4>
53
53
  </div>
54
54
  <%= admin_form_for @search, :url => self.send("admin_#{collection_name}_path") , :html => {:method => :get} do |f| %>
55
+
56
+ <% if partial?('filter') %>
55
57
  <%= render :partial => "filter", :locals => {:f => f} %>
58
+ <% else %>
59
+ <%= f.inputs do %>
60
+
61
+ <% if tc = title_column(current_resource_class) %>
62
+ <%= f.input :"#{tc}_contains" %>
63
+ <% end %>
64
+
65
+ <% if has_timestamps?(current_resource_class) %>
66
+ <%= f.input :created_at, :as => :daterange %>
67
+ <% end %>
68
+
69
+ <% end %>
70
+
71
+ <% end %>
72
+
56
73
  <%= f.buttons do %>
57
74
  <%= f.commit_button t('fullstack.admin.filter', :default => "Filter") %>
58
75
  <% end %>
59
76
  <% end %>
60
77
  </div>
61
78
  <% end %>
79
+
62
80
  <% end -%>
63
81
 
@@ -9,7 +9,7 @@
9
9
  </head>
10
10
 
11
11
  <body>
12
- <%= render :partial => 'admin/shared/nav' %>
12
+ <%= render :partial => 'admin/nav' %>
13
13
 
14
14
  <%= navbar :fluid => true, :fixed => :top do %>
15
15
  <%= brand "#{app_name} Admin", admin_root_path %>
@@ -0,0 +1,35 @@
1
+ #timeish.rb
2
+ module FormtasticBootstrap
3
+ module Inputs
4
+ module Base
5
+ module Timeish
6
+
7
+ def date_input_html
8
+ current_value = @object.send(method)
9
+ opts = input_html_options.merge({ :size => 24,
10
+ :class => "datepicker",
11
+ :max => 10,
12
+ :readonly => 'readonly',
13
+ :value => current_value.respond_to?(:strftime) ? current_value.strftime("%Y-%m-%d") : ""
14
+ })
15
+ builder.text_field(method, opts)
16
+ end
17
+
18
+ def time_input_html
19
+ time_fragments.map do |fragment|
20
+ fragment_input_html(fragment, "mini")
21
+ end.join.html_safe
22
+ end
23
+
24
+ def fragment_input_html(fragment, klass)
25
+ klass ||= ""
26
+ klass += " datetime-selector"
27
+
28
+ opts = input_options.merge(:prefix => fragment_prefix, :field_name => fragment_name(fragment), :default => value, :include_blank => include_blank?)
29
+ template.send(:"select_#{fragment}", value, opts, input_html_options.merge(:id => fragment_id(fragment), :class => klass.strip))
30
+ end
31
+
32
+ end
33
+ end
34
+ end
35
+ end
data/config/routes.rb CHANGED
@@ -1,3 +1,18 @@
1
1
  Rails.application.routes.draw do
2
2
  mount Ckeditor::Engine => '/ckeditor'
3
+
4
+ namespace :admin do
5
+
6
+ Fullstack::Admin.resources.each do |r|
7
+ if r.type == :resource
8
+ if "Admin::#{r.name.to_s.pluralize.camelize}Controller".safe_constantize
9
+ resources r.name, :except => [:show]
10
+ else
11
+ resources r.name, :except => [:show], :controller => :scaffold, :_admin_resource_type => r.name
12
+ end
13
+ end
14
+ end
15
+
16
+ end
17
+
3
18
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "fullstack-admin"
8
- s.version = "0.1.18"
8
+ s.version = "0.1.19"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["mcasimir"]
12
- s.date = "2012-08-13"
12
+ s.date = "2012-08-15"
13
13
  s.description = "Administration interface framework for fullstack"
14
14
  s.email = "maurizio.cas@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -948,17 +948,14 @@ Gem::Specification.new do |s|
948
948
  "app/assets/stylesheets/support/uploads.css",
949
949
  "app/controllers/admin/base_controller.rb",
950
950
  "app/controllers/admin/responder.rb",
951
+ "app/controllers/admin/scaffold_controller.rb",
951
952
  "app/helpers/admin_form_helper.rb",
952
- "app/helpers/resources_helper.rb",
953
953
  "app/helpers/scaffold_helper.rb",
954
954
  "app/inputs/boolean_input.rb",
955
- "app/inputs/checkbox_input.rb",
956
- "app/inputs/datepicker_input.rb",
957
955
  "app/inputs/daterange_input.rb",
958
956
  "app/inputs/datetime_input.rb",
959
957
  "app/inputs/image_input.rb",
960
958
  "app/inputs/markup_input.rb",
961
- "app/inputs/photo_chooser_input.rb",
962
959
  "app/inputs/simple_markup_input.rb",
963
960
  "app/inputs/string_input.rb",
964
961
  "app/inputs/tag_list_input.rb",
@@ -976,17 +973,22 @@ Gem::Specification.new do |s|
976
973
  "app/models/roleable.rb",
977
974
  "app/models/suspendable.rb",
978
975
  "app/models/trackable.rb",
976
+ "app/views/admin/_nav.html.erb",
977
+ "app/views/admin/base/_form.html.erb",
978
+ "app/views/admin/base/_index.html.erb",
979
979
  "app/views/admin/base/destroy.js.coffee",
980
980
  "app/views/admin/base/edit.html.erb",
981
981
  "app/views/admin/base/index.html.erb",
982
982
  "app/views/admin/base/new.html.erb",
983
983
  "app/views/admin/base/update.js.coffee",
984
984
  "app/views/layouts/admin.html.erb",
985
+ "config/initializers/formtastic_bootstrap_timeish_hack.rb",
985
986
  "config/routes.rb",
986
987
  "fullstack-admin.gemspec",
987
988
  "lib/fullstack-admin.rb",
988
989
  "lib/fullstack/admin.rb",
989
990
  "lib/fullstack/admin/engine.rb",
991
+ "lib/fullstack/admin/resources.rb",
990
992
  "lib/generators/fullstack/admin/install_generator.rb",
991
993
  "lib/generators/fullstack/admin/locale_generator.rb",
992
994
  "lib/generators/fullstack/admin/scaffold_generator.rb",
@@ -995,11 +997,10 @@ Gem::Specification.new do |s|
995
997
  "lib/generators/fullstack/admin/templates/root/app/controllers/admin/dashboard_controller.rb",
996
998
  "lib/generators/fullstack/admin/templates/root/app/models/user.rb",
997
999
  "lib/generators/fullstack/admin/templates/root/app/views/admin/dashboard/show.html.erb",
998
- "lib/generators/fullstack/admin/templates/root/app/views/admin/shared/_nav.html.erb",
999
1000
  "lib/generators/fullstack/admin/templates/root/db/migrate/%migration_timestamp%_create_ckeditor_assets.rb",
1000
1001
  "lib/generators/fullstack/admin/templates/root/lib/support/user_subject.rb",
1002
+ "lib/generators/fullstack/admin/templates/scaffold/_filter.html.erb",
1001
1003
  "lib/generators/fullstack/admin/templates/scaffold/controller.rb",
1002
- "lib/generators/fullstack/admin/templates/scaffold/views/_filter.html.erb.tt",
1003
1004
  "lib/generators/fullstack/admin/templates/scaffold/views/_form.html.erb.tt",
1004
1005
  "lib/generators/fullstack/admin/templates/scaffold/views/_index.html.erb.tt",
1005
1006
  "locales/en.yml",
@@ -1049,6 +1050,8 @@ Gem::Specification.new do |s|
1049
1050
  s.add_runtime_dependency(%q<meta_search>, [">= 0"])
1050
1051
  s.add_runtime_dependency(%q<plupload-rails>, [">= 0"])
1051
1052
  s.add_runtime_dependency(%q<fullstack>, [">= 0"])
1053
+ s.add_runtime_dependency(%q<bootstrap-datepicker-rails>, [">= 0"])
1054
+ s.add_runtime_dependency(%q<select2-rails>, [">= 0"])
1052
1055
  s.add_development_dependency(%q<jeweler>, [">= 0"])
1053
1056
  else
1054
1057
  s.add_dependency(%q<rails>, ["~> 3.2"])
@@ -1064,6 +1067,8 @@ Gem::Specification.new do |s|
1064
1067
  s.add_dependency(%q<meta_search>, [">= 0"])
1065
1068
  s.add_dependency(%q<plupload-rails>, [">= 0"])
1066
1069
  s.add_dependency(%q<fullstack>, [">= 0"])
1070
+ s.add_dependency(%q<bootstrap-datepicker-rails>, [">= 0"])
1071
+ s.add_dependency(%q<select2-rails>, [">= 0"])
1067
1072
  s.add_dependency(%q<jeweler>, [">= 0"])
1068
1073
  end
1069
1074
  else
@@ -1080,6 +1085,8 @@ Gem::Specification.new do |s|
1080
1085
  s.add_dependency(%q<meta_search>, [">= 0"])
1081
1086
  s.add_dependency(%q<plupload-rails>, [">= 0"])
1082
1087
  s.add_dependency(%q<fullstack>, [">= 0"])
1088
+ s.add_dependency(%q<bootstrap-datepicker-rails>, [">= 0"])
1089
+ s.add_dependency(%q<select2-rails>, [">= 0"])
1083
1090
  s.add_dependency(%q<jeweler>, [">= 0"])
1084
1091
  end
1085
1092
  end
@@ -32,8 +32,12 @@ require "less-rails-bootstrap"
32
32
  require "meta_search"
33
33
  require "plupload-rails"
34
34
  require "fullstack"
35
+ require "bootstrap-datepicker-rails"
36
+ require "select2-rails"
35
37
 
36
38
  require 'fullstack/admin/engine'
39
+ require 'fullstack/admin/resources'
40
+
37
41
 
38
42
  module Fullstack
39
43
  module Admin
@@ -0,0 +1,133 @@
1
+ module Fullstack
2
+ module Admin
3
+
4
+ class Entity
5
+ # leaf?
6
+ # parent
7
+ # children
8
+ # entity_type
9
+
10
+ def leaf?
11
+ self.children.empty?
12
+ end
13
+
14
+ def traverse_top_down(&block)
15
+ res = block.call(self)
16
+ children.each do |c|
17
+ c.traverse_top_down(&block)
18
+ end
19
+ res
20
+ end
21
+ alias :each :traverse_top_down
22
+
23
+ def traverse_bottom_up(&block)
24
+ children.each do |c|
25
+ c.traverse_bottom_up(&block)
26
+ end
27
+ block.call(self)
28
+ end
29
+ alias :reverse_each :traverse_bottom_up
30
+
31
+
32
+ end
33
+
34
+ # =============
35
+ # = Resources =
36
+ # =============
37
+
38
+ class Resources < Entity
39
+
40
+ attr_accessor :children
41
+
42
+ def initialize
43
+ @children = []
44
+ end
45
+
46
+ def group(name)
47
+ g = Group.new(name)
48
+ @children << g
49
+ yield(g)
50
+ end
51
+
52
+ def resource(name)
53
+ @children << Resource.new(name)
54
+ end
55
+
56
+ def type
57
+ :resources
58
+ end
59
+
60
+ end
61
+
62
+ # Group
63
+ class Group < Entity
64
+ attr_accessor :children, :name
65
+
66
+ def initialize(name)
67
+ @name = "#{name}"
68
+ @children = []
69
+ end
70
+
71
+ def resource(name)
72
+ @children << Resource.new(name)
73
+ end
74
+
75
+ def type
76
+ :group
77
+ end
78
+
79
+ end
80
+
81
+
82
+ # Resource
83
+ class Resource < Entity
84
+
85
+ attr_accessor :name
86
+
87
+ def initialize(name)
88
+ if name.is_a?(Class)
89
+ name = name.name
90
+ end
91
+ @name = "#{name}"
92
+ end
93
+
94
+ def type
95
+ :resource
96
+ end
97
+
98
+ def children
99
+ @children ||= [].freeze
100
+ end
101
+
102
+ end
103
+
104
+ # Fullstack::Admin.resources do |admin|
105
+ #
106
+ # admin.group :website do |g|
107
+ # g.resource :pages
108
+ # g.resource :menus
109
+ # g.resource :settings
110
+ # end
111
+ #
112
+ # admin.group :contents do |g|
113
+ # g.resource :posts
114
+ # end
115
+ #
116
+ # admin.group :users do |g|
117
+ # g.resource :users
118
+ # end
119
+ #
120
+ # end
121
+
122
+ def resources
123
+ @resources ||= Resources.new
124
+ if block_given?
125
+ yield(@resources)
126
+ end
127
+ @resources
128
+ end
129
+
130
+ module_function :resources
131
+ end
132
+ end
133
+
@@ -37,12 +37,11 @@ module Fullstack
37
37
  def create_views
38
38
  if options[:views]
39
39
  directory('views', Rails.root.join('app', 'views', scope, plural_name))
40
+ if has_timestamps? || title_column
41
+ template "_filter.html.erb", Rails.root.join('app', 'views', scope, plural_name, "_filter.html.erb")
42
+ end
40
43
  end
41
44
  end
42
-
43
- # def generate_inputs
44
- # generate("inputs #{name.singularize} --scope #{scope}")
45
- # end
46
45
 
47
46
  def append_to_menu
48
47
  placeholder_text = "FULLSTACK_PLACEHOLDER"
@@ -87,7 +86,7 @@ str
87
86
  end
88
87
 
89
88
  def title_column
90
- ( model.column_names & %W(title name label claim) ).first
89
+ ( model.column_names & %W(title name label browser_title seo_title seo_name key claim email) ).first
91
90
  end
92
91
 
93
92
  def controller_class_name
@@ -3,14 +3,11 @@
3
3
  <%%= f.errors %>
4
4
 
5
5
  <%%= f.inputs do %>
6
-
6
+ <%%= f.resource_inputs(current_resource) %>
7
7
  <%% end -%>
8
8
 
9
- <%%= form_actions do %>
10
- <%%= button (current_resource.persisted? ? t('fullstack.admin.update', :default => "Update") : t('fullstack.admin.create', :default => "Create")),
11
- :type => :primary,
12
- :size => :large %>
9
+ <%%= f.actions do %>
10
+ <%%= f.resource_submit(current_resource) %>
13
11
  <%% end %>
14
12
 
15
-
16
13
  <%% end -%>
@@ -1,18 +1,19 @@
1
- <%% if thead -%>
2
- <th><%%= sort_link title_method_for(current_collection.klass) %></th>
3
- <% if has_timestamps? %>
4
- <th><%%= sort_link :created_at %></th>
5
- <% end %>
6
-
7
- <th><%%= t('fullstack.admin.actions', :default => "Actions") %></th>
8
- <%% end -%>
1
+ <% if thead -%>
2
+ <th><%= sort_link title_column(current_resource_class) %></th>
9
3
 
10
- <%% if tbody -%>
11
- <td><%%= link_to title_for(content), [:edit, :<%= scope %>, content] %></td>
12
-
13
- <% if has_timestamps? %>
14
- <td><%%= l content.created_at.to_date, :format => :long %></td>
15
- <% end %>
16
-
17
- <td><%%= default_collection_actions_for(content) %></td>
18
- <%% end -%>
4
+ <% if has_timestamps?(current_resource_class) %>
5
+ <th><%= sort_link :created_at %></th>
6
+ <% end %>
7
+
8
+ <th><%= t('fullstack.admin.actions', :default => "Actions") %></th>
9
+ <% end -%>
10
+
11
+ <% if tbody -%>
12
+ <td><%= link_to (content.send(title_column(current_resource_class))), [:edit, :admin, content] %></td>
13
+
14
+ <% if has_timestamps?(current_resource_class) %>
15
+ <td><%= l content.created_at.to_date, :format => :long %></td>
16
+ <% end %>
17
+
18
+ <td><%= default_collection_actions_for(content) %></td>
19
+ <% end -%>
data/locales/en.yml CHANGED
@@ -12,6 +12,7 @@ en:
12
12
  create: "Create"
13
13
  filter: "Filter"
14
14
  actions: "Actions"
15
+ info: "Info"
15
16
  are_you_sure: "Are you sure?"
16
17
 
17
18
  form:
data/locales/it.yml CHANGED
@@ -6,6 +6,7 @@ it:
6
6
  dashboard: "Dashboard"
7
7
  logout: "Logout"
8
8
  new: "Crea"
9
+ update: "Invia"
9
10
  show: "Visualizza"
10
11
  edit: "Modifica"
11
12
  delete: "Elimina"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fullstack-admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.18
4
+ version: 0.1.19
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-08-13 00:00:00.000000000 Z
12
+ date: 2012-08-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -219,6 +219,38 @@ dependencies:
219
219
  - - ! '>='
220
220
  - !ruby/object:Gem::Version
221
221
  version: '0'
222
+ - !ruby/object:Gem::Dependency
223
+ name: bootstrap-datepicker-rails
224
+ requirement: !ruby/object:Gem::Requirement
225
+ none: false
226
+ requirements:
227
+ - - ! '>='
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :runtime
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ none: false
234
+ requirements:
235
+ - - ! '>='
236
+ - !ruby/object:Gem::Version
237
+ version: '0'
238
+ - !ruby/object:Gem::Dependency
239
+ name: select2-rails
240
+ requirement: !ruby/object:Gem::Requirement
241
+ none: false
242
+ requirements:
243
+ - - ! '>='
244
+ - !ruby/object:Gem::Version
245
+ version: '0'
246
+ type: :runtime
247
+ prerelease: false
248
+ version_requirements: !ruby/object:Gem::Requirement
249
+ none: false
250
+ requirements:
251
+ - - ! '>='
252
+ - !ruby/object:Gem::Version
253
+ version: '0'
222
254
  - !ruby/object:Gem::Dependency
223
255
  name: jeweler
224
256
  requirement: !ruby/object:Gem::Requirement
@@ -1174,17 +1206,14 @@ files:
1174
1206
  - app/assets/stylesheets/support/uploads.css
1175
1207
  - app/controllers/admin/base_controller.rb
1176
1208
  - app/controllers/admin/responder.rb
1209
+ - app/controllers/admin/scaffold_controller.rb
1177
1210
  - app/helpers/admin_form_helper.rb
1178
- - app/helpers/resources_helper.rb
1179
1211
  - app/helpers/scaffold_helper.rb
1180
1212
  - app/inputs/boolean_input.rb
1181
- - app/inputs/checkbox_input.rb
1182
- - app/inputs/datepicker_input.rb
1183
1213
  - app/inputs/daterange_input.rb
1184
1214
  - app/inputs/datetime_input.rb
1185
1215
  - app/inputs/image_input.rb
1186
1216
  - app/inputs/markup_input.rb
1187
- - app/inputs/photo_chooser_input.rb
1188
1217
  - app/inputs/simple_markup_input.rb
1189
1218
  - app/inputs/string_input.rb
1190
1219
  - app/inputs/tag_list_input.rb
@@ -1202,17 +1231,22 @@ files:
1202
1231
  - app/models/roleable.rb
1203
1232
  - app/models/suspendable.rb
1204
1233
  - app/models/trackable.rb
1234
+ - app/views/admin/_nav.html.erb
1235
+ - app/views/admin/base/_form.html.erb
1236
+ - app/views/admin/base/_index.html.erb
1205
1237
  - app/views/admin/base/destroy.js.coffee
1206
1238
  - app/views/admin/base/edit.html.erb
1207
1239
  - app/views/admin/base/index.html.erb
1208
1240
  - app/views/admin/base/new.html.erb
1209
1241
  - app/views/admin/base/update.js.coffee
1210
1242
  - app/views/layouts/admin.html.erb
1243
+ - config/initializers/formtastic_bootstrap_timeish_hack.rb
1211
1244
  - config/routes.rb
1212
1245
  - fullstack-admin.gemspec
1213
1246
  - lib/fullstack-admin.rb
1214
1247
  - lib/fullstack/admin.rb
1215
1248
  - lib/fullstack/admin/engine.rb
1249
+ - lib/fullstack/admin/resources.rb
1216
1250
  - lib/generators/fullstack/admin/install_generator.rb
1217
1251
  - lib/generators/fullstack/admin/locale_generator.rb
1218
1252
  - lib/generators/fullstack/admin/scaffold_generator.rb
@@ -1221,11 +1255,10 @@ files:
1221
1255
  - lib/generators/fullstack/admin/templates/root/app/controllers/admin/dashboard_controller.rb
1222
1256
  - lib/generators/fullstack/admin/templates/root/app/models/user.rb
1223
1257
  - lib/generators/fullstack/admin/templates/root/app/views/admin/dashboard/show.html.erb
1224
- - lib/generators/fullstack/admin/templates/root/app/views/admin/shared/_nav.html.erb
1225
1258
  - lib/generators/fullstack/admin/templates/root/db/migrate/%migration_timestamp%_create_ckeditor_assets.rb
1226
1259
  - lib/generators/fullstack/admin/templates/root/lib/support/user_subject.rb
1260
+ - lib/generators/fullstack/admin/templates/scaffold/_filter.html.erb
1227
1261
  - lib/generators/fullstack/admin/templates/scaffold/controller.rb
1228
- - lib/generators/fullstack/admin/templates/scaffold/views/_filter.html.erb.tt
1229
1262
  - lib/generators/fullstack/admin/templates/scaffold/views/_form.html.erb.tt
1230
1263
  - lib/generators/fullstack/admin/templates/scaffold/views/_index.html.erb.tt
1231
1264
  - locales/en.yml
@@ -1266,7 +1299,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
1266
1299
  version: '0'
1267
1300
  segments:
1268
1301
  - 0
1269
- hash: 2117914633197908610
1302
+ hash: 2930398911678922489
1270
1303
  required_rubygems_version: !ruby/object:Gem::Requirement
1271
1304
  none: false
1272
1305
  requirements:
@@ -1,21 +0,0 @@
1
- module ResourcesHelper
2
-
3
- def singular_name
4
- controller_name.singularize
5
- end
6
- alias :resource_name :singular_name
7
-
8
- def plural_name
9
- controller_name
10
- end
11
- alias :collection_name :plural_name
12
-
13
- def current_resource
14
- instance_variable_get("@#{resource_name}")
15
- end
16
-
17
- def current_collection
18
- instance_variable_get("@#{collection_name}")
19
- end
20
-
21
- end
@@ -1,109 +0,0 @@
1
- class CheckboxInput
2
- include Formtastic::Inputs::Base
3
- include FormtasticBootstrap::Inputs::Base::Labelling
4
- include FormtasticBootstrap::Inputs::Base::Wrapping
5
- include FormtasticBootstrap::Inputs::Base::Errors
6
- include FormtasticBootstrap::Inputs::Base::Hints
7
-
8
-
9
- def wrapper_html_options
10
- super.merge(:class => "mb1")
11
- end
12
-
13
-
14
- def to_html
15
-
16
- generic_input_wrapping do
17
-
18
- hidden_field_html <<
19
- check_box_html
20
- end
21
-
22
-
23
- end
24
-
25
- def hidden_field_html
26
- template.hidden_field_tag(input_html_options[:name], unchecked_value, :id => nil, :disabled => input_html_options[:disabled] )
27
- end
28
-
29
- def label_with_nested_checkbox
30
- builder.label(
31
- method,
32
- label_text_with_embedded_checkbox,
33
- label_html_options
34
- )
35
- end
36
-
37
- def label_html_options
38
- prev = super
39
- prev[:class] = prev[:class] - ['label']
40
-
41
- input_html_options.merge(
42
- prev.merge(
43
- :id => nil,
44
- :name => nil,
45
- :for => input_html_options[:id]
46
- )
47
- )
48
- end
49
-
50
- def label_text_with_embedded_checkbox
51
- check_box_html << "" << label_text
52
- end
53
-
54
- def check_box_html
55
- template.check_box_tag("#{object_name}[#{method}]", checked_value, checked?, input_html_options)
56
- end
57
-
58
- def unchecked_value
59
- options[:unchecked_value] || '0'
60
- end
61
-
62
- def checked_value
63
- options[:checked_value] || '1'
64
- end
65
-
66
- def responds_to_global_required?
67
- false
68
- end
69
-
70
- def input_html_options
71
- {:name => input_html_options_name}.merge(super)
72
- end
73
-
74
- def input_html_options_name
75
- if builder.options.key?(:index)
76
- "#{object_name}[#{builder.options[:index]}][#{method}]"
77
- else
78
- "#{object_name}[#{method}]"
79
- end
80
- end
81
-
82
- def checked?
83
- if defined? ActionView::Helpers::InstanceTag
84
- object && ActionView::Helpers::InstanceTag.check_box_checked?(object.send(method), checked_value)
85
- else
86
- object && boolean_checked?(object.send(method), checked_value)
87
- end
88
- end
89
-
90
- private
91
-
92
- def boolean_checked?(value, checked_value)
93
- case value
94
- when TrueClass, FalseClass
95
- value
96
- when NilClass
97
- false
98
- when Integer
99
- value != 0
100
- when String
101
- value == checked_value
102
- when Array
103
- value.include?(checked_value)
104
- else
105
- value.to_i != 0
106
- end
107
- end
108
-
109
- end
@@ -1,9 +0,0 @@
1
- class DatepickerInput < FormtasticBootstrap::Inputs::StringInput
2
- def input_html_options
3
- options = super
4
- options[:class] = [options[:class], "datepicker"].compact.join(' ')
5
- options[:readonly] = 'readonly'
6
- options
7
- end
8
- end
9
-
@@ -1,8 +0,0 @@
1
- class PhotoChooserInput < FormtasticBootstrap::Inputs::HiddenInput
2
-
3
- def to_html
4
- template.after_current_form(:photo_chooser, :replace => true) << template.render(:partial => "support/photos/chooser")
5
- super << template.render(:partial => "support/photos/input")
6
- end
7
-
8
- end