matestack-ui-core 1.0.1 → 1.3.2

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