interview 0.0.1 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/interview.gemspec +4 -0
  3. data/lib/generators/interview/install/install_generator.rb +47 -0
  4. data/lib/generators/interview/install/templates/32px.png +0 -0
  5. data/lib/generators/interview/install/templates/40px.png +0 -0
  6. data/lib/generators/interview/install/templates/application.js +22 -0
  7. data/lib/generators/interview/install/templates/bootstrap_interview.css.scss +98 -0
  8. data/lib/generators/interview/install/templates/ckeditor_config.js +19 -0
  9. data/lib/generators/interview/install/templates/colors.css.scss +2 -0
  10. data/lib/generators/interview/install/templates/defaults_de.yml +204 -0
  11. data/lib/generators/interview/install/templates/interview.js.coffee +72 -0
  12. data/lib/generators/interview/install/templates/interview.rb +4 -0
  13. data/lib/generators/interview/install/templates/jstree.css +916 -0
  14. data/lib/generators/interview/install/templates/jstree.js +5892 -0
  15. data/lib/generators/interview/install/templates/missing_large.png +0 -0
  16. data/lib/generators/interview/install/templates/missing_medium.png +0 -0
  17. data/lib/generators/interview/install/templates/missing_thumb.png +0 -0
  18. data/lib/generators/interview/install/templates/throbber.gif +0 -0
  19. data/lib/generators/interview/install/templates/views_defaults_de.yml +8 -0
  20. data/lib/generators/interview/view_control/templates/card.rb +6 -0
  21. data/lib/generators/interview/view_control/templates/form.rb +6 -0
  22. data/lib/generators/interview/view_control/templates/list.rb +6 -0
  23. data/lib/generators/interview/view_control/view_control_generator.rb +34 -0
  24. data/lib/interview/actionbar.rb +38 -0
  25. data/lib/interview/association_attribute.rb +33 -0
  26. data/lib/interview/association_list_attribute.rb +36 -0
  27. data/lib/interview/association_methods.rb +23 -0
  28. data/lib/interview/attribute.rb +141 -0
  29. data/lib/interview/boolean_attribute.rb +59 -0
  30. data/lib/interview/breadcrumbs.rb +21 -0
  31. data/lib/interview/container_attribute.rb +30 -0
  32. data/lib/interview/control.rb +73 -0
  33. data/lib/interview/control_def.rb +36 -0
  34. data/lib/interview/date_attribute.rb +20 -0
  35. data/lib/interview/datetime_attribute.rb +20 -0
  36. data/lib/interview/decimal_attribute.rb +10 -0
  37. data/lib/interview/dropdown.rb +26 -0
  38. data/lib/interview/form.rb +69 -0
  39. data/lib/interview/form_errors.rb +22 -0
  40. data/lib/interview/grid.rb +53 -0
  41. data/lib/interview/has_controls.rb +43 -0
  42. data/lib/interview/hidden_attribute.rb +15 -0
  43. data/lib/interview/html_control.rb +15 -0
  44. data/lib/interview/html_text_attribute.rb +19 -0
  45. data/lib/interview/image_attribute.rb +34 -0
  46. data/lib/interview/integer_attribute.rb +5 -0
  47. data/lib/interview/link.rb +129 -0
  48. data/lib/interview/list.rb +21 -0
  49. data/lib/interview/navigation.rb +55 -0
  50. data/lib/interview/navigation_item.rb +26 -0
  51. data/lib/interview/nested_form.rb +51 -0
  52. data/lib/interview/nested_form_add_link.rb +80 -0
  53. data/lib/interview/nested_form_remove_link.rb +28 -0
  54. data/lib/interview/object_context.rb +17 -0
  55. data/lib/interview/option_attribute.rb +74 -0
  56. data/lib/interview/polymorphic_add_link.rb +28 -0
  57. data/lib/interview/space.rb +18 -0
  58. data/lib/interview/string_attribute.rb +5 -0
  59. data/lib/interview/tab.rb +21 -0
  60. data/lib/interview/tab_box.rb +29 -0
  61. data/lib/interview/text.rb +15 -0
  62. data/lib/interview/text_attribute.rb +21 -0
  63. data/lib/interview/tooltip.rb +38 -0
  64. data/lib/interview/tree.rb +33 -0
  65. data/lib/interview/version.rb +1 -1
  66. data/lib/interview/view.rb +87 -0
  67. data/lib/interview.rb +196 -0
  68. metadata +107 -2
@@ -0,0 +1,69 @@
1
+ module Interview
2
+ class Form < Control
3
+ include HasControls
4
+
5
+ attr_accessor :skip_submit, :multi_create, :align, :redirect_to
6
+ attr_reader :form_builder
7
+
8
+ def attribute_modus
9
+ return :write
10
+ end
11
+
12
+ def render # todo: Aufräumen
13
+ object = find_attribute!(:object)
14
+ model = object.class.lookup_ancestors.last.model_name.singular # todo
15
+ # if object.class.superclass.name == 'ActiveRecord::Base'
16
+ # model = object.class.name.underscore
17
+ # else
18
+ # model = object.class.superclass.name.underscore
19
+ # end
20
+ if object.id
21
+ url = h.send("#{model}_path", object)
22
+ else
23
+ url = h.send("#{model.pluralize}_path")
24
+ end
25
+ opts = {as: model.to_sym, url: url, role: 'form', html: {}}
26
+ opts[:html][:class] = 'form-horizontal' if @align == 'horizontal'
27
+ opts[:html][:class] = 'form-inline' if @align == 'inline'
28
+ html = Builder::XmlMarkup.new
29
+ html << h.form_for(object, opts) do |form_builder|
30
+ @form_builder = form_builder
31
+ form_html = Builder::XmlMarkup.new
32
+ form_html << FormErrors.new(parent: self).render
33
+ if @redirect_to == :parent and Object.const_defined? 'Gretel'
34
+ form_html << h.hidden_field_tag('redirect_to', h.parent_breadcrumb.url)
35
+ end
36
+
37
+ @controls.each do |control|
38
+ form_html << control.render
39
+ form_html.text! ' ' if @align == 'inline'
40
+ end
41
+
42
+ if not @skip_submit
43
+ if @align == 'horizontal'
44
+ form_html.div class: 'form-group' do
45
+ form_html.div class: 'col-sm-offset-3 col-sm-9' do
46
+ form_html << form_builder.submit(class: 'btn btn-primary')
47
+ if @multi_create || find_attribute(:multi_create)
48
+ form_html.text! ' '
49
+ form_html << h.check_box_tag('new_record', '1', true)
50
+ form_html.text! ' und weiteren Datesatz'
51
+ end
52
+ end
53
+ end
54
+ else
55
+ form_html << form_builder.submit(class: 'btn btn-primary')
56
+ if @multi_create || find_attribute(:multi_create)
57
+ form_html.text! ' '
58
+ form_html << h.check_box_tag('new_record', '1', true)
59
+ form_html.text! ' und weiteren Datesatz'
60
+ end
61
+ end
62
+ end
63
+ form_html.target!.html_safe
64
+ end
65
+ return html.target!
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,22 @@
1
+ module Interview
2
+ class FormErrors < Control
3
+
4
+ def render
5
+ object = find_attribute!(:object)
6
+
7
+ html = Builder::XmlMarkup.new
8
+ if object.errors.any?
9
+ html.div class: 'error_explanation!' do
10
+ html.h2 "#{pluralize(object.errors.count, 'error')} prohibited this article from being saved:"
11
+ html.ul do
12
+ object.errors.full_messages.each do |msg|
13
+ html.li msg
14
+ end
15
+ end
16
+ end
17
+ end
18
+ return html.target!
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,53 @@
1
+ module Interview
2
+ class Grid < Control
3
+ include HasControls
4
+
5
+ attr_accessor :objects, :sortable
6
+ attr_reader :object
7
+
8
+ def render
9
+ objects = @objects || find_attribute!(:objects)
10
+ @object = find_attribute!(:object)
11
+ sortable_id = "sortable_#{@object.class.model_name.plural}" if @sortable
12
+ html = Builder::XmlMarkup.new
13
+ html.table class: 'table' do
14
+ html.thead do
15
+ html.tr do
16
+ html.th '' if @sortable
17
+ @controls.each do |control|
18
+ html.th do
19
+ html << control.caption
20
+ end
21
+ end
22
+ end
23
+ end
24
+ html_opts = {}
25
+ html_opts[:id] = sortable_id if @sortable
26
+ html.tbody html_opts do
27
+ objects.each do |object|
28
+ @object = object
29
+ html_opts = {}
30
+ html_opts[:id] = "#{sortable_id}_#{object.id}" if @sortable
31
+ html.tr html_opts do
32
+ if @sortable
33
+ html.td do
34
+ html.span '', class: 'handle glyphicon glyphicon-resize-vertical'
35
+ end
36
+ end
37
+ @controls.each do |control|
38
+ html.td do
39
+ html << control.render
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ if objects.empty?
47
+ html.p "Keine #{@object.class.model_name.human(count: 2)} vorhanden.", class: 'text-center text-muted'
48
+ end
49
+ return html.target!
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,43 @@
1
+ module HasControls
2
+
3
+ attr_reader :controls
4
+
5
+ def initialize(params={})
6
+ super
7
+ @controls = self.class.definition.build_controls_for self
8
+ end
9
+
10
+ def add_control(control, &block)
11
+ control.parent = self
12
+ yield(control) if block_given?
13
+ @controls << control
14
+ end
15
+
16
+ def add_controls(controls)
17
+ controls.each { |control| control.parent = self }
18
+ @controls += controls
19
+ end
20
+
21
+ def siblings
22
+ return @controls.map do |control|
23
+ if control.respond_to? :siblings
24
+ [control] + control.siblings
25
+ else
26
+ control
27
+ end
28
+ end.flatten
29
+ end
30
+
31
+ def self.included(mod)
32
+ mod.extend ClassMethods
33
+ end
34
+
35
+ module ClassMethods
36
+
37
+ def control(klass, params={}, &block)
38
+ @definition.control(klass, params, &block)
39
+ end
40
+
41
+ end
42
+
43
+ end
@@ -0,0 +1,15 @@
1
+ module Interview
2
+ class HiddenAttribute < Attribute
3
+
4
+ def render_write
5
+ form_builder.hidden_field @method
6
+ end
7
+
8
+ protected
9
+
10
+ def render_form_style
11
+ return render_write
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module Interview
2
+ class HtmlControl < Control
3
+
4
+ def initialize(params={}, &block)
5
+ super
6
+ @html = Builder::XmlMarkup.new
7
+ yield @html
8
+ end
9
+
10
+ def render
11
+ return @html.target!
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ module Interview
2
+ class HtmlTextAttribute < Attribute
3
+
4
+ attr_accessor :plain_text, :cut
5
+
6
+ def render_read
7
+ return '' if value.nil?
8
+ val = value
9
+ val.gsub! /<.+?>/, ' ' if @plain_text
10
+ val = val[0..29] + '...' if @cut and val.size > 30
11
+ return val.html_safe
12
+ end
13
+
14
+ def render_write
15
+ form_builder.cktext_area @method, class: 'form-control'
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,34 @@
1
+ module Interview
2
+ class ImageAttribute < Attribute
3
+
4
+ attr_accessor :image_style, :hide_if_not_exists
5
+
6
+ def render_read
7
+ return '' if value.nil?
8
+ image_style = @image_style || :thumb
9
+ if not value.exists? and @hide_if_not_exists
10
+ return ''
11
+ else
12
+ return h.image_tag value.url(image_style)
13
+ end
14
+ end
15
+
16
+ def render_write
17
+ object = find_attribute(:object)
18
+ image = object.send @method
19
+
20
+ html = Builder::XmlMarkup.new
21
+ if image.exists? and @image_style
22
+ html.br
23
+ html << h.image_tag(image.url(@image_style))
24
+ end
25
+ html << form_builder.file_field(@method)
26
+ if image.exists?
27
+ html << form_builder.check_box("destroy_#{@method}")
28
+ html.text! ' Datei löschen'
29
+ end
30
+ return html.target!
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,5 @@
1
+ module Interview
2
+ class IntegerAttribute < Attribute
3
+
4
+ end
5
+ end
@@ -0,0 +1,129 @@
1
+ module Interview
2
+ class Link < Control
3
+ include HasControls
4
+
5
+ attr_accessor :image, :caption, :hint, :style, :active,
6
+ :url, :controller, :object, :action, :http_method, :redirect_to, :nested_resource, :trail
7
+ attr_reader :url_params, :html_class
8
+
9
+ def initialize(params={})
10
+ @html_class = []
11
+ @url_params = {}
12
+ super
13
+ end
14
+
15
+ def scope=(scope)
16
+ @url_params[:scope] = scope
17
+ end
18
+
19
+ def filter=(filter)
20
+ @url_params[:filter] = filter
21
+ end
22
+
23
+ def render
24
+ if @redirect_to
25
+ if @redirect_to == :current
26
+ @url_params[:redirect_to] = h.request.original_url
27
+ elsif @redirect_to == :parent and Object.const_defined? 'Gretel'
28
+ @url_params[:redirect_to] = h.parent_breadcrumb.url
29
+ else
30
+ @url_params[:redirect_to] = @redirect_to
31
+ end
32
+ end
33
+
34
+ if @trail and Object.const_defined? 'Gretel'
35
+ @url_params[:trail] = h.breadcrumb_trail
36
+ end
37
+
38
+ if @url
39
+ url = @url
40
+ elsif @controller
41
+ url_options = @url_option.dup
42
+ opts = {controller: @controller, action: @action}.merge @url_params
43
+ url = h.url_for opts
44
+ else
45
+ url_params = @url_params.dup
46
+ url_params[:action] = @action if @action and not %w(index show destroy).include? @action
47
+ object = @object || find_attribute!(:object)
48
+ url_params.each do |key, value|
49
+ url_params[key] = value.call(self) if value.is_a? Proc
50
+ end
51
+ if @nested_resource and assoc_object
52
+ url = h.polymorphic_path [assoc_object, object], url_params
53
+ else
54
+ url = h.polymorphic_path object, url_params
55
+ end
56
+ end
57
+
58
+ html_options = {}
59
+ html_class = @html_class.dup
60
+ if @action == 'destroy'
61
+ html_options[:method] = :delete
62
+ html_options[:data] = { confirm: 'Are you sure?' }
63
+ end
64
+ if @http_method
65
+ html_options[:method] = @http_method.to_sym
66
+ end
67
+
68
+ if @hint
69
+ html_class << 'action_hint'
70
+ html_options[:'data-toggle'] = 'tooltip'
71
+ html_options[:title] = @hint
72
+ end
73
+
74
+ if @style and respond_to? "render_#{@style}_style", true
75
+ return send "render_#{@style}_style", url, html_class, html_options
76
+ else
77
+ return render_link url, html_class, html_options
78
+ end
79
+ end
80
+
81
+ def object # todo: Überdenken
82
+ find_attribute(:object)
83
+ end
84
+
85
+ def assoc_object # todo: Überdenken
86
+ find_attribute(:assoc_object)
87
+ end
88
+
89
+ protected
90
+
91
+ def render_button_style(url, html_class=[], html_options={})
92
+ html_class << 'btn btn-default'
93
+ return render_link(url, html_class, html_options)
94
+ end
95
+
96
+ def render_primary_button_style(url, html_class=[], html_options={})
97
+ html_class << 'btn btn-primary'
98
+ return render_link(url, html_class, html_options)
99
+ end
100
+
101
+ def render_list_style(url, html_class=[], html_options={})
102
+ html = Builder::XmlMarkup.new
103
+ li_class = @active ? 'active' : ''
104
+ html.li class: li_class do
105
+ html << render_link(url, html_class, html_options)
106
+ end
107
+ return html.target!
108
+ end
109
+
110
+ def render_link(url, html_class=[], html_options={})
111
+ class_string = html_class.join(' ')
112
+ html_options[:class] = class_string unless html_class.empty?
113
+ return h.link_to(url, html_options) do
114
+ html = Builder::XmlMarkup.new
115
+ if @controls.empty?
116
+ html.span '', class: "glyphicon glyphicon-#{@image}" if @image
117
+ html.text! ' ' if @image and @caption
118
+ html << @caption if @caption
119
+ else
120
+ @controls.each do |control|
121
+ html << control.render
122
+ end
123
+ end
124
+ html.target!.html_safe
125
+ end
126
+ end
127
+
128
+ end
129
+ end
@@ -0,0 +1,21 @@
1
+ module Interview
2
+ class List < Control
3
+ include HasControls
4
+
5
+ attr_accessor :objects
6
+ attr_reader :object
7
+
8
+ def render
9
+ objects = @objects || find_attribute!(:objects)
10
+ html = Builder::XmlMarkup.new
11
+ objects.each do |object|
12
+ @object = object
13
+ @controls.each do |control|
14
+ html << control.render
15
+ end
16
+ end
17
+ return html.target!
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,55 @@
1
+ module Interview
2
+ class Navigation < Control
3
+ include HasControls
4
+
5
+ attr_accessor :controller_name, :action_name, :current_scope, :current_filter
6
+
7
+ def render
8
+ auto_set_active
9
+
10
+ html = Builder::XmlMarkup.new
11
+ html.ul class: 'nav nav-pills nav-stacked' do
12
+ @controls.each do |control|
13
+ html << control.render
14
+ end
15
+ end
16
+ return html.target!
17
+ end
18
+
19
+ private
20
+
21
+ def auto_set_active
22
+ siblings.each { |sib| sib.active = false }
23
+ if (nav_item = siblings.find { |sib| controller_match(sib) && action_match(sib) && scope_match(sib) && filter_match(sib) })
24
+ nav_item.active = true
25
+ elsif (nav_item = siblings.find { |sib| controller_match(sib) && scope_match(sib) && filter_match(sib) })
26
+ nav_item.active = true
27
+ elsif (nav_item = siblings.find { |sib| controller_match(sib) && (scope_match(sib) || filter_match(sib)) })
28
+ nav_item.active = true
29
+ elsif (nav_item = siblings.find { |sib| controller_match(sib) })
30
+ nav_item.active = true
31
+ end
32
+ end
33
+
34
+ def controller_match(nav_item)
35
+ return @controller_name == nav_item.controller
36
+ end
37
+
38
+ def action_match(nav_item)
39
+ return @action_name == nav_item.action
40
+ end
41
+
42
+ def scope_match(nav_item)
43
+ return true if @current_scope.nil?
44
+ return false if nav_item.url_options[:scope].nil?
45
+ return true if nav_item.url_options[:scope] == @current_scope
46
+ end
47
+
48
+ def filter_match(nav_item)
49
+ return true if @current_filter.nil?
50
+ return false if nav_item.url_options[:filter].nil?
51
+ return @current_filter.all? { |key, value| nav_item.url_options[:filter][key] == value }
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,26 @@
1
+ module Interview
2
+ class NavigationItem < Link
3
+
4
+ include HasControls
5
+
6
+ attr_accessor :active
7
+
8
+ def render
9
+ css_class = "level#{ancestors.count-1}"
10
+ css_class += " active" if @active
11
+ show_siblings = @active || siblings.any? { |sib| sib.active }
12
+
13
+ html = Builder::XmlMarkup.new
14
+ html.li class: css_class do
15
+ html << super
16
+ end
17
+ if show_siblings
18
+ @controls.each do |c|
19
+ html << c.render
20
+ end
21
+ end
22
+ return html.target!
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,51 @@
1
+ module Interview
2
+ class NestedForm < Control
3
+ include HasControls
4
+
5
+ attr_accessor :polymorphic, :align # todo: align einbauen
6
+ attr_reader :form_builder, :object
7
+
8
+ def render
9
+ assoc_form_builder = find_attribute! :form_builder
10
+ assoc_method = find_attribute! :assoc_method
11
+ objects = find_attribute! :objects
12
+
13
+ html = Builder::XmlMarkup.new
14
+ html.div class: 'nested_forms' do
15
+ html << assoc_form_builder.fields_for(assoc_method.to_sym, objects) do |form_builder|
16
+ if @polymorphic
17
+ render_polymorphic_nested_form(form_builder)
18
+ else
19
+ render_nested_form(form_builder)
20
+ end
21
+ end
22
+ end
23
+ return html.target!
24
+ end
25
+
26
+ def render_nested_form(form_builder)
27
+ @form_builder = form_builder
28
+ @object = form_builder.object
29
+ html = Builder::XmlMarkup.new
30
+ html.div class: 'nested_form collapse in' do
31
+ @controls.each do |control|
32
+ html << control.render
33
+ end
34
+ html << form_builder.hidden_field(:id)
35
+ html << form_builder.hidden_field(:_destroy, class: 'nested_form_destroy')
36
+ end
37
+ html.target!.html_safe
38
+ end
39
+
40
+ def render_polymorphic_nested_form(form_builder)
41
+ object = form_builder.object
42
+ if klass = "#{object.class.name}NestedForm".safe_constantize
43
+ nested_form = klass.new(parent: self)
44
+ return nested_form.render_nested_form(form_builder)
45
+ else
46
+ return self.render_nested_form(form_builder)
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,80 @@
1
+ module Interview
2
+ class NestedFormAddLink < Control
3
+
4
+ attr_accessor :style, :polymorphic_classes
5
+
6
+ def render
7
+ if @style and @style.to_sym == :horizontal_form
8
+ html = Builder::XmlMarkup.new # todo: in eigenes Objekt auslagern?
9
+ html.div class: 'row' do
10
+ html.div class: 'col-xs-9 col-xs-offset-3' do
11
+ html << render_link
12
+ end
13
+ end
14
+ return html.target!
15
+ else
16
+ return render_link
17
+ end
18
+ end
19
+
20
+ def render_link
21
+ form_builder = find_attribute! :form_builder
22
+ assoc_method = find_attribute!(:assoc_method).to_sym
23
+ if @polymorphic_classes
24
+ return render_polymorphic_link(form_builder, assoc_method)
25
+ else
26
+ html = render_form(form_builder, assoc_method)
27
+ text = h.t('views.nested_form_add', association: find_attribute!(:singular_title))
28
+ return h.content_tag :a, text, { href: '#', class: 'nested_form_add_link', data: { content: CGI::escapeHTML(html) } }, false
29
+ end
30
+ end
31
+
32
+ protected
33
+
34
+ def render_polymorphic_link(form_builder, assoc_method)
35
+ poly_classes = @polymorphic_classes.map do |poly_class|
36
+ poly_class.is_a?(String) ? poly_class.camelcase.constantize : poly_class
37
+ end
38
+
39
+ select_options = [[ h.t('helpers.select.prompt'), nil ]]
40
+ select_options += poly_classes.map do |poly_class|
41
+ [ poly_class.model_name.human, poly_class.model_name.singular ]
42
+ end
43
+
44
+ data_content = {}
45
+ poly_classes.each do |poly_class|
46
+ new_object = form_builder.object.association(assoc_method.to_sym).build(type: poly_class.name)
47
+ html = render_form(form_builder, assoc_method, new_object)
48
+ data_content[poly_class.model_name.singular] = html
49
+ end
50
+
51
+ html = Builder::XmlMarkup.new
52
+ html.div do
53
+ html << h.select_tag("add_link_class", h.options_for_select(select_options), class: 'form-control', style: 'display: inline; width: auto;')
54
+ html.text! ' '
55
+ html << h.content_tag(:a, h.t('views.add'), {href: '#', class: 'nested_form_polymorphic_add_link btn btn-default',
56
+ data: { content: CGI::escapeHTML(data_content.to_json) } }, false)
57
+ end
58
+ return html.target!
59
+ end
60
+
61
+ def render_form(form_builder, assoc_method, new_object=nil)
62
+ new_object ||= form_builder.object.association(assoc_method.to_sym).build
63
+ new_object.assign_attributes(new_object.class.defaults)
64
+ if new_object_assoc = new_object.class.reflect_on_all_associations.find { |a|
65
+ a.foreign_key == form_builder.object.association(assoc_method.to_sym).reflection.foreign_key }
66
+ new_object.association(new_object_assoc.name).target ||= form_builder.object
67
+ end
68
+
69
+ nested_form = find_attribute! :nested_form
70
+ return form_builder.fields_for(assoc_method, new_object, :child_index => "new_association") do |builder|
71
+ if @polymorphic_classes
72
+ nested_form.render_polymorphic_nested_form(builder)
73
+ else
74
+ nested_form.render_nested_form(builder)
75
+ end
76
+ end
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,28 @@
1
+ module Interview
2
+ class NestedFormRemoveLink < Control
3
+
4
+ attr_accessor :style
5
+
6
+ def render
7
+ if @style and @style.to_sym == :horizontal_form
8
+ html = Builder::XmlMarkup.new
9
+ html.div class: 'row' do
10
+ html.div class: 'col-xs-9 col-xs-offset-3' do
11
+ html << render_link
12
+ end
13
+ end
14
+ return html.target!
15
+ else
16
+ return render_link
17
+ end
18
+ end
19
+
20
+ def render_link
21
+ assoc_object = find_attribute! :assoc_object
22
+ assoc_method = find_attribute!(:assoc_method).to_s
23
+ text = h.t('views.nested_form_remove', association: assoc_object.class.human_attribute_name(assoc_method.singularize)) # todo: in view auslagern
24
+ return h.content_tag :a, text, href: '#', class: 'nested_form_remove_link'
25
+ end
26
+
27
+ end
28
+ end