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,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