lolita 3.1.14 → 3.1.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/History.rdoc +17 -0
  2. data/README.rdoc +1 -0
  3. data/VERSION +1 -1
  4. data/app/controllers/lolita/info_controller.rb +3 -0
  5. data/app/helpers/components/lolita/configuration_component.rb +21 -0
  6. data/app/views/components/lolita/configuration/columns/_header.html.erb +2 -2
  7. data/app/views/components/lolita/configuration/columns/_row.html.erb +1 -1
  8. data/app/views/components/lolita/configuration/field/_display.html.erb +3 -1
  9. data/app/views/components/lolita/configuration/field/boolean/_display.html.erb +1 -1
  10. data/app/views/components/lolita/configuration/field/date/_display.html.erb +1 -1
  11. data/app/views/components/lolita/configuration/field/date_time/_display.html.erb +1 -1
  12. data/app/views/components/lolita/configuration/field/date_time/date/_display.html.erb +1 -1
  13. data/app/views/components/lolita/configuration/field/date_time/time/_display.html.erb +1 -1
  14. data/app/views/components/lolita/configuration/field/float/_display.html.erb +1 -1
  15. data/app/views/components/lolita/configuration/field/hidden/_display.html.erb +1 -0
  16. data/app/views/components/lolita/configuration/field/string/_display.html.erb +1 -1
  17. data/app/views/components/lolita/configuration/field/string/password/_display.html.erb +1 -1
  18. data/app/views/components/lolita/configuration/field/string/text/_display.html.erb +1 -1
  19. data/app/views/components/lolita/configuration/field/time/_display.html.erb +1 -1
  20. data/app/views/components/lolita/configuration/nested_form/_display.html.erb +13 -0
  21. data/app/views/components/lolita/configuration/nested_form/_fields.html.erb +13 -0
  22. data/app/views/components/lolita/configuration/tab/_display.html.erb +1 -1
  23. data/app/views/components/lolita/configuration/tab/_fields.html.erb +9 -7
  24. data/app/views/components/lolita/configuration/tab/_form.html.erb +8 -0
  25. data/app/views/components/lolita/configuration/tab/default/_display.html.erb +3 -11
  26. data/config/locales/en.yml +2 -0
  27. data/config/locales/lv.yml +4 -2
  28. data/lib/generators/templates/lolita.rb +5 -3
  29. data/lib/lolita.rb +1 -0
  30. data/lib/lolita/adapter/active_record.rb +2 -0
  31. data/lib/lolita/configuration/columns.rb +3 -1
  32. data/lib/lolita/configuration/field/hidden.rb +12 -0
  33. data/lib/lolita/configuration/helper.rb +24 -0
  34. data/lib/lolita/configuration/nested_form.rb +50 -4
  35. data/lib/lolita/configuration/tab.rb +26 -28
  36. data/lib/lolita/configuration/tab/content.rb +0 -1
  37. data/lib/lolita/controllers/component_helpers.rb +18 -0
  38. data/lib/lolita/controllers/internal_helpers.rb +7 -1
  39. data/lolita.gemspec +11 -3
  40. data/public/javascripts/lolita/main.js +10 -0
  41. data/public/stylesheets/lolita/PIE-custom.htc +87 -0
  42. data/public/stylesheets/lolita/PIE.htc +81 -0
  43. data/public/stylesheets/lolita/style.css +80 -7
  44. data/spec/configuration/tab_spec.rb +29 -10
  45. metadata +40 -32
  46. data/app/views/components/lolita/configuration/tab/_nested_form.html.erb +0 -16
data/History.rdoc CHANGED
@@ -1,3 +1,20 @@
1
+ === Version 3.1.15 / 2011-08-29
2
+ * Enhancements
3
+ * By default content tab excludes technical columns, like created_at, updated_at etc.
4
+ * It's possible to define and lolita uses nested fields in each tab through nested_fields_for.
5
+ * All fields (except array/habtm) uses #tab_form for field generation, that is current tab form.
6
+ * Lolita know how to vizualize habtm relation
7
+ * Added #component_locals method for views, so it is possible to access next component locals.
8
+ * Hidden field type added
9
+ * Nested forms updated to be more flexible
10
+
11
+ * Changes
12
+ * For unknown period field_sets are removed from use, it is possible to define them and use in your own views.
13
+
14
+ * Bug fixes
15
+ * /lolita now redirects to first existing mapping if any defined (Issue #14)
16
+ * component hooks fixed to use right local variable and detect right name of current component
17
+
1
18
  === Version 3.1.14 / 2011-08-24
2
19
  * Enhancements
3
20
  * request notifications moved to related methods in ::Controllers::InternalHelpers
data/README.rdoc CHANGED
@@ -31,6 +31,7 @@ This will make routes like
31
31
  /lolita/posts
32
32
  /lolita/posts/1/edit
33
33
  /lolita/posts/new
34
+ Or open /lolita and it will redirect to first available resource list view.
34
35
 
35
36
  For more detailed usage read Usage[https://github.com/ithouse/lolita/wiki/Usage] at wiki.
36
37
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.1.14
1
+ 3.1.15
@@ -2,6 +2,9 @@ class Lolita::InfoController < ApplicationController
2
2
  @@properties = []
3
3
 
4
4
  def index
5
+ if Lolita.mappings.any?
6
+ return redirect_to(lolita_resources_path(Lolita.mappings.values.first))
7
+ end
5
8
  render :layout => false
6
9
  end
7
10
 
@@ -0,0 +1,21 @@
1
+ module Components
2
+ module Lolita
3
+ module ConfigurationComponent
4
+ def link_to_remove_fields(name, f)
5
+ f.hidden_field(:_destroy) + link_to_function(name, "remove_fields(this)")
6
+ end
7
+
8
+ def link_to_add_fields(name, f, nested_form)
9
+ new_object = nested_form.klass.new
10
+ fields_content = ""
11
+ fields = f.fields_for(nested_form.name, new_object, :child_index => "new_#{nested_form.name}") do |builder|
12
+ self.tab_form(builder) do
13
+ fields_content = render_component(nested_form, :"fields")
14
+ end
15
+ end
16
+ link_to_function(name, "add_fields(this, \"#{nested_form.name}\", \"#{escape_javascript(fields_content)}\")")
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -1,9 +1,9 @@
1
1
  <thead>
2
2
  <tr>
3
- <%= render_component columns,:first_column_header %>
3
+ <%#= render_component columns,:first_column_header %>
4
4
  <% columns.each do |column| %>
5
5
  <%= render_component column,:header %>
6
6
  <% end %>
7
7
  <%= render_component columns,:last_column_header %>
8
8
  </tr>
9
- </thead>
9
+ </thead>
@@ -1,5 +1,5 @@
1
1
  <tr class="<%= index%2==0 ? "even" : "odd" %>">
2
- <%= render_component columns,:first,:record=>record %>
2
+ <%#= render_component columns,:first,:record=>record %>
3
3
  <% columns.each do |column| %>
4
4
  <%= render_component column, :record=>record %>
5
5
  <% end %>
@@ -1,5 +1,7 @@
1
1
  <div class="field" id="field_<%=field.__id__%>">
2
- <%= render_component *field.build(:name=>"/lolita/configuration/field", :state => :"label") %>
2
+ <% unless field.type == "hidden" %>
3
+ <%= render_component *field.build(:name=>"/lolita/configuration/field", :state => :"label") %>
4
+ <% end %>
3
5
  <div class="field-value" id="field_<%=field.__id__%>_value">
4
6
  <%= render_component *field.build %>
5
7
  </div>
@@ -1 +1 @@
1
- <%= check_box resource_name, field.name, field.html_options %>
1
+ <%= tab_form.check_box field.name, field.html_options %>
@@ -1 +1 @@
1
- <%= date_select resource_name, field.name, field.options, field.html_options %>
1
+ <%= tab_form.date_select field.name, field.options, field.html_options %>
@@ -1 +1 @@
1
- <%= datetime_select resource_name, field.name,field.options,field.html_options %>
1
+ <%= tab_form.datetime_select field.name,field.options,field.html_options %>
@@ -1 +1 @@
1
- <%= date_select resource_name, field.name,field.options,field.html_options %>
1
+ <%= tab_form.date_select field.name,field.options,field.html_options %>
@@ -1 +1 @@
1
- <%= time_select resource_name, field.name,field.options,field.html_options %>
1
+ <%= tab.form.time_select field.name,field.options,field.html_options %>
@@ -1 +1 @@
1
- <%= text_field resource_name, field.name,field.html_options %>
1
+ <%= tab_form.text_field field.name,field.html_options %>
@@ -0,0 +1 @@
1
+ <%=tab_form.hidden_field field.name, field.html_options%>
@@ -1,5 +1,5 @@
1
1
  <% if field.options[:native_type] == "text" %>
2
2
  <%= render_component :"lolita/configuration/field/string/text", :display, :field=>field %>
3
3
  <% else %>
4
- <%= text_field resource_name, field.name, field.html_options %>
4
+ <%= tab_form.text_field field.name, field.html_options %>
5
5
  <% end %>
@@ -1,3 +1,3 @@
1
1
  <div class="field-value" id="field_<%=field.__id__%>_value">
2
- <%= password_field resource_name, field.name,field.html_options %>
2
+ <%= tab_form.password_field field.name,field.html_options %>
3
3
  </div>
@@ -5,7 +5,7 @@
5
5
  <% end %>
6
6
  <% end %>
7
7
 
8
- <%= text_area resource_name, field.name, :rows=>(field.rows || 20), :"data-simple"=>field.simple %>
8
+ <%= tab_form.text_area field.name, :rows=>(field.rows || 20), :"data-simple"=>field.simple %>
9
9
  <% if @textarea_component_include_tinymce_once.nil? %>
10
10
  <script type="text/javascript">
11
11
  $(document).ready(
@@ -1 +1 @@
1
- <%= time_select resource_name, field.name %>
1
+ <%= tab_form.time_select field.name,field.options, field.html_options %>
@@ -0,0 +1,13 @@
1
+ <div class="nested_form" id=<%= "nested_form_#{nested_form.__id__}" %>>
2
+ <% unless nested_form.field_style == :normal %>
3
+ <%= label_tag nested_form.name %>
4
+ <% end %>
5
+ <%= tab_form.fields_for nested_form.name do |form| %>
6
+ <% tab_form(form) do %>
7
+ <%= render_component nested_form, :fields %>
8
+ <% end %>
9
+ <% end %>
10
+ <% if nested_form.expandable? %>
11
+ <p><%= link_to_add_fields ::I18n.t("lolita.nested_form.add", :resource_name => nested_form.klass.model_name.human.downcase), tab_form, nested_form %> </p>
12
+ <% end %>
13
+ </div>
@@ -0,0 +1,13 @@
1
+ <div class = "fields" >
2
+ <% nested_form.fields.each do |field| %>
3
+ <% if nested_form.field_style == :normal %>
4
+ <%= render_component "lolita/configuration/field", :display, :field => field %>
5
+ <% else %>
6
+ <%= render_component field %>
7
+ <% end %>
8
+ <% end %>
9
+ <% if nested_form.expandable? %>
10
+ <%= link_to_remove_fields I18n.t("lolita.shared.delete").downcase, tab_form %>
11
+ <% end %>
12
+ </div>
13
+
@@ -13,5 +13,5 @@
13
13
  }.compact.join("<br>") %>
14
14
  </p>
15
15
  <% end %>
16
- <%= render_component *tab.build %>
16
+ <%= render_component "lolita/configuration/tab", :form, :tab => tab %>
17
17
  </div>
@@ -1,7 +1,9 @@
1
- <% tab.fields_with_field_set do |fields_or_field,field_set| %>
2
- <% if field_set %>
3
- <%= render_component :"lolita/configuration/field_set", :display, :fields=>fields_or_field,:field_set=>field_set %>
4
- <% else %>
5
- <%= render_component :"lolita/configuration/field", :display,:field=>fields_or_field %>
6
- <% end %>
7
- <% end %>
1
+ <% tab.fields_in_groups do |group| %>
2
+ <% if group.first.nested_form %>
3
+ <%= render_component group.first.nested_form %>
4
+ <% else %>
5
+ <% group.each do |field| %>
6
+ <%= render_component "lolita/configuration/field", :display, :field => field %>
7
+ <% end %>
8
+ <% end %>
9
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <%
2
+ #This partial is useful for hooks. You don't need to hook in each tab, but you can hook here, that is common to all tabs
3
+ %>
4
+ <%= form_for resource, :url => "#",:html => {:multipart=>true, :id=>"tab-form-#{tab.__id__}",:method => resource.new_record? ? :post : :put} do |form| %>
5
+ <% self.tab_form = form %>
6
+ <%= render_component *tab.build %>
7
+ <% end %>
8
+ <% self.tab_form = nil %>
@@ -1,11 +1,3 @@
1
- <% #
2
- # FIXME: move to /tab_types/
3
- #
4
- %>
5
- <%= form_for resource, :url => "#",:html => {:multipart=>true, :id=>"tab-form-#{tab.__id__}",:method => resource.new_record? ? :post : :put} do |form| %>
6
- <% self.tab_form = form %>
7
- <div class="tab-content">
8
- <%= render_component :"lolita/configuration/tab", :fields, :tab=>tab, %>
9
- </div>
10
- <% end %>
11
- <% self.tab_form = nil %>
1
+ <div class="tab-content">
2
+ <%= render_component :"lolita/configuration/tab", :fields, :tab=>tab %>
3
+ </div>
@@ -6,6 +6,8 @@ en:
6
6
  log_out: Log out
7
7
  edit: Edit
8
8
  delete: Delete
9
+ nested_form:
10
+ add: "Add %{resource_name}"
9
11
  tabs:
10
12
  last_save: Last saved
11
13
  save: Save
@@ -4,8 +4,10 @@ lv:
4
4
  save_notice: Veiksmīgi saglabāts.
5
5
  save_alert: Saglabāšana neizdevās.
6
6
  log_out: Atteikties
7
- edit: Edit
8
- delete: Delete
7
+ edit: Labot
8
+ delete: Dzēst
9
+ nested_form:
10
+ add: "Pievienot %{resource_name}"
9
11
  tabs:
10
12
  last_save: Pēdējā saglabāšana
11
13
  save: Saglabāt
@@ -3,6 +3,7 @@ Lolita.setup do |config|
3
3
  # ==> User and authentication configuration
4
4
  # Add one or more of your user classes to Lolita
5
5
  # config.user_classes << MyUser
6
+ # config.authentication = :authenticate_user!
6
7
 
7
8
  # Define authentication for Lolita controllers.
8
9
  # Call some of your own methods
@@ -11,9 +12,10 @@ Lolita.setup do |config|
11
12
  # config.authentication={
12
13
  # current_user.is_a?(Admin) || current_user.has_role?(:admin)
13
14
  # }
14
-
15
+
15
16
  <% if defined?(Devise) %>
16
- config.user_classes << User
17
- config.authentication=:authenticate_user!
17
+ <% default_user_class = Devise.mappings.keys.first %>
18
+ config.user_classes << <%= default_user.to_s.camelize %>
19
+ config.authentication=:authenticate_<%= default_user_class %>!
18
20
  <% end %>
19
21
  end
data/lib/lolita.rb CHANGED
@@ -60,6 +60,7 @@ module Lolita
60
60
 
61
61
 
62
62
  module Configuration
63
+ autoload :Helper, 'lolita/configuration/helper'
63
64
  autoload :Factory, 'lolita/configuration/factory'
64
65
  autoload :Base, 'lolita/configuration/base'
65
66
  autoload :Column, 'lolita/configuration/column'
@@ -23,6 +23,8 @@ module Lolita
23
23
  end
24
24
 
25
25
  def reflect_on_association(name)
26
+ # TODO create association proxy for different dbi, so use of attributes will go through them
27
+ # like #klass, it's same for mongoid ar AR but it may change for others
26
28
  klass.reflect_on_association(name)
27
29
  end
28
30
 
@@ -28,7 +28,9 @@ module Lolita
28
28
  def generate!
29
29
  @columns.clear
30
30
  @dbi.fields.each_with_index{|field,index|
31
- @columns[index]=Lolita::Configuration::Column.new(@dbi,field)
31
+ unless Lolita::Configuration::Helper.tehnical_field?(field,@dbi)
32
+ @columns << Lolita::Configuration::Column.new(@dbi,field)
33
+ end
32
34
  }
33
35
  end
34
36
 
@@ -0,0 +1,12 @@
1
+ module Lolita
2
+ module Configuration
3
+ module Field
4
+ class Hidden < Lolita::Configuration::Field::Base
5
+ def initialize *args
6
+ @type="hidden"
7
+ super
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,24 @@
1
+ module Lolita
2
+ module Configuration
3
+ module Helper
4
+ class << self
5
+ # Return true if field name matches one of these:
6
+ # * created_at, updated_at, type
7
+ # * ends with _id, but there is no association that uses that field as foreign_key
8
+ # * there are uploader with that name
9
+ def tehnical_field?(db_field,dbi)
10
+ name = db_field[:name].to_s
11
+ if name.match(/^created_at|updated_at|type$/)
12
+ true
13
+ elsif name.match(/_id$/)
14
+ # FIXME move this to dbi association proxy
15
+ key_method = dbi.adapter_name == :active_record ? :association_foreign_key : :key
16
+ !dbi.associations.values.detect{|assoc| assoc.send(key_method) == name}
17
+ elsif dbi.klass.respond_to?(:uploaders)
18
+ dbi_klass.uploaders.keys.include?(name.to_sym)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,10 +1,24 @@
1
1
  module Lolita
2
2
  module Configuration
3
+ # Accept those attributes
4
+ # * <tt>:name</tt> - Name of nested relation, like :comments.
5
+ # * <tt>:field_style</tt> - Is fields rendered with as normal (with lable and staff) or like in table (:simple). Default :simple
6
+ # * <tt>:expandable</tt> - Show or not "Add new" and "Delete" links in form,
7
+ # by default, it is expandable if association macro is :many
8
+ # * <tt>:field_rejection_proc</tt> - Proc, that contains condition of how to reject field.
9
+ # By default form rejects all fields from parent tab that doesn't have current form as field nested_form
10
+ # ====Example
11
+ # form = Lolita::Configuration::NestedForm.new(Lolita::Configuration::Tab::Content.new,:comments)
12
+ # form.field_rejection_proc = Proc.new{|field|
13
+ # field.name.to_s.match(/_id$/)
14
+ # }
15
+ # # form exclude all fields that ends with _id
3
16
  class NestedForm
4
- @@last_nested_form=0
17
+ include Lolita::Builder
18
+ @@last_nested_form=0
5
19
 
6
- attr_reader :parent, :options
7
- attr_accessor :name
20
+ attr_reader :parent, :options, :field_style
21
+ attr_accessor :name, :expandable, :field_rejection_proc
8
22
 
9
23
  def initialize parent,name=nil, options ={}
10
24
  @parent=parent
@@ -12,8 +26,40 @@ module Lolita
12
26
  self.name=name || "nested_form_#{next_nested_form}"
13
27
  end
14
28
 
29
+ def field_style=(value)
30
+ allowed_values = [:normal,:simple]
31
+ raise ArgumentError, "Only #{allowed_values.inspect} are allowed" unless allowed_values.include?(value)
32
+ @field_style = value
33
+ end
34
+
35
+ def expandable?
36
+ @expandable == true || (@expandable == nil && macro == :many)
37
+ end
38
+
39
+ def dbi
40
+ @parent.dbi
41
+ end
42
+
43
+ def fields=(new_fields)
44
+ @fields = new_fields
45
+ end
46
+
15
47
  def fields
16
- self.parent.fields.reject{|f| f.nested_form!=self}
48
+ if @fields
49
+ @fields
50
+ elsif field_rejection_proc
51
+ self.parent.fields.reject(&field_rejection_proc)
52
+ else
53
+ self.parent.fields.reject{|f| f.nested_form!=self}
54
+ end
55
+ end
56
+
57
+ def klass
58
+ dbi.reflect_on_association(name).klass
59
+ end
60
+
61
+ def macro
62
+ dbi.association_macro(dbi.reflect_on_association(name))
17
63
  end
18
64
 
19
65
  private
@@ -84,20 +84,20 @@ module Lolita
84
84
  # See Lolita::Adapter classes for use of DB field method.
85
85
  def default_fields
86
86
  self.current_dbi.fields.each{|db_field|
87
- self.field(db_field)
87
+ self.field(db_field) unless Lolita::Configuration::Helper.tehnical_field?(db_field,self.current_dbi)
88
88
  }
89
89
  end
90
90
 
91
91
  # Add tab nested fields for <em>class_or_name</em> and <em>&block</em>
92
92
  # that will be evaluted in current tab instance.
93
93
  def nested_fields_for class_or_name, options ={},&block
94
- current_class=get_class(class_or_name)
95
- nested_form = Lolita::Configuration::NestedForm.new(self,current_class.to_s.downcase, options)
94
+ current_class = get_class(class_or_name)
95
+ nested_form = Lolita::Configuration::NestedForm.new(self,class_or_name, options)
96
96
  self.current_nested_form = nested_form
97
97
  @nested_forms << nested_form
98
- self.current_dbi=Lolita::DBI::Base.new(current_class)
98
+ self.current_dbi = Lolita::DBI::Base.new(current_class)
99
99
  self.instance_eval(&block)
100
- self.current_dbi=self.dbi
100
+ self.current_dbi = self.dbi
101
101
  self.current_nested_form = nil
102
102
  end
103
103
 
@@ -133,31 +133,25 @@ module Lolita
133
133
  }
134
134
  end
135
135
 
136
- # tab.field do
137
- # tab.fields_with_fieldset do |field,fieldset|
138
- # =field
139
- # end
140
-
141
- def fields_by_forms
142
- forms = []
143
- current_form = nil
144
- content = forms
145
- self.fields.each do |field|
146
- if field.nested_form
147
- if current_form != field.nested_form
148
- form_fields = []
149
- forms << form_fields
150
- content = form_fields
151
- end
152
- content << field
136
+ # Return fields in groups where in one group are fields for same model.
137
+ # It return all groups as array or yield each group when block is given.
138
+ def fields_in_groups()
139
+ groups = []
140
+ current_class = nil
141
+ self.fields.each do |group_field|
142
+
143
+ klass = group_field.dbi.klass
144
+ if current_class == klass
145
+ groups.last << group_field
146
+ else
147
+ groups << [group_field]
153
148
  end
149
+ current_class = klass
154
150
  end
155
151
  if block_given?
156
- forms.each do |form_or_field|
157
- yield form_or_field
158
- end
152
+ groups.each{|group| yield group }
159
153
  else
160
- forms
154
+ groups
161
155
  end
162
156
  end
163
157
 
@@ -194,8 +188,12 @@ module Lolita
194
188
  end
195
189
  end
196
190
 
197
- def get_class(str_or_sym_or_class)
198
- str_or_sym_or_class.is_a?(Class) ? str_or_sym_or_class : str_or_sym_or_class.to_s.camelize.constantize
191
+ def get_class(association_name)
192
+ if association_name.is_a?(Symbol) && assoc = self.current_dbi.reflect_on_association(association_name)
193
+ assoc.klass
194
+ else
195
+ raise ArgumentError, "Association named `#{association_name}` not found for #{self.current_dbi.klass}."
196
+ end
199
197
  end
200
198
 
201
199
  def validate