interview 0.0.1 → 0.0.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 (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,8 @@
1
+ de:
2
+ views:
3
+ sure: 'Bist du sicher?'
4
+ add: "Hinzufügen"
5
+ new: "%{model} erstellen"
6
+ edit: "%{model} bearbeiten"
7
+ nested_form_add: "%{association} hinzufügen"
8
+ nested_form_remove: "%{association} entfernen"
@@ -0,0 +1,6 @@
1
+ class <%= singular_table_name.classify %>Card < Interview::CardView
2
+ <% attributes.each do |attribute| -%>
3
+ control class: '<%= attribute_class_name(attribute) %>',
4
+ method: '<%= attribute.name %>'
5
+ <% end -%>
6
+ end
@@ -0,0 +1,6 @@
1
+ class <%= singular_table_name.classify %>Form < Interview::FormView
2
+ <% attributes.each do |attribute| -%>
3
+ control class: '<%= attribute_class_name(attribute) %>',
4
+ method: '<%= attribute.name %>'
5
+ <% end -%>
6
+ end
@@ -0,0 +1,6 @@
1
+ class <%= singular_table_name.classify %>List < Interview::GridView
2
+ <% attributes.each do |attribute| -%>
3
+ control class: '<%= attribute_class_name(attribute) %>',
4
+ method: '<%= attribute.name %>'
5
+ <% end -%>
6
+ end
@@ -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,10 @@
1
+ module Interview
2
+ class DecimalAttribute < Attribute
3
+
4
+ def render_read
5
+ return '' if value.nil?
6
+ return h.number_with_precision(value).to_s
7
+ end
8
+
9
+ end
10
+ 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