matestack-ui-core 1.0.1 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +782 -16
  3. data/app/concepts/matestack/ui/core/async/async.js +6 -28
  4. data/app/concepts/matestack/ui/core/async/async.rb +7 -10
  5. data/app/concepts/matestack/ui/core/cable/cable.haml +4 -0
  6. data/app/concepts/matestack/ui/core/cable/cable.js +100 -0
  7. data/app/concepts/matestack/ui/core/cable/cable.rb +28 -0
  8. data/app/concepts/matestack/ui/core/cable/children_wrapper.haml +2 -0
  9. data/app/concepts/matestack/ui/core/collection/content/content.js +2 -2
  10. data/app/concepts/matestack/ui/core/collection/content/content.rb +1 -1
  11. data/app/concepts/matestack/ui/core/component/base.rb +10 -4
  12. data/app/concepts/matestack/ui/core/component/component.js +18 -1
  13. data/app/concepts/matestack/ui/core/component/dynamic.rb +1 -1
  14. data/app/concepts/matestack/ui/core/form/checkbox/base.rb +120 -0
  15. data/app/concepts/matestack/ui/core/form/checkbox/checkbox.js +15 -0
  16. data/app/concepts/matestack/ui/core/form/checkbox/checkbox.rb +7 -70
  17. data/app/concepts/matestack/ui/core/form/checkbox/mixin.js +80 -0
  18. data/app/concepts/matestack/ui/core/form/form.js +15 -46
  19. data/app/concepts/matestack/ui/core/form/input/base.rb +75 -0
  20. data/app/concepts/matestack/ui/core/form/input/input.js +15 -0
  21. data/app/concepts/matestack/ui/core/form/input/input.rb +8 -52
  22. data/app/concepts/matestack/ui/core/form/input/mixin.js +55 -0
  23. data/app/concepts/matestack/ui/core/form/radio/base.rb +90 -0
  24. data/app/concepts/matestack/ui/core/form/radio/mixin.js +62 -0
  25. data/app/concepts/matestack/ui/core/form/radio/radio.js +15 -0
  26. data/app/concepts/matestack/ui/core/form/radio/radio.rb +7 -62
  27. data/app/concepts/matestack/ui/core/form/select/base.rb +98 -0
  28. data/app/concepts/matestack/ui/core/form/select/mixin.js +58 -0
  29. data/app/concepts/matestack/ui/core/form/select/select.js +15 -0
  30. data/app/concepts/matestack/ui/core/form/select/select.rb +11 -60
  31. data/app/concepts/matestack/ui/core/form/submit/base.rb +12 -0
  32. data/app/concepts/matestack/ui/core/form/submit/submit.js +19 -0
  33. data/app/concepts/matestack/ui/core/form/submit/submit.rb +9 -6
  34. data/app/concepts/matestack/ui/core/form/textarea/base.rb +49 -0
  35. data/app/concepts/matestack/ui/core/form/textarea/mixin.js +41 -0
  36. data/app/concepts/matestack/ui/core/form/textarea/textarea.js +15 -0
  37. data/app/concepts/matestack/ui/core/form/textarea/textarea.rb +10 -21
  38. data/app/concepts/matestack/ui/core/js/core.js +12 -0
  39. data/app/concepts/matestack/ui/core/{form/submit/submit.haml → select/select.haml} +1 -1
  40. data/app/concepts/matestack/ui/core/select/select.rb +7 -0
  41. data/app/helpers/matestack/ui/core/application_helper.rb +6 -3
  42. data/app/javascript/matestack-ui-core/index.js +12 -2
  43. data/app/lib/matestack/ui/core/has_view_context.rb +4 -2
  44. data/app/lib/matestack/ui/core/rendering/main_renderer.rb +4 -1
  45. data/lib/matestack/ui/core/components.rb +4 -1
  46. data/lib/matestack/ui/core/version.rb +1 -1
  47. data/vendor/assets/javascripts/dist/matestack-ui-core.js +768 -98
  48. data/vendor/assets/javascripts/dist/matestack-ui-core.js.map +1 -1
  49. data/vendor/assets/javascripts/dist/matestack-ui-core.min.js +1 -1
  50. data/vendor/assets/javascripts/dist/matestack-ui-core.min.js.br +0 -0
  51. data/vendor/assets/javascripts/dist/matestack-ui-core.min.js.gz +0 -0
  52. data/vendor/assets/javascripts/dist/matestack-ui-core.min.js.map +1 -1
  53. data/vendor/assets/javascripts/dist/matestack-ui-core.min.js.map.br +0 -0
  54. data/vendor/assets/javascripts/dist/matestack-ui-core.min.js.map.gz +0 -0
  55. metadata +25 -7
  56. data/app/concepts/matestack/ui/core/component/rerender.rb +0 -8
  57. data/app/concepts/matestack/ui/core/form/select/select.haml +0 -9
@@ -76,19 +76,9 @@ const componentDef = {
76
76
  },
77
77
  created: function () {
78
78
  const self = this
79
- if(this.componentConfig["show_on"] != undefined){
80
- this.showing = false
81
- var show_events = this.componentConfig["show_on"].split(",")
82
- show_events.forEach(show_event => matestackEventHub.$on(show_event.trim(), self.show));
83
- }
84
- if(this.componentConfig["hide_on"] != undefined){
85
- var hide_events = this.componentConfig["hide_on"].split(",")
86
- hide_events.forEach(hide_event => matestackEventHub.$on(hide_event.trim(), self.hide));
87
- }
88
- if(this.componentConfig["rerender_on"] != undefined){
89
- var rerender_events = this.componentConfig["rerender_on"].split(",")
90
- rerender_events.forEach(rerender_event => matestackEventHub.$on(rerender_event.trim(), self.rerender));
91
- }
79
+ self.registerEvents(this.componentConfig['show_on'], self.show)
80
+ self.registerEvents(this.componentConfig['hide_on'], self.hide)
81
+ self.registerEvents(this.componentConfig['rerender_on'], self.rerender)
92
82
  if(this.componentConfig["show_on"] != undefined){
93
83
  this.showing = false
94
84
  }
@@ -106,21 +96,9 @@ const componentDef = {
106
96
  beforeDestroy: function() {
107
97
  const self = this
108
98
  clearTimeout(self.hideAfterTimeout)
109
- matestackEventHub.$off(this.componentConfig["rerender_on"], self.rerender);
110
- matestackEventHub.$off(this.componentConfig["show_on"], self.show);
111
- matestackEventHub.$off(this.componentConfig["hide_on"], self.hide);
112
- if(this.componentConfig["show_on"] != undefined){
113
- var shown_events = this.componentConfig["show_on"].split(",")
114
- shown_events.forEach(show_event => matestackEventHub.$off(show_event.trim(), self.show));
115
- }
116
- if(this.componentConfig["hide_on"] != undefined){
117
- var hiden_events = this.componentConfig["hide_on"].split(",")
118
- hiden_events.forEach(hide_event => matestackEventHub.$off(hide_event.trim(), self.hide));
119
- }
120
- if(this.componentConfig["rerender_on"] != undefined){
121
- var rerender_events = this.componentConfig["rerender_on"].split(",")
122
- rerender_events.forEach(rerender_event => matestackEventHub.$off(rerender_event.trim(), self.rerender));
123
- }
99
+ self.removeEvents(this.componentConfig["show_on"], self.show)
100
+ self.removeEvents(this.componentConfig["hide_on"], self.hide)
101
+ self.removeEvents(this.componentConfig["rerender_on"], self.rerender)
124
102
  },
125
103
  components: {
126
104
  VRuntimeTemplate: VRuntimeTemplate
@@ -1,24 +1,21 @@
1
1
  module Matestack::Ui::Core::Async
2
- class Async < Matestack::Ui::Core::Component::Rerender
2
+ class Async < Matestack::Ui::Core::Component::Dynamic
3
3
  vue_js_component_name "matestack-ui-core-async"
4
4
 
5
- optional :id # will be required in 1.0.0
5
+ requires :id # required since 1.1.0
6
6
 
7
7
  def initialize(*args)
8
8
  super
9
- ActiveSupport::Deprecation.warn(
10
- 'Calling async components without id is deprecated. Instead provide a unique id for async components.'
11
- ) if id.blank?
12
- @component_config[:component_key] = id || "async_#{Digest::SHA256.hexdigest(caller[3])}"
13
- if @included_config.present? && @included_config[:isolated_parent_class].present?
14
- @component_config[:parent_class] = @included_config[:isolated_parent_class]
9
+ component_config[:component_key] = id
10
+ if included_config.present? && included_config[:isolated_parent_class].present?
11
+ component_config[:parent_class] = included_config[:isolated_parent_class]
15
12
  end
16
13
  end
17
14
 
18
15
  def children_wrapper_attributes
19
16
  html_attributes.merge({
20
17
  "v-if": "showing",
21
- id: @component_config[:component_key]
18
+ id: component_config[:component_key]
22
19
  })
23
20
  end
24
21
 
@@ -33,7 +30,7 @@ module Matestack::Ui::Core::Async
33
30
  end
34
31
 
35
32
  def get_component_key
36
- @component_config[:component_key]
33
+ component_config[:component_key]
37
34
  end
38
35
 
39
36
  end
@@ -0,0 +1,4 @@
1
+ %component{dynamic_tag_attributes.merge('v-bind:initial-template': "#{render_content.to_json}")}
2
+ %div{class: "matestack-cable-component-container", "v-bind:class": "{ 'loading': loading === true }"}
3
+ %div{class: "matestack-cable-component-wrapper", "v-if": "cableTemplate != null", "v-bind:class": "{ 'loading': loading === true }"}
4
+ %v-runtime-template{":template":"cableTemplate"}
@@ -0,0 +1,100 @@
1
+ import Vue from 'vue/dist/vue.esm'
2
+ import VRuntimeTemplate from "v-runtime-template"
3
+ import matestackEventHub from '../js/event-hub'
4
+ import componentMixin from '../component/component'
5
+
6
+ const componentDef = {
7
+ mixins: [componentMixin],
8
+ props: {
9
+ initialTemplate: String,
10
+ },
11
+ data: function(){
12
+ return {
13
+ cableTemplate: null,
14
+ cableTemplateDomElement: null,
15
+ loading: false,
16
+ event: {
17
+ data: {}
18
+ }
19
+ }
20
+ },
21
+ methods: {
22
+ append: function(payload){
23
+ var html = this.formatPayload(payload)
24
+ this.cableTemplateDomElement.insertAdjacentHTML(
25
+ 'beforeend',
26
+ html.join('')
27
+ )
28
+ this.updateCableTemplate()
29
+ },
30
+ prepend: function(payload){
31
+ var html = this.formatPayload(payload)
32
+ this.cableTemplateDomElement.insertAdjacentHTML(
33
+ 'afterbegin',
34
+ html.join('')
35
+ )
36
+ this.updateCableTemplate()
37
+ },
38
+ delete: function(payload){
39
+ var ids = this.formatPayload(payload)
40
+ ids.forEach(id =>
41
+ this.cableTemplateDomElement.querySelector('#' + id).remove()
42
+ )
43
+ this.updateCableTemplate()
44
+ },
45
+ update: function(payload){
46
+ const self = this
47
+ var html = this.formatPayload(payload)
48
+ html.forEach(function(elem){
49
+ var dom_elem = document.createElement('div')
50
+ dom_elem.innerHTML = elem
51
+ var id = dom_elem.firstChild.id
52
+ var old_elem = self.cableTemplateDomElement.querySelector('#' + id)
53
+ old_elem.parentNode.replaceChild(dom_elem.firstChild, old_elem)
54
+ })
55
+ this.updateCableTemplate()
56
+ },
57
+ replace: function(payload){
58
+ var html = this.formatPayload(payload)
59
+ this.cableTemplateDomElement.innerHTML = html.join('')
60
+ this.updateCableTemplate()
61
+ },
62
+ updateCableTemplate: function(){
63
+ this.cableTemplate = this.cableTemplateDomElement.outerHTML
64
+ },
65
+ formatPayload: function(payload){
66
+ if(!Array.isArray(payload.data)){
67
+ return [payload.data]
68
+ }
69
+ return payload.data
70
+ },
71
+ },
72
+ mounted: function() {
73
+ const self = this
74
+ var dom_elem = document.createElement('div')
75
+ dom_elem.innerHTML = this.initialTemplate
76
+ this.cableTemplateDomElement = dom_elem.querySelector("#" + this.componentConfig["id"])
77
+ this.cableTemplate = this.cableTemplateDomElement.outerHTML
78
+ this.registerEvents(this.componentConfig['append_on'], self.append)
79
+ this.registerEvents(this.componentConfig['prepend_on'], self.prepend)
80
+ this.registerEvents(this.componentConfig['delete_on'], self.delete)
81
+ this.registerEvents(this.componentConfig['update_on'], self.update)
82
+ this.registerEvents(this.componentConfig['replace_on'], self.replace)
83
+ },
84
+ beforeDestroy: function() {
85
+ const self = this
86
+ this.cableTemplate = null
87
+ this.removeEvents(this.componentConfig['append_on'], self.append)
88
+ this.removeEvents(this.componentConfig['prepend_on'], self.prepend)
89
+ this.removeEvents(this.componentConfig['delete_on'], self.delete)
90
+ this.removeEvents(this.componentConfig['update_on'], self.update)
91
+ this.removeEvents(this.componentConfig['replace_on'], self.replace)
92
+ },
93
+ components: {
94
+ VRuntimeTemplate: VRuntimeTemplate
95
+ }
96
+ }
97
+
98
+ let component = Vue.component('matestack-ui-core-cable', componentDef)
99
+
100
+ export default componentDef
@@ -0,0 +1,28 @@
1
+ module Matestack::Ui::Core::Cable
2
+ class Cable < Matestack::Ui::Core::Component::Dynamic
3
+ vue_js_component_name 'matestack-ui-core-cable'
4
+
5
+ requires :id
6
+
7
+ def setup
8
+ component_config[:component_key] = id
9
+ end
10
+
11
+ def show
12
+ render :cable
13
+ end
14
+
15
+ def render_content
16
+ render :children_wrapper do
17
+ render :children
18
+ end
19
+ end
20
+
21
+ def children_wrapper_attributes
22
+ html_attributes.merge({
23
+ id: component_config[:component_key]
24
+ })
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,2 @@
1
+ %div{ children_wrapper_attributes.merge(class: "matestack-cable-component-root") }
2
+ =yield
@@ -2,10 +2,10 @@ import Vue from 'vue/dist/vue.esm'
2
2
  import matestackEventHub from '../../js/event-hub'
3
3
  import queryParamsHelper from '../../js/helpers/query-params-helper'
4
4
  import componentMixin from '../../component/component'
5
- import asyncMixin from '../../async/async'
5
+ // import asyncMixin from '../../async/async'
6
6
 
7
7
  const componentDef = {
8
- mixins: [componentMixin, asyncMixin],
8
+ mixins: [componentMixin],
9
9
  data: function(){
10
10
  return {
11
11
  currentLimit: null,
@@ -1,5 +1,5 @@
1
1
  module Matestack::Ui::Core::Collection::Content
2
- class Content < Matestack::Ui::Core::Component::Rerender
2
+ class Content < Matestack::Ui::Core::Component::Dynamic
3
3
  vue_js_component_name 'matestack-ui-core-collection-content'
4
4
 
5
5
  def setup
@@ -4,12 +4,11 @@ module Matestack::Ui::Core::Component
4
4
  include Matestack::Ui::Core::HasViewContext
5
5
  include Matestack::Ui::Core::HtmlAttributes
6
6
  include Matestack::Ui::Core::Properties
7
+ include Matestack::Ui::Core::DSL
7
8
 
8
9
  # define html global attributes
9
10
  html_attributes *HTML_GLOBAL_ATTRIBUTES, *HTML_EVENT_ATTRIBUTES
10
11
 
11
- # probably need to remove for other tests to be green again
12
- include Matestack::Ui::Core::DSL
13
12
 
14
13
  view_paths << "#{Matestack::Ui::Core::Engine.root}/app/concepts"
15
14
  view_paths << "#{::Rails.root}#{'/' unless ::Rails.root.nil?}app/matestack"
@@ -99,6 +98,11 @@ module Matestack::Ui::Core::Component
99
98
  def get_included_config
100
99
  @included_config
101
100
  end
101
+ alias :included_config :get_included_config
102
+
103
+ def component_config
104
+ @component_config
105
+ end
102
106
 
103
107
  # TODO: modifies/recreates view lookup paths on every invocation?!
104
108
  # At least memoize it I guess...
@@ -161,8 +165,10 @@ module Matestack::Ui::Core::Component
161
165
  def params
162
166
  if @matestack_context.present? && @matestack_context[:controller].present?
163
167
  @matestack_context[:controller].params
164
- else
168
+ elsif context.present? && context[:params]
165
169
  context[:params]
170
+ else
171
+ ActionController::Parameters.new({})
166
172
  end
167
173
  end
168
174
 
@@ -239,7 +245,7 @@ module Matestack::Ui::Core::Component
239
245
 
240
246
  # check only allowed keys are passed to isolated components
241
247
  if child_class < Matestack::Ui::Core::Isolated::Isolated
242
- unless args.empty? || args[0].keys.all? { |key| [:defer, :public_options, :rerender_on, :init_on, :rerender_delay, :matestack_context].include? key }
248
+ unless args.empty? || args[0].keys.all? { |key| [:defer, :public_options, :rerender_on, :init_on, :rerender_delay, :matestack_context, :context].include? key }
243
249
  raise "isolated components can only take params in a public_options hash, which will be exposed to the client side in order to perform an async request with these params."
244
250
  end
245
251
  if args.any? { |arg| arg[:init_on].present? } && @matestack_skip_defer == true
@@ -1,5 +1,22 @@
1
+ import matestackEventHub from '../js/event-hub'
2
+
1
3
  const componentMixin = {
2
- props: ['componentConfig', 'params']
4
+ props: ['componentConfig', 'params'],
5
+ methods: {
6
+ registerEvents: function(events, callback){
7
+ if(events != undefined){
8
+ var event_names = events.split(",")
9
+ event_names.forEach(event_name => matestackEventHub.$on(event_name.trim(), callback));
10
+ }
11
+ },
12
+ removeEvents: function(events, callback){
13
+ if(events != undefined){
14
+ var event_names = events.split(",")
15
+ event_names.forEach(event_name => matestackEventHub.$off(event_name.trim(), callback));
16
+ }
17
+ }
18
+ }
19
+
3
20
  }
4
21
 
5
22
  export default componentMixin
@@ -16,7 +16,7 @@ module Matestack::Ui::Core::Component
16
16
  "is": get_vue_js_name,
17
17
  "ref": component_id,
18
18
  ":params": params.except(:controller, :action).to_json,
19
- ":component-config": @component_config.to_json,
19
+ ":component-config": component_config.to_json,
20
20
  "inline-template": true,
21
21
  }
22
22
  attrs.merge!(options[:attributes]) unless options[:attributes].nil?
@@ -0,0 +1,120 @@
1
+ require_relative '../utils'
2
+ require_relative '../has_errors'
3
+ module Matestack::Ui::Core::Form::Checkbox
4
+ class Base < Matestack::Ui::Core::Component::Dynamic
5
+ include Matestack::Ui::Core::Form::Utils
6
+ include Matestack::Ui::Core::Form::HasInputHtmlAttributes
7
+ include Matestack::Ui::Core::Form::HasErrors
8
+
9
+ requires :key
10
+ optional :value, :false_value, :multiple, :init, for: { as: :input_for }, label: { as: :input_label }, options: { as: :checkbox_options }
11
+
12
+ def component_id
13
+ "checkbox-component-for-#{attr_key}"
14
+ end
15
+
16
+ def input_key
17
+ "$parent.data[\"#{key}\"]"
18
+ end
19
+
20
+ def error_key
21
+ "$parent.errors[\"#{key}\"]"
22
+ end
23
+
24
+ def change_event
25
+ "inputChanged('#{attr_key}')"
26
+ end
27
+
28
+ def render_options
29
+ # multiple
30
+ if checkbox_options
31
+ checkbox_options.to_a.each do |item|
32
+ input html_attributes.merge(
33
+ attributes: vue_attributes,
34
+ type: :checkbox,
35
+ id: "#{id_for_item(item_value(item))}",
36
+ name: item_name(item),
37
+ value: item_value(item)
38
+ )
39
+ label text: item_name(item), for: id_for_item(item_value(item))
40
+ end
41
+ # checked/unchecked checkbox (true/false checkbox)
42
+ else
43
+ input html_attributes.merge(
44
+ attributes: vue_attributes_for_single_input,
45
+ type: :hidden,
46
+ id: id_for_item(value),
47
+ value: (false_value || 0)
48
+ )
49
+
50
+ input html_attributes.merge(
51
+ attributes: vue_attributes_for_single_input,
52
+ type: :checkbox,
53
+ id: id_for_item(value),
54
+ value: checked_value
55
+ )
56
+
57
+ label text: input_label, for: id_for_item(value)
58
+ end
59
+ end
60
+
61
+ def vue_attributes
62
+ (options[:attributes] || {}).merge({
63
+ "@change": change_event,
64
+ ref: "select.multiple.#{attr_key}",
65
+ 'init-value': init_value,
66
+ 'v-bind:class': "{ '#{input_error_class}': #{error_key} }",
67
+ 'value-type': value_type,
68
+ "#{v_model_type}": input_key,
69
+ })
70
+ end
71
+
72
+ def vue_attributes_for_single_input
73
+ (options[:attributes] || {}).merge({
74
+ "@change": change_event,
75
+ ref: "input.#{attr_key}",
76
+ 'init-value': init_value_for_single_input,
77
+ 'v-bind:class': "{ '#{input_error_class}': #{error_key} }",
78
+ "#{v_model_type}": input_key
79
+ })
80
+ end
81
+
82
+ def init_value_for_single_input
83
+ if init_value == true || init_value == 1
84
+ return "true"
85
+ end
86
+ if init_value == false || init_value == 0
87
+ return "false"
88
+ end
89
+ end
90
+
91
+ def value_type
92
+ item_value(checkbox_options.first).is_a?(Integer) ? Integer : nil
93
+ end
94
+
95
+ def item_value(item)
96
+ item.is_a?(Array) ? item.last : item
97
+ end
98
+
99
+ def item_name(item)
100
+ item.is_a?(Array) ? item.first : item
101
+ end
102
+
103
+ def checked_value
104
+ value || 1
105
+ end
106
+
107
+ def v_model_type
108
+ if checkbox_options && checkbox_options.first.is_a?(Integer)
109
+ 'v-model.number'
110
+ else
111
+ 'v-model'
112
+ end
113
+ end
114
+
115
+ def id_for_item(value)
116
+ "#{html_attributes[:id]}_#{value}"
117
+ end
118
+
119
+ end
120
+ end