interview 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/interview/install/install_generator.rb +3 -0
  3. data/lib/generators/interview/install/templates/application.css +14 -0
  4. data/lib/generators/interview/install/templates/application.js +2 -0
  5. data/lib/generators/interview/install/templates/blueimp-gallery.css +226 -0
  6. data/lib/generators/interview/install/templates/blueimp-gallery.js +1341 -0
  7. data/lib/generators/interview/install/templates/bootstrap_interview.css.scss +28 -0
  8. data/lib/generators/interview/install/templates/interview.js.coffee +60 -2
  9. data/lib/generators/interview/install/templates/missing_thumb.png +0 -0
  10. data/lib/interview/association_attribute.rb +6 -8
  11. data/lib/interview/association_list_attribute.rb +3 -2
  12. data/lib/interview/attribute.rb +52 -30
  13. data/lib/interview/collapse_container.rb +20 -0
  14. data/lib/interview/condition_container.rb +19 -0
  15. data/lib/interview/dropdown.rb +16 -4
  16. data/lib/interview/form.rb +42 -47
  17. data/lib/interview/form_errors.rb +2 -2
  18. data/lib/interview/grid.rb +1 -1
  19. data/lib/interview/image_attribute.rb +55 -15
  20. data/lib/interview/image_gallery_attribute.rb +74 -0
  21. data/lib/interview/image_light_box.rb +19 -0
  22. data/lib/interview/link.rb +2 -1
  23. data/lib/interview/list.rb +8 -2
  24. data/lib/interview/media_object.rb +45 -0
  25. data/lib/interview/navigation_item.rb +19 -4
  26. data/lib/interview/navigation_item_old.rb +26 -0
  27. data/lib/interview/nested_form_add_link.rb +1 -1
  28. data/lib/interview/panel.rb +18 -0
  29. data/lib/interview/polymorphic_add_link.rb +33 -4
  30. data/lib/interview/search_form.rb +21 -0
  31. data/lib/interview/text.rb +33 -3
  32. data/lib/interview/version.rb +1 -1
  33. data/lib/interview/view.rb +28 -6
  34. data/lib/interview.rb +12 -0
  35. metadata +13 -2
@@ -4,6 +4,11 @@
4
4
 
5
5
  $navbar-default-brand-color: $brand-primary;
6
6
  $navbar-default-bg: $brand-primary-lighten;
7
+ $navbar-inverse-brand-color: $brand-primary-lighten;
8
+ $navbar-inverse-bg: $brand-primary;
9
+ $navbar-inverse-color: #ffffff;
10
+ $navbar-inverse-link-color: $brand-primary-lighten;
11
+ $navbar-inverse-link-hover-color: #ffffff;
7
12
 
8
13
  @import 'bootstrap';
9
14
 
@@ -95,4 +100,27 @@ $nav-stacked-link-padding-level2: 5px 15px 5px 45px !default;
95
100
  input {
96
101
  width: auto;
97
102
  }
103
+ }
104
+
105
+ .inline-block {
106
+ display: inline-block;
107
+ /* IE 7 hack */
108
+ *zoom:1;
109
+ *display: inline;
110
+ vertical-align: middle;
111
+ margin-right: 10px;
112
+ }
113
+
114
+ .list-item {
115
+ margin-top: 15px;
116
+ }
117
+
118
+ .img-thumb {
119
+ display: inline-block;
120
+ /* IE 7 hack */
121
+ *zoom:1;
122
+ *display: inline;
123
+ vertical-align: middle;
124
+ margin-right: 5px;
125
+ margin-bottom: 5px;
98
126
  }
@@ -42,7 +42,7 @@ jQuery ->
42
42
  e.preventDefault()
43
43
  object_class = $('#add_link_class').children('option:selected').val()
44
44
  if object_class != ''
45
- location.href = "#{$(this).attr('href')}?type=#{object_class}"
45
+ location.href = "#{$(this).attr('href')}?filter%5Btype%5D=#{object_class}"
46
46
 
47
47
  $('.jstree').each ->
48
48
  params =
@@ -69,4 +69,62 @@ jQuery ->
69
69
  "position": data.position
70
70
  error: (data) ->
71
71
  tree.jstree('refresh')
72
- $(tree).before("<div class=\"alert alert-danger\">#{data.responseText}</div>")
72
+ $(tree).before("<div class=\"alert alert-danger\">#{data.responseText}</div>")
73
+
74
+ $('.collapse_link').click (e) ->
75
+ e.preventDefault()
76
+ $($(this).data('target')).collapse('toggle')
77
+
78
+ $('.img-link').click (e) ->
79
+ links = $('.img-link')
80
+ target = event.target || event.srcElement
81
+ link = if target.src then target.parentNode else target
82
+ options = { index: link, event: e }
83
+ blueimp.Gallery(links, options)
84
+
85
+ $('.image-upload').fileupload
86
+ add: (e, data) ->
87
+ types = /(\.|\/)(gif|jpe?g|png|mov|mpeg|mpeg4|avi)$/i
88
+ file = data.files[0]
89
+ if types.test(file.type) || types.test(file.name)
90
+ data.context = $(tmpl("upload-progress-script", file))
91
+ $('#upload-progress').append($(data.context))
92
+
93
+ $("input[name='_method']").attr('name', 'method')
94
+ data.submit()
95
+ $("input[name='method']").attr('name', '_method')
96
+ else
97
+ alert("#{file.name} is not a gif, jpg or png image file")
98
+ progress: (e, data) ->
99
+ if data.context
100
+ progress = parseInt(data.loaded / data.total * 100, 10)
101
+ data.context.find('.bar').css('width', progress + '%')
102
+ done: (e, data) ->
103
+ $('#image-tag').attr('src', data.result.thumb_url)
104
+ # context = $(tmpl("image-thumb-script", data.result))
105
+ # $('#image-gallery').append($(context))
106
+ $('.image-id').attr('value', data.result.id)
107
+
108
+ $('.multiple-image-upload').fileupload
109
+ add: (e, data) ->
110
+ types = /(\.|\/)(gif|jpe?g|png|mov|mpeg|mpeg4|avi)$/i
111
+ file = data.files[0]
112
+ if types.test(file.type) || types.test(file.name)
113
+ data.context = $(tmpl("upload-progress-script", file))
114
+ $('#upload-progress').append($(data.context))
115
+
116
+ $("input[name='_method']").attr('name', 'method')
117
+ data.submit()
118
+ $("input[name='method']").attr('name', '_method')
119
+ else
120
+ alert("#{file.name} is not a gif, jpg or png image file")
121
+ progress: (e, data) ->
122
+ if data.context
123
+ progress = parseInt(data.loaded / data.total * 100, 10)
124
+ data.context.find('.bar').css('width', progress + '%')
125
+ done: (e, data) ->
126
+ context = $(tmpl("image-thumb-script", data.result))
127
+ $('#image-gallery').append($(context))
128
+ ids = JSON.parse($('.image-ids').attr('value'))
129
+ ids.push data.result.id
130
+ $('.image-ids').attr('value', JSON.stringify(ids))
@@ -6,13 +6,10 @@ module Interview
6
6
  def render_read
7
7
  return '' if value.nil?
8
8
  assoc_object = value
9
- if h.respond_to? "#{@method}_path"
10
- return Link.new(parent: self,
11
- caption: "#{assoc_object.human_id}",
12
- object: assoc_object).render
13
- else
14
- return assoc_object.human_id
15
- end
9
+ # todo: Link nicht anzeigen, wenn Route für Objekt nicht existiert
10
+ return Link.new(parent: self,
11
+ caption: "#{assoc_object.human_id}",
12
+ object: assoc_object).render
16
13
  end
17
14
 
18
15
  def render_write
@@ -26,7 +23,8 @@ module Interview
26
23
  assoc_class = object.class.new.send("build_#{@method}").class
27
24
  pool = assoc_class.all
28
25
  end
29
- form_builder.collection_select "#{@method}_id", pool, :id, :human_id, {prompt: true}, {class: 'form-control'}
26
+ form_builder.collection_select "#{@method}_id", pool, :id, :human_id, {include_blank: true}, {class: 'form-control'}
27
+ # todo: prompt einbauen
30
28
  end
31
29
 
32
30
  end
@@ -1,7 +1,7 @@
1
1
  module Interview
2
2
  class AssociationListAttribute < Attribute
3
3
 
4
- attr_accessor :use
4
+ attr_accessor :use, :size
5
5
 
6
6
  def render_read
7
7
  return '' if value.nil?
@@ -17,6 +17,7 @@ module Interview
17
17
  end
18
18
 
19
19
  def render_write
20
+ size = @size || 8
20
21
  if @use == 'multi_select'
21
22
  object = find_attribute!(:object)
22
23
  if object.respond_to? "#{method.singularize}_pool"
@@ -25,7 +26,7 @@ module Interview
25
26
  assoc_class = object.class.new.send(@method).build.class
26
27
  pool = assoc_class.all
27
28
  end
28
- form_builder.collection_select "#{@method.singularize}_ids", pool, :id, :human_id, {prompt: true}, {class: 'form-control', multiple: true}
29
+ form_builder.collection_select "#{@method.singularize}_ids", pool, :id, :human_id, {prompt: true}, {class: 'form-control', multiple: true, size: size}
29
30
  # form_builder.collection_select "#{@method.singularize}_ids", Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true
30
31
  else
31
32
  return form_builder.text_field "#{@method}_human_ids_string", class: 'form-control'
@@ -2,10 +2,15 @@ module Interview
2
2
  class Attribute < Control
3
3
 
4
4
  attr_accessor :method, :caption, :style, :link, :nil_value, :hide_caption, :hide_tooltip,
5
- :only_for, :align, :on_changed
5
+ :only_for, :align, :on_changed, :html_class, :surrounding_tag
6
+
7
+ def initialize(params={})
8
+ @html_class = []
9
+ super
10
+ end
6
11
 
7
12
  def value
8
- object = find_attribute! :object
13
+ object = @object || find_attribute!(:object)
9
14
  if object.respond_to? @method
10
15
  val = object.send @method
11
16
  end
@@ -18,14 +23,13 @@ module Interview
18
23
  return @caption
19
24
  else
20
25
  object = find_attribute! :object
21
- puts "#{object.class.name} #{@method}"
22
26
  return object.class.human_attribute_name(@method)
23
27
  end
24
28
  end
25
29
 
26
30
  def tooltip
27
31
  object = find_attribute! :object
28
- return h.t("activerecord.tooltips.#{object.class.name.underscore}.attributes.#{@method}", default: '')
32
+ return h.t("activerecord.attribute_tooltips.#{object.class.model_name.i18n_key}.#{@method}", default: '')
29
33
  end
30
34
 
31
35
 
@@ -33,10 +37,11 @@ module Interview
33
37
  return '' if hide?
34
38
 
35
39
  if @style and respond_to?("render_#{@style}_style", true)
36
- return send("render_#{@style}_style")
40
+ html = send("render_#{@style}_style")
37
41
  else
38
- return render_default_style
42
+ html = render_default_style
39
43
  end
44
+ return add_surrounding_tag(html)
40
45
  end
41
46
 
42
47
  def render_read
@@ -74,45 +79,62 @@ module Interview
74
79
  object = find_attribute! :object
75
80
  align = @align || find_attribute(:align)
76
81
 
77
- html = Builder::XmlMarkup.new
78
- html.div class: "form-group" do # todo: old class: "form-group attribute_#{@method.to_s} collapse in"
79
- opts = {}
80
- opts[:class] = 'col-xs-3 control-label' if align == 'horizontal'
81
- opts[:class] = 'sr-only' if align == 'inline'
82
- if @hide_caption
83
- html.div opts
84
- else
85
- html << form_builder.label(@method, opts) do
86
- form_html = Builder::XmlMarkup.new
87
- form_html.text! caption
88
- # if not @hide_tooltip and tooltip != ''
89
- # form_html.text! ' '
90
- # form_html << Tooltip.new(tooltip: tooltip, style: :popover).render
91
- # end
92
- form_html.target!.html_safe
93
- end
94
- end
82
+ html = Builder::XmlMarkup.new(indent: 2)
83
+ html.div class: 'form-group' do
84
+
85
+ html.div class: 'col-xs-3' if @hide_caption and align == 'horizontal'
86
+ render_form_label(html)
87
+
95
88
  if align == 'horizontal'
96
89
  html.div class: 'col-xs-9' do
97
90
  html << render_write
98
- if not @hide_tooltip and tooltip != ''
99
- html.p tooltip, class: 'help-block'
100
- end
91
+ render_form_tooltip(html)
101
92
  end
102
93
  else
103
94
  html << render_write
104
- if not @hide_tooltip and tooltip != ''
105
- html.p tooltip, class: 'help-block'
106
- end
95
+ render_form_tooltip(html)
107
96
  end
97
+
108
98
  end
109
99
  return html.target!
110
100
  end
111
101
 
102
+ def render_form_label(html)
103
+ align = @align || find_attribute(:align)
104
+ html_opts = if @hide_caption or align == 'inline'
105
+ { class: 'sr-only' }
106
+ elsif align == 'horizontal'
107
+ { class: 'col-xs-3 control-label' }
108
+ else
109
+ {}
110
+ end
111
+ html << form_builder.label(@method, html_opts) do
112
+ form_html = Builder::XmlMarkup.new
113
+ form_html.text! caption
114
+ form_html.target!.html_safe
115
+ end
116
+ end
117
+
118
+ def render_form_tooltip(html)
119
+ if not @hide_tooltip and tooltip != ''
120
+ html.p tooltip, class: 'help-block'
121
+ end
122
+ end
123
+
112
124
  def form_builder
113
125
  return find_attribute! :form_builder
114
126
  end
115
127
 
128
+ def add_surrounding_tag(html)
129
+ if @surrounding_tag
130
+ opts = {}
131
+ opts[:class] = @html_class.join(' ') unless @html_class.empty?
132
+ return h.content_tag @surrounding_tag.to_sym, html, opts
133
+ else
134
+ return html
135
+ end
136
+ end
137
+
116
138
  def add_link(value)
117
139
  if @link
118
140
  return Link.new(parent: @parent, caption: value.to_s).render
@@ -0,0 +1,20 @@
1
+ module Interview
2
+ class CollapseContainer < Control
3
+ include HasControls
4
+
5
+ attr_accessor :caption
6
+
7
+ def render
8
+ html = Builder::XmlMarkup.new
9
+ new_id = Time.now.to_f.to_s.delete('.')
10
+ html << h.link_to(@caption, '#', class: 'collapse_link', data: { toggle: 'collapse', target: "##{new_id}" })
11
+ html.div id: new_id, class: 'panel-collapse collapse' do
12
+ @controls.each do |control|
13
+ html << control.render
14
+ end
15
+ end
16
+ return html.target!
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ module Interview
2
+ class ConditionContainer < Control
3
+ include HasControls
4
+
5
+ attr_accessor :condition
6
+
7
+ def render
8
+ object = find_attribute :object
9
+ if @condition.call(object)
10
+ return @controls.map do |control|
11
+ control.render
12
+ end.join
13
+ else
14
+ return ''
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -2,13 +2,25 @@ module Interview
2
2
  class Dropdown < Control
3
3
  include HasControls
4
4
 
5
- attr_accessor :caption, :align
5
+ attr_accessor :image, :caption, :style, :html_class
6
+
7
+ def initialize(params={})
8
+ @html_class = []
9
+ super
10
+ end
6
11
 
7
12
  def render
8
13
  html = Builder::XmlMarkup.new
9
- html.div class: 'dropdown' do
10
- html.a class: 'dropdown-toggle btn btn-default', href: '#', :'data-toggle' => 'dropdown' do
11
- html.text! @caption + ' '
14
+ html_class = @html_class.dup
15
+ html_class << 'dropdown'
16
+ html.div class: html_class.join(' ') do
17
+ html_class = 'dropdown-toggle'
18
+ html_class += ' btn btn-default' if @style == 'button'
19
+ html.a class: html_class, href: '#', :'data-toggle' => 'dropdown' do
20
+ html.span '', class: "glyphicon glyphicon-#{@image}" if @image
21
+ html.text! ' ' if @image and @caption
22
+ html.text! @caption if @caption
23
+ html.text! ' ' if @caption
12
24
  html.span '', class: 'caret'
13
25
  end
14
26
  html.ul class: 'dropdown-menu' do
@@ -5,64 +5,59 @@ module Interview
5
5
  attr_accessor :skip_submit, :multi_create, :align, :redirect_to
6
6
  attr_reader :form_builder
7
7
 
8
- def attribute_modus
9
- return :write
10
- end
11
-
12
- def render # todo: Aufräumen
8
+ def render
13
9
  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")
10
+ html_options = case @align
11
+ when 'horizontal' then { class: 'form-horizontal' }
12
+ when 'inline' then { class: 'form-inline' }
13
+ else {}
24
14
  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|
15
+ return h.form_for(object, role: 'form', html: html_options) do |form_builder|
30
16
  @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
17
+ html = Builder::XmlMarkup.new(indent: 2)
18
+
19
+ render_default_controls(html)
36
20
 
37
21
  @controls.each do |control|
38
- form_html << control.render
39
- form_html.text! ' ' if @align == 'inline'
22
+ html << control.render
23
+ html.text! ' ' if @align == 'inline'
40
24
  end
41
25
 
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'
26
+ if @align == 'horizontal'
27
+ html.div class: 'form-group' do
28
+ html.div class: 'col-sm-offset-3 col-sm-9' do
29
+ render_submit(html)
60
30
  end
61
31
  end
32
+ else
33
+ render_submit(html)
34
+ end
35
+
36
+ html.target!.html_safe
37
+ end
38
+ end
39
+
40
+ protected
41
+
42
+ def render_submit(html)
43
+ if not @skip_submit
44
+ html << form_builder.submit(class: 'btn btn-primary')
45
+ if @multi_create || find_attribute(:multi_create)
46
+ html.text! ' '
47
+ html << h.check_box_tag('new_record', '1', true)
48
+ html.text! ' und weiteren Datesatz' # todo
62
49
  end
63
- form_html.target!.html_safe
64
50
  end
65
- return html.target!
51
+ end
52
+
53
+ def render_default_controls(html)
54
+ html << FormErrors.new(parent: self).render
55
+
56
+ if @redirect_to == :parent and Object.const_defined? 'Gretel'
57
+ html << h.hidden_field_tag('redirect_to', h.parent_breadcrumb.url)
58
+ elsif @redirect_to == :current
59
+ html << h.hidden_field_tag('redirect_to', h.request.original_url)
60
+ end
66
61
  end
67
62
 
68
63
  end
@@ -6,8 +6,8 @@ module Interview
6
6
 
7
7
  html = Builder::XmlMarkup.new
8
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:"
9
+ html.div class: 'alert alert-danger' do
10
+ html.h4 h.translate("errors.template.header", count: object.errors.count, model: object.class.model_name.human)
11
11
  html.ul do
12
12
  object.errors.full_messages.each do |msg|
13
13
  html.li msg
@@ -44,7 +44,7 @@ module Interview
44
44
  end
45
45
  end
46
46
  if objects.empty?
47
- html.p "Keine #{@object.class.model_name.human(count: 2)} vorhanden.", class: 'text-center text-muted'
47
+ html.p "Keine #{@object.class.human_name(count: 2)} vorhanden.", class: 'text-center text-muted'
48
48
  end
49
49
  return html.target!
50
50
  end
@@ -1,32 +1,72 @@
1
1
  module Interview
2
2
  class ImageAttribute < Attribute
3
3
 
4
- attr_accessor :image_style, :hide_if_not_exists
4
+ # - Bild muss in eingener Klasse ausgelagert werden
5
+ # - object muss die Methode method_id= implementieren
6
+ # - method_id muss als parameter erlaubt werden
7
+ # - json ansicht auf bild muss vorhanden sein
8
+
9
+ attr_accessor :object, :submethod, :image_style, :hide_if_not_exists
5
10
 
6
11
  def render_read
7
- return '' if value.nil?
12
+ submethod = @submethod || 'attachment'
8
13
  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)
14
+ object = @object || find_attribute(:object)
15
+ image = value || object.association(@method).build
16
+
17
+ attachment = image.send(submethod)
18
+ return '' if not attachment.exists? and @hide_if_not_exists
19
+
20
+ html = Builder::XmlMarkup.new
21
+ opts = {class: "image_#{image_style}"}
22
+ opts[:class] += ' ' + @html_class.join(' ') unless @html_class.empty? or @surrounding_tag
23
+ html.div opts do
24
+ html << h.image_tag(attachment.url(image_style), class: 'img-responsive')
13
25
  end
26
+ return html.target!
14
27
  end
15
28
 
16
29
  def render_write
17
- object = find_attribute(:object)
18
- image = object.send @method
30
+ object = @object || find_attribute(:object)
31
+ submethod = @submethod || 'attachment'
32
+ image_style = @image_style || :thumb
33
+ image = object.send(@method) || object.association(@method).build
34
+ attachment = image.send(submethod)
35
+ model = image.class.model_name.singular
19
36
 
20
37
  html = Builder::XmlMarkup.new
21
- if image.exists? and @image_style
22
- html.br
23
- html << h.image_tag(image.url(@image_style))
38
+
39
+ html << form_builder.hidden_field("#{@method.singularize}_id", class: 'image-id')
40
+
41
+ html.div class: 'inline-block' do
42
+ html << h.image_tag(attachment.url(image_style), id: 'image-tag')
24
43
  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'
44
+
45
+ html.div class: 'inline-block' do
46
+ html.span class: "btn btn-default fileinput-button" do
47
+ html.span "Select file..."
48
+ html << h.file_field_tag("#{model}[#{submethod}]", class: 'image-upload',
49
+ data: {url: "/#{model.pluralize}.json", type: 'POST'})
50
+ end
51
+
52
+ # if attachment.exists?
53
+ # html << form_builder.check_box("destroy_#{@method}")
54
+ # html.text! ' Datei löschen'
55
+ # end
56
+ end
57
+
58
+ html.div id: 'upload-progress' do
29
59
  end
60
+
61
+ html.script id: 'upload-progress-script', type: 'text/x-tmpl' do
62
+ html.div class: 'upload' do
63
+ html.text! "{%=o.name%}"
64
+ html.div class: 'progress' do
65
+ html.div '', class: 'progress-bar bar', style: 'width: 0%'
66
+ end
67
+ end
68
+ end
69
+
30
70
  return html.target!
31
71
  end
32
72
 
@@ -0,0 +1,74 @@
1
+ module Interview
2
+ class ImageGalleryAttribute < Attribute
3
+
4
+ attr_accessor :object, :submethod, :image_style, :light_box_image_style
5
+
6
+ def render_read
7
+ submethod = @submethod || 'attachment'
8
+ image_style = @image_style || :thumb
9
+ images = value
10
+
11
+ html = Builder::XmlMarkup.new
12
+ render_gallery(html, images, submethod, image_style, @light_box_image_style)
13
+ return html.target!
14
+ end
15
+
16
+ def render_write
17
+ object = @object || find_attribute(:object)
18
+ submethod = @submethod || 'attachment'
19
+ image_style = @image_style || :thumb
20
+ images = object.send @method
21
+ model = images.klass.model_name.singular
22
+
23
+ html = Builder::XmlMarkup.new
24
+ html.div class: 'image-upload-group' do
25
+
26
+ html << form_builder.hidden_field("#{@method.singularize}_ids", class: 'image-ids')
27
+
28
+ render_gallery(html, images, submethod, image_style, @light_box_image_style)
29
+
30
+ light_box_image_url = @light_box_image_style ? "#{@light_box_image_style}_url" : 'url'
31
+ html.script id: 'image-thumb-script', type: 'text/x-tmpl' do
32
+ html.a href: "{%=o.#{light_box_image_url}%}", class: 'img-link' do
33
+ html.img class: 'img-thumb', src: "{%=o.thumb_url%}"
34
+ end
35
+ end
36
+
37
+ html.div class: "clearfix" do
38
+ html.span class: "btn btn-default fileinput-button" do
39
+ html.span "Bilder hinzufügen" # todo
40
+ html << h.file_field_tag("#{model}[#{submethod}]", class: 'multiple-image-upload', multiple: true,
41
+ data: {url: "/#{model.pluralize}.json", type: 'POST'})
42
+ end
43
+ end
44
+
45
+ html.div class: 'upload-progress' do
46
+ end
47
+
48
+ html.script id: 'upload-progress-script', type: 'text/x-tmpl' do
49
+ html.div class: 'upload' do
50
+ html.text! "{%=o.name%}"
51
+ html.div class: 'progress' do
52
+ html.div '', class: 'progress-bar bar', style: 'width: 0%'
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ return html.target!
59
+ end
60
+
61
+ protected
62
+
63
+ def render_gallery(html, images, submethod, image_style, light_box_image_style)
64
+ html.div class: 'image-gallery' do
65
+ images.each do |image|
66
+ html.a href: image.send(submethod).url(light_box_image_style), class: 'img-link' do
67
+ html << h.image_tag(image.send(submethod).url(image_style), class: 'img-thumb')
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ end
74
+ end