interview 0.0.1 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/interview.gemspec +4 -0
- data/lib/generators/interview/install/install_generator.rb +47 -0
- data/lib/generators/interview/install/templates/32px.png +0 -0
- data/lib/generators/interview/install/templates/40px.png +0 -0
- data/lib/generators/interview/install/templates/application.js +22 -0
- data/lib/generators/interview/install/templates/bootstrap_interview.css.scss +98 -0
- data/lib/generators/interview/install/templates/ckeditor_config.js +19 -0
- data/lib/generators/interview/install/templates/colors.css.scss +2 -0
- data/lib/generators/interview/install/templates/defaults_de.yml +204 -0
- data/lib/generators/interview/install/templates/interview.js.coffee +72 -0
- data/lib/generators/interview/install/templates/interview.rb +4 -0
- data/lib/generators/interview/install/templates/jstree.css +916 -0
- data/lib/generators/interview/install/templates/jstree.js +5892 -0
- data/lib/generators/interview/install/templates/missing_large.png +0 -0
- data/lib/generators/interview/install/templates/missing_medium.png +0 -0
- data/lib/generators/interview/install/templates/missing_thumb.png +0 -0
- data/lib/generators/interview/install/templates/throbber.gif +0 -0
- data/lib/generators/interview/install/templates/views_defaults_de.yml +8 -0
- data/lib/generators/interview/view_control/templates/card.rb +6 -0
- data/lib/generators/interview/view_control/templates/form.rb +6 -0
- data/lib/generators/interview/view_control/templates/list.rb +6 -0
- data/lib/generators/interview/view_control/view_control_generator.rb +34 -0
- data/lib/interview/actionbar.rb +38 -0
- data/lib/interview/association_attribute.rb +33 -0
- data/lib/interview/association_list_attribute.rb +36 -0
- data/lib/interview/association_methods.rb +23 -0
- data/lib/interview/attribute.rb +141 -0
- data/lib/interview/boolean_attribute.rb +59 -0
- data/lib/interview/breadcrumbs.rb +21 -0
- data/lib/interview/container_attribute.rb +30 -0
- data/lib/interview/control.rb +73 -0
- data/lib/interview/control_def.rb +36 -0
- data/lib/interview/date_attribute.rb +20 -0
- data/lib/interview/datetime_attribute.rb +20 -0
- data/lib/interview/decimal_attribute.rb +10 -0
- data/lib/interview/dropdown.rb +26 -0
- data/lib/interview/form.rb +69 -0
- data/lib/interview/form_errors.rb +22 -0
- data/lib/interview/grid.rb +53 -0
- data/lib/interview/has_controls.rb +43 -0
- data/lib/interview/hidden_attribute.rb +15 -0
- data/lib/interview/html_control.rb +15 -0
- data/lib/interview/html_text_attribute.rb +19 -0
- data/lib/interview/image_attribute.rb +34 -0
- data/lib/interview/integer_attribute.rb +5 -0
- data/lib/interview/link.rb +129 -0
- data/lib/interview/list.rb +21 -0
- data/lib/interview/navigation.rb +55 -0
- data/lib/interview/navigation_item.rb +26 -0
- data/lib/interview/nested_form.rb +51 -0
- data/lib/interview/nested_form_add_link.rb +80 -0
- data/lib/interview/nested_form_remove_link.rb +28 -0
- data/lib/interview/object_context.rb +17 -0
- data/lib/interview/option_attribute.rb +74 -0
- data/lib/interview/polymorphic_add_link.rb +28 -0
- data/lib/interview/space.rb +18 -0
- data/lib/interview/string_attribute.rb +5 -0
- data/lib/interview/tab.rb +21 -0
- data/lib/interview/tab_box.rb +29 -0
- data/lib/interview/text.rb +15 -0
- data/lib/interview/text_attribute.rb +21 -0
- data/lib/interview/tooltip.rb +38 -0
- data/lib/interview/tree.rb +33 -0
- data/lib/interview/version.rb +1 -1
- data/lib/interview/view.rb +87 -0
- data/lib/interview.rb +196 -0
- metadata +107 -2
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Interview
|
4
|
+
module Generators
|
5
|
+
class ViewControlGenerator < ::Rails::Generators::NamedBase
|
6
|
+
include Rails::Generators::ResourceHelpers
|
7
|
+
|
8
|
+
argument :attributes, type: :array, default: [], banner: "field:type field:type"
|
9
|
+
|
10
|
+
source_root File.expand_path("../templates", __FILE__)
|
11
|
+
desc "This generator adds View Controls for a model."
|
12
|
+
|
13
|
+
def add_erb_templates
|
14
|
+
template "list.rb", "app/view_controls/#{file_name}_list.rb"
|
15
|
+
template "card.rb", "app/view_controls/#{file_name}_card.rb"
|
16
|
+
template "form.rb", "app/view_controls/#{file_name}_form.rb"
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def attribute_class_name(attribute)
|
22
|
+
return case attribute.type
|
23
|
+
when :string then 'StringAttribute'
|
24
|
+
when :text then 'TextAttribute'
|
25
|
+
when :boolean then 'BooleanAttribute'
|
26
|
+
when :date then 'DateAttribute'
|
27
|
+
when :option then 'OptionAttribute'
|
28
|
+
else 'Attribute'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Interview
|
2
|
+
class Actionbar < Control
|
3
|
+
include HasControls
|
4
|
+
|
5
|
+
attr_accessor :title, :icon
|
6
|
+
|
7
|
+
def render
|
8
|
+
title = @title || find_attribute(:title)
|
9
|
+
icon = @icon
|
10
|
+
if icon == :polymorphic
|
11
|
+
object = find_attribute! :object
|
12
|
+
icon = object.icon
|
13
|
+
end
|
14
|
+
|
15
|
+
html = Builder::XmlMarkup.new
|
16
|
+
html.div class: 'clearfix' do
|
17
|
+
unless @controls.empty?
|
18
|
+
html.ul class: 'list-inline pull-right' do
|
19
|
+
@controls.each do |control|
|
20
|
+
html.li do
|
21
|
+
html << control.render
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
if title
|
27
|
+
html.p class: 'h3' do
|
28
|
+
html.span '', class: icon if icon
|
29
|
+
html.text! ' ' if icon
|
30
|
+
html.text! title
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
return html.target!
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Interview
|
2
|
+
class AssociationAttribute < Attribute
|
3
|
+
|
4
|
+
attr_accessor :association_class
|
5
|
+
|
6
|
+
def render_read
|
7
|
+
return '' if value.nil?
|
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
|
16
|
+
end
|
17
|
+
|
18
|
+
def render_write
|
19
|
+
object = find_attribute!(:object)
|
20
|
+
if object.respond_to? "#{method}_pool"
|
21
|
+
pool = object.send "#{method}_pool"
|
22
|
+
elsif @association_class
|
23
|
+
assoc_class = Object.const_get(@association_class.to_s.camelcase)
|
24
|
+
pool = assoc_class.all
|
25
|
+
else
|
26
|
+
assoc_class = object.class.new.send("build_#{@method}").class
|
27
|
+
pool = assoc_class.all
|
28
|
+
end
|
29
|
+
form_builder.collection_select "#{@method}_id", pool, :id, :human_id, {prompt: true}, {class: 'form-control'}
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Interview
|
2
|
+
class AssociationListAttribute < Attribute
|
3
|
+
|
4
|
+
attr_accessor :use
|
5
|
+
|
6
|
+
def render_read
|
7
|
+
return '' if value.nil?
|
8
|
+
assoc_objects = value
|
9
|
+
assoc_count = assoc_objects.count
|
10
|
+
if @use == 'link'
|
11
|
+
return Link.new(caption: "#{@method.humanize} (#{assoc_count})",
|
12
|
+
object: "#{assoc_objects.klass}",
|
13
|
+
filter: assoc_objects.where_values_hash).render # todo: Überarbeiten
|
14
|
+
else
|
15
|
+
return assoc_objects.human_ids.join(', ')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def render_write
|
20
|
+
if @use == 'multi_select'
|
21
|
+
object = find_attribute!(:object)
|
22
|
+
if object.respond_to? "#{method.singularize}_pool"
|
23
|
+
pool = object.send "#{method.singularize}_pool"
|
24
|
+
else
|
25
|
+
assoc_class = object.class.new.send(@method).build.class
|
26
|
+
pool = assoc_class.all
|
27
|
+
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", Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true
|
30
|
+
else
|
31
|
+
return form_builder.text_field "#{@method}_human_ids_string", class: 'form-control'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module AssociationMethods
|
2
|
+
|
3
|
+
def define_readers
|
4
|
+
super
|
5
|
+
mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
6
|
+
def #{name}_human_ids_string
|
7
|
+
return self.#{name}.human_ids.join(', ')
|
8
|
+
end
|
9
|
+
CODE
|
10
|
+
end
|
11
|
+
|
12
|
+
def define_writers
|
13
|
+
super
|
14
|
+
mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
|
15
|
+
def #{name}_human_ids_string=(string)
|
16
|
+
human_ids = string.split /, */
|
17
|
+
#{name} = human_ids.map { |human_id| self.#{name}.klass.find_by_human_id(human_id) }
|
18
|
+
self.#{name} = #{name}
|
19
|
+
end
|
20
|
+
CODE
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
module Interview
|
2
|
+
class Attribute < Control
|
3
|
+
|
4
|
+
attr_accessor :method, :caption, :style, :link, :nil_value, :hide_caption, :hide_tooltip,
|
5
|
+
:only_for, :align, :on_changed
|
6
|
+
|
7
|
+
def value
|
8
|
+
object = find_attribute! :object
|
9
|
+
if object.respond_to? @method
|
10
|
+
val = object.send @method
|
11
|
+
end
|
12
|
+
val = @nil_value if val.nil?
|
13
|
+
return val
|
14
|
+
end
|
15
|
+
|
16
|
+
def caption
|
17
|
+
if @caption
|
18
|
+
return @caption
|
19
|
+
else
|
20
|
+
object = find_attribute! :object
|
21
|
+
puts "#{object.class.name} #{@method}"
|
22
|
+
return object.class.human_attribute_name(@method)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def tooltip
|
27
|
+
object = find_attribute! :object
|
28
|
+
return h.t("activerecord.tooltips.#{object.class.name.underscore}.attributes.#{@method}", default: '')
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def render
|
33
|
+
return '' if hide?
|
34
|
+
|
35
|
+
if @style and respond_to?("render_#{@style}_style", true)
|
36
|
+
return send("render_#{@style}_style")
|
37
|
+
else
|
38
|
+
return render_default_style
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def render_read
|
43
|
+
return value.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
def render_write
|
47
|
+
return form_builder.text_field @method, class: 'form-control'
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
def render_default_style
|
53
|
+
return add_link(render_read)
|
54
|
+
end
|
55
|
+
|
56
|
+
def render_card_style
|
57
|
+
html = Builder::XmlMarkup.new
|
58
|
+
html.div class: 'row' do
|
59
|
+
html.p class: 'col-xs-3' do
|
60
|
+
html.b caption unless @hide_caption
|
61
|
+
if not @hide_tooltip and tooltip != ''
|
62
|
+
html << Tooltip.new(tooltip: tooltip, style: :popover).render
|
63
|
+
end
|
64
|
+
end
|
65
|
+
html.p class: 'col-xs-9' do
|
66
|
+
html << add_link(render_read)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
return html.target!
|
70
|
+
end
|
71
|
+
|
72
|
+
def render_form_style
|
73
|
+
form_builder = find_attribute! :form_builder
|
74
|
+
object = find_attribute! :object
|
75
|
+
align = @align || find_attribute(:align)
|
76
|
+
|
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
|
95
|
+
if align == 'horizontal'
|
96
|
+
html.div class: 'col-xs-9' do
|
97
|
+
html << render_write
|
98
|
+
if not @hide_tooltip and tooltip != ''
|
99
|
+
html.p tooltip, class: 'help-block'
|
100
|
+
end
|
101
|
+
end
|
102
|
+
else
|
103
|
+
html << render_write
|
104
|
+
if not @hide_tooltip and tooltip != ''
|
105
|
+
html.p tooltip, class: 'help-block'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
return html.target!
|
110
|
+
end
|
111
|
+
|
112
|
+
def form_builder
|
113
|
+
return find_attribute! :form_builder
|
114
|
+
end
|
115
|
+
|
116
|
+
def add_link(value)
|
117
|
+
if @link
|
118
|
+
return Link.new(parent: @parent, caption: value.to_s).render
|
119
|
+
else
|
120
|
+
return value
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def hide?
|
125
|
+
if @only_for
|
126
|
+
object = find_attribute! :object
|
127
|
+
if @only_for.is_a? Array
|
128
|
+
unless @only_for.any? { |class_name| object.is_a? class_name.camelcase.constantize }
|
129
|
+
return true
|
130
|
+
end
|
131
|
+
else
|
132
|
+
unless object.is_a? @only_for.camelcase.constantize
|
133
|
+
return true
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
return false
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Interview
|
2
|
+
class BooleanAttribute < Attribute
|
3
|
+
|
4
|
+
def render_read
|
5
|
+
return '' if value.nil?
|
6
|
+
html = Builder::XmlMarkup.new
|
7
|
+
if value
|
8
|
+
html.span '', class: 'glyphicon glyphicon-ok'
|
9
|
+
else
|
10
|
+
html.text! ''
|
11
|
+
end
|
12
|
+
return html.target!
|
13
|
+
end
|
14
|
+
|
15
|
+
def render_write
|
16
|
+
form_builder.check_box @method
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def render_form_style
|
22
|
+
form_builder = find_attribute! :form_builder
|
23
|
+
object = find_attribute! :object
|
24
|
+
align = @align || find_attribute(:align)
|
25
|
+
|
26
|
+
html = Builder::XmlMarkup.new
|
27
|
+
html.div class: "form-group attribute_#{@method.to_s} collapse in" do
|
28
|
+
if align == 'horizontal'
|
29
|
+
html.div class: 'col-xs-9 col-xs-offset-3' do
|
30
|
+
html << render_checkbox
|
31
|
+
end
|
32
|
+
else
|
33
|
+
html << render_checkbox
|
34
|
+
end
|
35
|
+
end
|
36
|
+
return html.target!
|
37
|
+
end
|
38
|
+
|
39
|
+
def render_checkbox
|
40
|
+
html = Builder::XmlMarkup.new
|
41
|
+
html << render_write
|
42
|
+
html.text! ' '
|
43
|
+
html << form_builder.label(@method) do
|
44
|
+
form_html = Builder::XmlMarkup.new
|
45
|
+
form_html.text! caption
|
46
|
+
# if not @hide_tooltip and tooltip != ''
|
47
|
+
# form_html.text! ' '
|
48
|
+
# form_html << Tooltip.new(tooltip: tooltip, style: :popover).render
|
49
|
+
# end
|
50
|
+
form_html.target!.html_safe
|
51
|
+
end
|
52
|
+
if not @hide_tooltip and tooltip != ''
|
53
|
+
html.p tooltip, class: 'help-block'
|
54
|
+
end
|
55
|
+
return html.target!
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Interview
|
2
|
+
class Breadcrumbs < Control
|
3
|
+
|
4
|
+
include HasControls
|
5
|
+
|
6
|
+
def render
|
7
|
+
if Object.const_defined?('Gretel')
|
8
|
+
return h.breadcrumbs
|
9
|
+
else
|
10
|
+
html = Builder::XmlMarkup.new
|
11
|
+
html.ol class: 'breadcrumb' do
|
12
|
+
@controls.each do |control|
|
13
|
+
html << control.render
|
14
|
+
end
|
15
|
+
end
|
16
|
+
return html.target!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Interview
|
2
|
+
class ContainerAttribute < Attribute
|
3
|
+
include HasControls
|
4
|
+
|
5
|
+
def value
|
6
|
+
return nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def caption
|
10
|
+
return @caption.to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
def tooltip
|
14
|
+
return ''
|
15
|
+
end
|
16
|
+
|
17
|
+
def render_read
|
18
|
+
html = Builder::XmlMarkup.new
|
19
|
+
@controls.each do |control|
|
20
|
+
html << control.render
|
21
|
+
end
|
22
|
+
return html.target!
|
23
|
+
end
|
24
|
+
|
25
|
+
def render_write
|
26
|
+
render_read
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Interview
|
2
|
+
class Control
|
3
|
+
include Draper::ViewHelpers
|
4
|
+
|
5
|
+
attr_accessor :parent
|
6
|
+
|
7
|
+
def initialize(params={})
|
8
|
+
set_attributes(params)
|
9
|
+
set_defaults
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_attributes(params={})
|
13
|
+
params.each do |key, value|
|
14
|
+
key = "#{key}=".to_sym
|
15
|
+
if respond_to?(key) # and not value.nil?
|
16
|
+
send(key, value)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def set_defaults
|
22
|
+
if self.class.const_defined? 'DEFAULTS'
|
23
|
+
self.class::DEFAULTS.each do |key, value|
|
24
|
+
self.send("#{key}=".to_sym, value)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def ancestors
|
30
|
+
if @parent.nil?
|
31
|
+
return []
|
32
|
+
else
|
33
|
+
return [@parent] + @parent.ancestors
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def find_attribute(attribute)
|
38
|
+
return nil if @parent.nil?
|
39
|
+
if @parent.respond_to? attribute
|
40
|
+
return @parent.send attribute
|
41
|
+
else
|
42
|
+
return @parent.find_attribute attribute
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def find_attribute!(attr_name)
|
47
|
+
attribute = find_attribute(attr_name)
|
48
|
+
throw "Attribute #{attr_name} was not found." if attribute.nil?
|
49
|
+
return attribute
|
50
|
+
end
|
51
|
+
|
52
|
+
def render
|
53
|
+
return ''
|
54
|
+
end
|
55
|
+
|
56
|
+
@definition = ControlDef.new :control
|
57
|
+
|
58
|
+
def self.definition
|
59
|
+
return @definition
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.build(opts={})
|
63
|
+
return @definition.build(opts)
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.inherited(subclass)
|
67
|
+
new_def = @definition.deep_dup
|
68
|
+
new_def.klass = subclass.name.underscore.to_sym
|
69
|
+
subclass.instance_variable_set :@definition, new_def
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class ControlDef
|
2
|
+
|
3
|
+
attr_accessor :klass
|
4
|
+
attr_reader :params, :controls
|
5
|
+
|
6
|
+
def initialize(klass, params={})
|
7
|
+
@klass = klass.to_sym
|
8
|
+
@params = params
|
9
|
+
@controls = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def control(klass, params={}, &block)
|
13
|
+
control = ControlDef.new(klass, params)
|
14
|
+
@controls << control
|
15
|
+
yield(control) if block_given?
|
16
|
+
end
|
17
|
+
|
18
|
+
def build(params={})
|
19
|
+
control = Object::const_get("#{@klass.to_s.camelcase}").new(@params.merge(params))
|
20
|
+
if control.respond_to? :add_controls
|
21
|
+
control.add_controls build_controls_for(control)
|
22
|
+
end
|
23
|
+
return control
|
24
|
+
end
|
25
|
+
|
26
|
+
def build_controls_for(parent_control)
|
27
|
+
return @controls.map { |c| c.build(parent: parent_control) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def deep_dup
|
31
|
+
new_definition = self.class.new(@klass, @params.deep_dup)
|
32
|
+
new_definition.instance_variable_set :@controls, @controls.deep_dup
|
33
|
+
return new_definition
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Interview
|
2
|
+
class DateAttribute < Attribute
|
3
|
+
|
4
|
+
attr_accessor :format
|
5
|
+
|
6
|
+
def render_read
|
7
|
+
return '' if value.nil?
|
8
|
+
if @format
|
9
|
+
return value.strftime(@format)
|
10
|
+
else
|
11
|
+
return h.l value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def render_write
|
16
|
+
form_builder.date_select @method #, {}, {class: 'form-control'}
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Interview
|
2
|
+
class DatetimeAttribute < Attribute
|
3
|
+
|
4
|
+
attr_accessor :format
|
5
|
+
|
6
|
+
def render_read
|
7
|
+
return '' if value.nil?
|
8
|
+
if @format
|
9
|
+
return value.strftime(@format)
|
10
|
+
else
|
11
|
+
return h.l value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def render_write
|
16
|
+
form_builder.date_select @method #, {}, {class: 'form-control'}
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Interview
|
2
|
+
class Dropdown < Control
|
3
|
+
include HasControls
|
4
|
+
|
5
|
+
attr_accessor :caption, :align
|
6
|
+
|
7
|
+
def render
|
8
|
+
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 + ' '
|
12
|
+
html.span '', class: 'caret'
|
13
|
+
end
|
14
|
+
html.ul class: 'dropdown-menu' do
|
15
|
+
@controls.each do |control|
|
16
|
+
html.li do
|
17
|
+
html << control.render
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
return html.target!
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|