trestle 0.8.3 → 0.8.6

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 (171) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.travis.yml +10 -1
  4. data/Gemfile +4 -0
  5. data/README.md +1 -0
  6. data/app/assets/javascripts/trestle/admin.js +24 -0
  7. data/app/assets/javascripts/trestle/components/_confirmation.js +23 -0
  8. data/app/assets/javascripts/trestle/components/_datepicker.js +22 -0
  9. data/app/assets/javascripts/trestle/components/_dialog.js +107 -0
  10. data/app/assets/javascripts/trestle/components/_errors.js +11 -0
  11. data/app/assets/javascripts/trestle/components/_form.js +48 -0
  12. data/app/assets/javascripts/trestle/components/_gallery.js +27 -0
  13. data/app/assets/javascripts/trestle/components/_select.js +11 -0
  14. data/app/assets/javascripts/trestle/components/_sidebar.js +75 -0
  15. data/app/assets/javascripts/trestle/components/_table.js +21 -0
  16. data/app/assets/javascripts/trestle/components/_tabs.js +24 -0
  17. data/app/assets/javascripts/trestle/components/_tooltips.js +3 -0
  18. data/app/assets/javascripts/trestle/core/_contexts.js +13 -0
  19. data/app/assets/javascripts/trestle/core/_cookies.js +24 -0
  20. data/app/assets/javascripts/trestle/core/_events.js +39 -0
  21. data/app/assets/javascripts/trestle/core/_visit.js +10 -0
  22. data/app/assets/javascripts/trestle/custom.js +4 -0
  23. data/app/assets/stylesheets/trestle/components/_alerts.scss +28 -0
  24. data/app/assets/stylesheets/trestle/components/_buttons.scss +9 -0
  25. data/app/assets/stylesheets/trestle/components/_modal.scss +92 -0
  26. data/app/assets/stylesheets/trestle/components/_navigation.scss +80 -10
  27. data/app/assets/stylesheets/trestle/components/_sidebar.scss +1 -0
  28. data/app/assets/stylesheets/trestle/components/_table.scss +6 -0
  29. data/app/assets/stylesheets/trestle/core/_defaults.scss +5 -1
  30. data/app/controllers/trestle/application_controller.rb +5 -1
  31. data/app/helpers/trestle/dialog_helper.rb +7 -0
  32. data/app/helpers/trestle/form_helper.rb +8 -1
  33. data/app/helpers/trestle/format_helper.rb +48 -0
  34. data/app/helpers/trestle/hook_helper.rb +8 -3
  35. data/app/helpers/trestle/url_helper.rb +33 -11
  36. data/app/views/layouts/trestle/admin.html.erb +4 -4
  37. data/app/views/trestle/admin/index.html.erb +1 -1
  38. data/app/views/trestle/application/_alert.html.erb +2 -0
  39. data/app/views/trestle/application/_dialog.html.erb +36 -0
  40. data/app/views/trestle/application/_flash.html.erb +18 -4
  41. data/app/views/trestle/application/_tabs.html.erb +7 -1
  42. data/app/views/trestle/dashboard/index.html.erb +2 -2
  43. data/app/views/trestle/resource/_form.html.erb +1 -1
  44. data/app/views/trestle/resource/edit.html.erb +6 -6
  45. data/app/views/trestle/resource/index.html.erb +5 -2
  46. data/app/views/trestle/resource/new.html.erb +4 -4
  47. data/app/views/trestle/resource/show.html.erb +6 -6
  48. data/app/views/trestle/shared/_sidebar.html.erb +7 -4
  49. data/bower.json +2 -2
  50. data/config/locales/en.yml +38 -18
  51. data/config/locales/fr.rb +18 -0
  52. data/config/locales/fr.yml +69 -0
  53. data/config/locales/nl.rb +18 -0
  54. data/config/locales/nl.yml +67 -0
  55. data/config/locales/pl.rb +18 -0
  56. data/config/locales/pl.yml +70 -0
  57. data/config/locales/pt-BR.rb +18 -0
  58. data/config/locales/pt-BR.yml +69 -0
  59. data/gemfiles/rails-4.2.gemfile +14 -0
  60. data/gemfiles/rails-5.0.gemfile +14 -0
  61. data/gemfiles/rails-5.1.gemfile +14 -0
  62. data/gemfiles/rails-edge.gemfile +15 -0
  63. data/lib/generators/trestle/install/install_generator.rb +3 -3
  64. data/lib/generators/trestle/install/templates/custom.js +7 -0
  65. data/lib/generators/trestle/install/templates/trestle.rb.erb +9 -2
  66. data/lib/generators/trestle/resource/templates/admin.rb.erb +1 -1
  67. data/lib/trestle/adapters/active_record_adapter.rb +46 -20
  68. data/lib/trestle/adapters/adapter.rb +176 -0
  69. data/lib/trestle/adapters/sequel_adapter.rb +85 -0
  70. data/lib/trestle/adapters.rb +7 -64
  71. data/lib/trestle/admin/builder.rb +10 -2
  72. data/lib/trestle/admin.rb +14 -1
  73. data/lib/trestle/attribute.rb +14 -37
  74. data/lib/trestle/breadcrumb.rb +19 -0
  75. data/lib/trestle/configuration.rb +14 -3
  76. data/lib/trestle/display.rb +1 -1
  77. data/lib/trestle/form/automatic.rb +29 -21
  78. data/lib/trestle/form/builder.rb +4 -0
  79. data/lib/trestle/form/field.rb +2 -2
  80. data/lib/trestle/form/fields/check_box.rb +1 -1
  81. data/lib/trestle/form/fields/collection_select.rb +1 -1
  82. data/lib/trestle/form/fields/date_select.rb +1 -1
  83. data/lib/trestle/form/fields/datetime_select.rb +1 -1
  84. data/lib/trestle/form/fields/grouped_collection_select.rb +1 -1
  85. data/lib/trestle/form/fields/select.rb +2 -2
  86. data/lib/trestle/form/fields/tag_select.rb +1 -2
  87. data/lib/trestle/form/fields/time_select.rb +1 -1
  88. data/lib/trestle/form/fields/time_zone_select.rb +1 -1
  89. data/lib/trestle/form.rb +7 -3
  90. data/lib/trestle/model_name.rb +64 -0
  91. data/lib/trestle/navigation/group.rb +8 -0
  92. data/lib/trestle/navigation/item.rb +1 -1
  93. data/lib/trestle/options.rb +7 -5
  94. data/lib/trestle/reloader.rb +1 -1
  95. data/lib/trestle/resource/builder.rb +17 -1
  96. data/lib/trestle/resource/controller.rb +80 -18
  97. data/lib/trestle/resource.rb +26 -16
  98. data/lib/trestle/scope.rb +1 -1
  99. data/lib/trestle/table/actions_column.rb +21 -16
  100. data/lib/trestle/table/automatic.rb +5 -12
  101. data/lib/trestle/table/builder.rb +3 -2
  102. data/lib/trestle/table/column.rb +27 -45
  103. data/lib/trestle/table/row.rb +8 -2
  104. data/lib/trestle/table.rb +7 -1
  105. data/lib/trestle/version.rb +1 -1
  106. data/lib/trestle.rb +1 -0
  107. data/trestle.gemspec +5 -5
  108. data/vendor/assets/bower_components/trestle/flatpickr/dist/flatpickr.css +51 -26
  109. data/vendor/assets/bower_components/trestle/flatpickr/dist/flatpickr.js +349 -299
  110. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ar.js +5 -5
  111. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/bg.js +5 -5
  112. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/bn.js +5 -5
  113. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/cat.js +7 -7
  114. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/cs.js +7 -7
  115. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/cy.js +7 -7
  116. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/da.js +6 -6
  117. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/de.js +10 -10
  118. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/eo.js +11 -11
  119. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/es.js +7 -7
  120. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/et.js +11 -11
  121. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/fa.js +6 -6
  122. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/fi.js +7 -7
  123. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/fr.js +11 -11
  124. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/gr.js +13 -13
  125. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/he.js +5 -5
  126. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/hi.js +5 -5
  127. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/hr.js +6 -6
  128. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/hu.js +10 -10
  129. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/id.js +7 -7
  130. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/index.js +97 -0
  131. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/it.js +10 -10
  132. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ja.js +5 -5
  133. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ko.js +6 -6
  134. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/lt.js +10 -10
  135. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/lv.js +6 -6
  136. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/mk.js +8 -8
  137. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ms.js +7 -7
  138. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/my.js +7 -7
  139. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/nl.js +11 -11
  140. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/no.js +11 -11
  141. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/pa.js +5 -5
  142. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/pl.js +6 -6
  143. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/pt.js +6 -8
  144. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ro.js +7 -9
  145. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/ru.js +6 -8
  146. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/si.js +5 -7
  147. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/sk.js +8 -8
  148. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/sl.js +8 -10
  149. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/sq.js +5 -7
  150. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/sr.js +9 -10
  151. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/sv.js +8 -10
  152. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/th.js +10 -11
  153. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/tr.js +6 -8
  154. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/uk.js +6 -7
  155. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/vn.js +6 -8
  156. data/vendor/assets/bower_components/trestle/flatpickr/dist/l10n/zh.js +9 -11
  157. data/vendor/assets/bower_components/trestle/select2/dist/js/select2.full.js +90 -69
  158. metadata +58 -33
  159. data/app/assets/javascripts/trestle/_confirmation.js.coffee +0 -18
  160. data/app/assets/javascripts/trestle/_datepicker.js.coffee +0 -18
  161. data/app/assets/javascripts/trestle/_errors.js.coffee +0 -8
  162. data/app/assets/javascripts/trestle/_form.js.coffee +0 -4
  163. data/app/assets/javascripts/trestle/_gallery.js.coffee +0 -21
  164. data/app/assets/javascripts/trestle/_select.js.coffee +0 -7
  165. data/app/assets/javascripts/trestle/_sidebar.js.coffee +0 -45
  166. data/app/assets/javascripts/trestle/_table.js.coffee +0 -16
  167. data/app/assets/javascripts/trestle/_tabs.js.coffee +0 -9
  168. data/app/assets/javascripts/trestle/_tooltips.js.coffee +0 -2
  169. data/app/assets/javascripts/trestle/admin.js.coffee +0 -22
  170. data/app/assets/javascripts/trestle/custom.js.coffee +0 -4
  171. data/lib/generators/trestle/install/templates/custom.js.coffee +0 -7
@@ -2,28 +2,36 @@ module Trestle
2
2
  class Form
3
3
  class Automatic < Form
4
4
  def initialize(admin)
5
- @block = Proc.new do
6
- admin.default_attributes.each do |attribute|
7
- next if attribute.primary_key?
8
- next if attribute.inheritance_column?
9
- next if attribute.counter_cache?
10
-
11
- case attribute.type
12
- when :association
13
- options = attribute.association_class.all.map { |instance| [display(instance), instance.id] }
14
- prompt = "- Select #{admin.model.human_attribute_name(attribute.association_name)} -"
15
-
16
- select attribute.name, options, include_blank: prompt
17
- when :text
18
- text_area attribute.name
19
- when :date
20
- date_field attribute.name
21
- when :datetime
22
- datetime_field attribute.name
23
- when :boolean
24
- check_box attribute.name
5
+ super() do |instance|
6
+ admin.default_form_attributes.each do |attribute|
7
+ if attribute.array?
8
+ if [:string, :text].include?(attribute.type)
9
+ select attribute.name, nil, {}, { multiple: true, data: { tags: true, select_on_close: true }}
10
+ end
25
11
  else
26
- text_field attribute.name
12
+ case attribute.type
13
+ when :association
14
+ if attribute.polymorphic?
15
+ static_field attribute.name do
16
+ associated_instance = instance.public_send(attribute.association_name)
17
+ admin_link_to format_value(associated_instance), associated_instance
18
+ end
19
+ else
20
+ prompt = I18n.t("admin.form.select.prompt", default: "- Select %{attribute_name} -", attribute_name: admin.human_attribute_name(attribute.association_name))
21
+
22
+ select attribute.name, attribute.association_class.all, include_blank: prompt
23
+ end
24
+ when :text
25
+ text_area attribute.name
26
+ when :date
27
+ date_field attribute.name
28
+ when :datetime
29
+ datetime_field attribute.name
30
+ when :boolean
31
+ check_box attribute.name
32
+ else
33
+ text_field attribute.name
34
+ end
27
35
  end
28
36
  end
29
37
  end
@@ -9,6 +9,10 @@ module Trestle
9
9
  cattr_accessor :fields
10
10
  self.fields = {}
11
11
 
12
+ def errors(name)
13
+ object.errors[name].to_a
14
+ end
15
+
12
16
  def self.register(name, klass)
13
17
  rename_existing_helper_method(name)
14
18
  self.fields[name] = klass
@@ -13,8 +13,8 @@ module Trestle
13
13
  end
14
14
 
15
15
  def errors
16
- errors = builder.object.errors[name]
17
- errors += builder.object.errors[name.to_s.sub(/_id$/, '')] if name.to_s =~ /_id$/
16
+ errors = builder.errors(name)
17
+ errors += builder.errors(name.to_s.sub(/_id$/, '')) if name.to_s =~ /_id$/
18
18
  errors
19
19
  end
20
20
 
@@ -20,7 +20,7 @@ module Trestle
20
20
  content_tag(:label) do
21
21
  safe_join([
22
22
  builder.raw_check_box(name, options, checked_value, unchecked_value),
23
- options[:label] || admin.model.human_attribute_name(name)
23
+ options[:label] || admin.human_attribute_name(name)
24
24
  ], " ")
25
25
  end
26
26
  end
@@ -16,7 +16,7 @@ module Trestle
16
16
  end
17
17
 
18
18
  def default_html_options
19
- Trestle::Options.new(class: ["form-control"])
19
+ Trestle::Options.new(class: ["form-control"], data: { enable_select2: true })
20
20
  end
21
21
  end
22
22
  end
@@ -17,7 +17,7 @@ module Trestle
17
17
  end
18
18
 
19
19
  def default_html_options
20
- Trestle::Options.new(class: ["form-control"])
20
+ Trestle::Options.new(class: ["form-control"], data: { enable_select2: true })
21
21
  end
22
22
  end
23
23
  end
@@ -17,7 +17,7 @@ module Trestle
17
17
  end
18
18
 
19
19
  def default_html_options
20
- Trestle::Options.new(class: ["form-control"])
20
+ Trestle::Options.new(class: ["form-control"], data: { enable_select2: true })
21
21
  end
22
22
  end
23
23
  end
@@ -16,7 +16,7 @@ module Trestle
16
16
  end
17
17
 
18
18
  def default_html_options
19
- Trestle::Options.new(class: ["form-control"])
19
+ Trestle::Options.new(class: ["form-control"], data: { enable_select2: true })
20
20
  end
21
21
  end
22
22
  end
@@ -7,7 +7,7 @@ module Trestle
7
7
  def initialize(builder, template, name, choices=nil, options={}, html_options={}, &block)
8
8
  super(builder, template, name, options, &block)
9
9
 
10
- @choices = Choices.new(choices)
10
+ @choices = Choices.new(choices || builder.object.send(name))
11
11
  @html_options = default_html_options.merge(html_options)
12
12
  end
13
13
 
@@ -16,7 +16,7 @@ module Trestle
16
16
  end
17
17
 
18
18
  def default_html_options
19
- Trestle::Options.new(class: ["form-control"])
19
+ Trestle::Options.new(class: ["form-control"], data: { enable_select2: true })
20
20
  end
21
21
 
22
22
  # Allows an array of model instances (or a scope) to be
@@ -3,8 +3,7 @@ module Trestle
3
3
  module Fields
4
4
  class TagSelect < Select
5
5
  def initialize(builder, template, name, options={}, html_options={})
6
- choices = builder.object.send(name)
7
- super(builder, template, name, choices, options, html_options)
6
+ super(builder, template, name, nil, options, html_options)
8
7
  end
9
8
 
10
9
  def default_html_options
@@ -17,7 +17,7 @@ module Trestle
17
17
  end
18
18
 
19
19
  def default_html_options
20
- Trestle::Options.new(class: ["form-control"])
20
+ Trestle::Options.new(class: ["form-control"], data: { enable_select2: true })
21
21
  end
22
22
  end
23
23
  end
@@ -16,7 +16,7 @@ module Trestle
16
16
  end
17
17
 
18
18
  def default_html_options
19
- Trestle::Options.new(class: ["form-control"])
19
+ Trestle::Options.new(class: ["form-control"], data: { enable_select2: true })
20
20
  end
21
21
  end
22
22
  end
data/lib/trestle/form.rb CHANGED
@@ -8,10 +8,14 @@ module Trestle
8
8
  autoload :Fields
9
9
  autoload :Renderer
10
10
 
11
- attr_reader :block
11
+ attr_reader :options, :block
12
12
 
13
- def initialize(&block)
14
- @block = block
13
+ def initialize(options={}, &block)
14
+ @options, @block = options, block
15
+ end
16
+
17
+ def dialog?
18
+ options[:dialog] == true
15
19
  end
16
20
 
17
21
  def render(template, instance)
@@ -0,0 +1,64 @@
1
+ require "active_model/naming"
2
+
3
+ module Trestle
4
+ class ModelName
5
+ attr_reader :klass
6
+
7
+ delegate :downcase, :upcase, :titleize, :titlecase, to: :to_s
8
+
9
+ def initialize(klass)
10
+ @klass = klass
11
+ @name = klass.respond_to?(:model_name) ? klass.model_name : ActiveModel::Name.new(klass)
12
+ end
13
+
14
+ def ==(other)
15
+ other.is_a?(self.class) && klass == other.klass
16
+ end
17
+
18
+ def to_s
19
+ singular
20
+ end
21
+
22
+ def singular(options={})
23
+ human(default_singular, options)
24
+ end
25
+ alias_method :singularize, :singular
26
+
27
+ def plural(options={})
28
+ if i18n_supported? && i18n_pluralizations_available?
29
+ human(default_plural, { count: :many }.merge(options))
30
+ else
31
+ default_plural
32
+ end
33
+ end
34
+ alias_method :pluralize, :plural
35
+
36
+ protected
37
+ # Default singular version if it cannot be determined from i18n
38
+ def default_singular
39
+ @name.name.demodulize.titleize
40
+ end
41
+
42
+ # Default plural version if it cannot be determined from i18n
43
+ def default_plural
44
+ singular.pluralize(I18n.locale)
45
+ end
46
+
47
+ # Safely delegates to ActiveModel::Name#human, catching exceptions caused by missing pluralizations
48
+ def human(default, options={})
49
+ @name.human(options.merge(default: default))
50
+ rescue I18n::InvalidPluralizationData
51
+ default
52
+ end
53
+
54
+ # Checks if the model can be translated by ActiveModel
55
+ def i18n_supported?
56
+ klass.respond_to?(:lookup_ancestors) && klass.respond_to?(:i18n_scope)
57
+ end
58
+
59
+ # Checks if multiple pluralization forms (e.g. zero/one/few/many/other) are available from i18n
60
+ def i18n_pluralizations_available?
61
+ @name.human(count: nil).is_a?(Hash)
62
+ end
63
+ end
64
+ end
@@ -40,6 +40,10 @@ module Trestle
40
40
  def label
41
41
  I18n.t("admin.navigation.groups.#{name}", default: name.to_s.titlecase)
42
42
  end
43
+
44
+ def id
45
+ name.to_s.parameterize
46
+ end
43
47
  end
44
48
 
45
49
  class NullGroup
@@ -59,6 +63,10 @@ module Trestle
59
63
  NullGroup.hash
60
64
  end
61
65
 
66
+ def id
67
+ nil
68
+ end
69
+
62
70
  def <=>(other)
63
71
  -1
64
72
  end
@@ -40,7 +40,7 @@ module Trestle
40
40
  end
41
41
 
42
42
  def label
43
- I18n.t("admin.navigation.items.#{name}", default: name.to_s.titlecase)
43
+ options[:label] || I18n.t("admin.navigation.items.#{name}", default: name.to_s.titlecase)
44
44
  end
45
45
 
46
46
  def icon
@@ -4,13 +4,15 @@ module Trestle
4
4
  self[hash]
5
5
  end
6
6
 
7
- def merge(other)
8
- dup.merge!(other)
7
+ def merge(other, &block)
8
+ dup.merge!(other, &block)
9
9
  end
10
10
 
11
- def merge!(other)
12
- deep_merge!(other || {}) do |key, v1, v2|
13
- if v1.is_a?(Array)
11
+ def merge!(other, &block)
12
+ super(other || {}) do |key, v1, v2|
13
+ if v1.is_a?(Hash) && v2.is_a?(Hash)
14
+ v1.merge(v2, &block)
15
+ elsif v1.is_a?(Array)
14
16
  v1 + Array(v2)
15
17
  else
16
18
  v2
@@ -34,7 +34,7 @@ module Trestle
34
34
  end
35
35
 
36
36
  def load_paths
37
- ActiveSupport::Dependencies.autoload_paths.grep(/\/app\/admin\Z/)
37
+ Trestle.config.load_paths.map { |path| path.respond_to?(:call) ? path.call : path }.flatten.map(&:to_s)
38
38
  end
39
39
 
40
40
  private
@@ -14,13 +14,21 @@ module Trestle
14
14
  admin.adapter = adapter
15
15
  end
16
16
 
17
+ def remove_action(*actions)
18
+ actions.each do |action|
19
+ controller.remove_possible_method(action.to_sym)
20
+ admin.actions.delete(action.to_sym)
21
+ end
22
+ end
23
+
17
24
  def collection(&block)
18
25
  admin.collection = block
19
26
  end
20
27
 
21
- def instance(&block)
28
+ def find_instance(&block)
22
29
  admin.find_instance = block
23
30
  end
31
+ alias instance find_instance
24
32
 
25
33
  def build_instance(&block)
26
34
  admin.build_instance = block
@@ -82,6 +90,14 @@ module Trestle
82
90
 
83
91
  admin.scopes[name] = Scope.new(admin, name, options, &(scope || block))
84
92
  end
93
+
94
+ def return_to(options={}, &block)
95
+ actions = options.key?(:on) ? Array(options[:on]) : [:create, :update, :destroy]
96
+
97
+ actions.each do |action|
98
+ admin.return_locations[action.to_sym] = block
99
+ end
100
+ end
85
101
  end
86
102
  end
87
103
  end
@@ -1,28 +1,60 @@
1
1
  module Trestle
2
2
  class Resource
3
3
  class Controller < Admin::Controller
4
+ after_action :set_trestle_location_header
5
+
4
6
  def index
5
7
  self.collection = admin.prepare_collection(params)
8
+
9
+ respond_to do |format|
10
+ format.html
11
+ format.json { render json: collection }
12
+ format.js
13
+ end
6
14
  end
7
15
 
8
16
  def new
9
- self.instance = admin.build_instance
17
+ self.instance = admin.build_instance({}, params)
18
+
19
+ respond_to do |format|
20
+ format.html
21
+ format.json { render json: instance }
22
+ format.js
23
+ end
10
24
  end
11
25
 
12
26
  def create
13
- self.instance = admin.build_instance(admin.permitted_params(params))
27
+ self.instance = admin.build_instance(admin.permitted_params(params), params)
14
28
 
15
29
  if admin.save_instance(instance)
16
- flash[:message] = flash_message("success.create", default: "The %{model_name} was successfully created.")
17
- redirect_to action: :show, id: admin.to_param(instance)
30
+ respond_to do |format|
31
+ format.html do
32
+ flash[:message] = flash_message("success.create", default: "The %{lowercase_model_name} was successfully created.")
33
+ redirect_to(admin.return_location(:create, instance), turbolinks: false)
34
+ end
35
+ format.json { render json: instance, status: :created, location: { action: :show, id: admin.to_param(instance) } }
36
+ format.js
37
+ end
18
38
  else
19
- flash.now[:error] = flash_message("failure.create", default: "Please correct the errors below.")
20
- render "new"
39
+ respond_to do |format|
40
+ format.html do
41
+ flash.now[:error] = flash_message("failure.create", default: "Please correct the errors below.")
42
+ render "new", status: :unprocessable_entity
43
+ end
44
+ format.json { render json: instance.errors, status: :unprocessable_entity }
45
+ format.js
46
+ end
21
47
  end
22
48
  end
23
49
 
24
50
  def show
25
51
  self.instance = admin.find_instance(params)
52
+
53
+ respond_to do |format|
54
+ format.html
55
+ format.json { render json: instance }
56
+ format.js
57
+ end
26
58
  end
27
59
 
28
60
  def edit
@@ -31,27 +63,51 @@ module Trestle
31
63
 
32
64
  def update
33
65
  self.instance = admin.find_instance(params)
34
- admin.update_instance(instance, admin.permitted_params(params))
66
+ admin.update_instance(instance, admin.permitted_params(params), params)
35
67
 
36
68
  if admin.save_instance(instance)
37
- flash[:message] = flash_message("success.update", default: "The %{model_name} was successfully updated.")
38
- redirect_to action: :show, id: admin.to_param(instance)
69
+ respond_to do |format|
70
+ format.html do
71
+ flash[:message] = flash_message("success.update", default: "The %{lowercase_model_name} was successfully updated.")
72
+ redirect_to(admin.return_location(:update, instance), turbolinks: false)
73
+ end
74
+ format.json { render json: instance, status: :ok }
75
+ format.js
76
+ end
39
77
  else
40
- flash.now[:error] = flash_message("failure.update", default: "Please correct the errors below.")
41
- render "show"
78
+ respond_to do |format|
79
+ format.html do
80
+ flash.now[:error] = flash_message("failure.update", default: "Please correct the errors below.")
81
+ render "show", status: :unprocessable_entity
82
+ end
83
+ format.json { render json: instance.errors, status: :unprocessable_entity }
84
+ format.js
85
+ end
42
86
  end
43
87
  end
44
88
 
45
89
  def destroy
46
90
  self.instance = admin.find_instance(params)
91
+ success = admin.delete_instance(instance)
47
92
 
48
- if admin.delete_instance(instance)
49
- flash[:message] = flash_message("success.destroy", default: "The %{model_name} was successfully deleted.")
50
- else
51
- flash[:error] = flash_message("failure.destroy", default: "Could not delete %{model_name}.")
52
- end
93
+ respond_to do |format|
94
+ format.html do
95
+ if success
96
+ flash[:message] = flash_message("success.destroy", default: "The %{lowercase_model_name} was successfully deleted.")
97
+ redirect_to admin.return_location(:destroy)
98
+ else
99
+ flash[:error] = flash_message("failure.destroy", default: "Could not delete %{lowercase_model_name}.")
53
100
 
54
- redirect_to action: :index
101
+ if self.instance = admin.find_instance(params)
102
+ redirect_to action: :show, id: admin.to_param(instance)
103
+ else
104
+ redirect_to admin.return_location(:destroy)
105
+ end
106
+ end
107
+ end
108
+ format.json { head :no_content }
109
+ format.js
110
+ end
55
111
  end
56
112
 
57
113
  protected
@@ -62,7 +118,13 @@ module Trestle
62
118
  helper_method :instance
63
119
 
64
120
  def flash_message(type, options={})
65
- t("trestle.flash.#{type}", options.merge(model_name: admin.model_name.underscore.humanize(capitalize: false)))
121
+ t("trestle.flash.#{type}", options.merge(model_name: admin.model_name, lowercase_model_name: admin.model_name.downcase))
122
+ end
123
+
124
+ def set_trestle_location_header
125
+ unless request.headers["X-Trestle-Dialog"]
126
+ headers["X-Trestle-Location"] = request.path
127
+ end
66
128
  end
67
129
  end
68
130
  end
@@ -5,6 +5,9 @@ module Trestle
5
5
  autoload :Builder
6
6
  autoload :Controller
7
7
 
8
+ RESOURCE_ACTIONS = [:index, :show, :new, :create, :edit, :update, :destroy]
9
+ READONLY_ACTIONS = [:index, :show]
10
+
8
11
  class << self
9
12
  def adapter
10
13
  @adapter ||= Trestle.config.default_adapter.new(self)
@@ -39,10 +42,12 @@ module Trestle
39
42
  adapter_method :decorate_collection
40
43
  adapter_method :unscope
41
44
  adapter_method :merge_scopes
45
+ adapter_method :count
42
46
  adapter_method :sort
43
47
  adapter_method :paginate
44
- adapter_method :count
45
- adapter_method :default_attributes
48
+ adapter_method :human_attribute_name
49
+ adapter_method :default_table_attributes
50
+ adapter_method :default_form_attributes
46
51
 
47
52
  attr_accessor :decorator
48
53
 
@@ -95,9 +100,7 @@ module Trestle
95
100
  return collection unless params[:sort]
96
101
 
97
102
  field = params[:sort].to_sym
98
-
99
- order = params[:order].downcase
100
- order = "asc" unless %w(asc desc).include?(order)
103
+ order = params[:order].to_s.downcase == "desc" ? :desc : :asc
101
104
 
102
105
  if column_sorts.has_key?(field)
103
106
  instance_exec(collection, order, &column_sorts[field])
@@ -119,29 +122,41 @@ module Trestle
119
122
  end
120
123
 
121
124
  def model_name
122
- options[:as] || default_model_name
125
+ @model_name ||= Trestle::ModelName.new(model)
126
+ end
127
+
128
+ def actions
129
+ @actions ||= (readonly? ? READONLY_ACTIONS : RESOURCE_ACTIONS).dup
123
130
  end
124
131
 
125
132
  def readonly?
126
133
  options[:readonly]
127
134
  end
128
135
 
129
- def breadcrumb
130
- Breadcrumb.new(model_name.pluralize, path)
136
+ def default_breadcrumb
137
+ Breadcrumb.new(I18n.t("admin.breadcrumbs.#{admin_name}", default: model_name.plural.titleize), path)
131
138
  end
132
139
 
133
140
  def routes
134
141
  admin = self
135
142
 
136
143
  Proc.new do
137
- resources admin.admin_name, controller: admin.controller_namespace, as: admin.route_name, path: admin.options[:path], except: admin.disabled_routes do
144
+ resources admin.admin_name, controller: admin.controller_namespace, as: admin.route_name, path: admin.options[:path], except: (RESOURCE_ACTIONS - admin.actions) do
138
145
  instance_exec(&admin.additional_routes) if admin.additional_routes
139
146
  end
140
147
  end
141
148
  end
142
149
 
143
- def disabled_routes
144
- readonly? ? [:new, :create, :edit, :update, :destroy] : []
150
+ def return_locations
151
+ @return_locations ||= {
152
+ create: Proc.new { |instance| path(:show, id: to_param(instance)) },
153
+ update: Proc.new { |instance| path(:show, id: to_param(instance)) },
154
+ destroy: Proc.new { path(:index) }
155
+ }
156
+ end
157
+
158
+ def return_location(action, instance=nil)
159
+ instance_exec(instance, &return_locations[action])
145
160
  end
146
161
 
147
162
  private
@@ -150,11 +165,6 @@ module Trestle
150
165
  rescue NameError
151
166
  raise NameError, "Unable to find model #{admin_name.classify}. Specify a different model using Trestle.resource(:#{admin_name}, model: MyModel)"
152
167
  end
153
-
154
- def default_model_name
155
- model_name = model.model_name
156
- model_name.respond_to?(:human) ? model_name.human : model_name.to_s.titleize
157
- end
158
168
  end
159
169
  end
160
170
  end
data/lib/trestle/scope.rb CHANGED
@@ -20,7 +20,7 @@ module Trestle
20
20
 
21
21
  def apply(collection)
22
22
  if @block
23
- @block.call
23
+ @admin.instance_exec(&@block)
24
24
  else
25
25
  collection.public_send(name)
26
26
  end