fullstack-admin 0.1.18 → 0.1.19

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 (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