matestack-ui-vuejs 3.0.0.rc1

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 (77) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +492 -0
  4. data/Rakefile +64 -0
  5. data/lib/matestack/ui/component.rb +1 -0
  6. data/lib/matestack/ui/isolated_component.rb +1 -0
  7. data/lib/matestack/ui/vue_js/components/action.js +70 -0
  8. data/lib/matestack/ui/vue_js/components/action.rb +46 -0
  9. data/lib/matestack/ui/vue_js/components/app.js +122 -0
  10. data/lib/matestack/ui/vue_js/components/app.rb +46 -0
  11. data/lib/matestack/ui/vue_js/components/async.js +104 -0
  12. data/lib/matestack/ui/vue_js/components/async.rb +84 -0
  13. data/lib/matestack/ui/vue_js/components/cable.js +96 -0
  14. data/lib/matestack/ui/vue_js/components/cable.rb +69 -0
  15. data/lib/matestack/ui/vue_js/components/collection/content.js +96 -0
  16. data/lib/matestack/ui/vue_js/components/collection/content.rb +32 -0
  17. data/lib/matestack/ui/vue_js/components/collection/filter.js +45 -0
  18. data/lib/matestack/ui/vue_js/components/collection/filter.rb +29 -0
  19. data/lib/matestack/ui/vue_js/components/collection/filter_reset.rb +19 -0
  20. data/lib/matestack/ui/vue_js/components/collection/helper.rb +128 -0
  21. data/lib/matestack/ui/vue_js/components/collection/next.rb +19 -0
  22. data/lib/matestack/ui/vue_js/components/collection/order.js +45 -0
  23. data/lib/matestack/ui/vue_js/components/collection/order.rb +28 -0
  24. data/lib/matestack/ui/vue_js/components/collection/order_toggle.rb +21 -0
  25. data/lib/matestack/ui/vue_js/components/collection/order_toggle_indicator.rb +30 -0
  26. data/lib/matestack/ui/vue_js/components/collection/page.rb +21 -0
  27. data/lib/matestack/ui/vue_js/components/collection/previous.rb +19 -0
  28. data/lib/matestack/ui/vue_js/components/form/base.rb +179 -0
  29. data/lib/matestack/ui/vue_js/components/form/checkbox.js +13 -0
  30. data/lib/matestack/ui/vue_js/components/form/checkbox.rb +109 -0
  31. data/lib/matestack/ui/vue_js/components/form/checkbox_mixin.js +90 -0
  32. data/lib/matestack/ui/vue_js/components/form/context.rb +15 -0
  33. data/lib/matestack/ui/vue_js/components/form/fields_for_add_item.js +50 -0
  34. data/lib/matestack/ui/vue_js/components/form/fields_for_add_item.rb +35 -0
  35. data/lib/matestack/ui/vue_js/components/form/fields_for_remove_item.rb +19 -0
  36. data/lib/matestack/ui/vue_js/components/form/form.js +276 -0
  37. data/lib/matestack/ui/vue_js/components/form/form.rb +77 -0
  38. data/lib/matestack/ui/vue_js/components/form/input.js +13 -0
  39. data/lib/matestack/ui/vue_js/components/form/input.rb +54 -0
  40. data/lib/matestack/ui/vue_js/components/form/input_mixin.js +79 -0
  41. data/lib/matestack/ui/vue_js/components/form/nested_form.js +153 -0
  42. data/lib/matestack/ui/vue_js/components/form/nested_form.rb +57 -0
  43. data/lib/matestack/ui/vue_js/components/form/radio.js +13 -0
  44. data/lib/matestack/ui/vue_js/components/form/radio.rb +85 -0
  45. data/lib/matestack/ui/vue_js/components/form/radio_mixin.js +75 -0
  46. data/lib/matestack/ui/vue_js/components/form/select.js +13 -0
  47. data/lib/matestack/ui/vue_js/components/form/select.rb +96 -0
  48. data/lib/matestack/ui/vue_js/components/form/select_mixin.js +76 -0
  49. data/lib/matestack/ui/vue_js/components/form/textarea.js +13 -0
  50. data/lib/matestack/ui/vue_js/components/form/textarea.rb +37 -0
  51. data/lib/matestack/ui/vue_js/components/form/textarea_mixin.js +54 -0
  52. data/lib/matestack/ui/vue_js/components/helpers.js +5 -0
  53. data/lib/matestack/ui/vue_js/components/isolated.js +105 -0
  54. data/lib/matestack/ui/vue_js/components/isolated.rb +86 -0
  55. data/lib/matestack/ui/vue_js/components/mixin.js +66 -0
  56. data/lib/matestack/ui/vue_js/components/onclick.js +18 -0
  57. data/lib/matestack/ui/vue_js/components/onclick.rb +37 -0
  58. data/lib/matestack/ui/vue_js/components/page_switch.js +24 -0
  59. data/lib/matestack/ui/vue_js/components/page_switch.rb +35 -0
  60. data/lib/matestack/ui/vue_js/components/runtime_render.js +17 -0
  61. data/lib/matestack/ui/vue_js/components/toggle.js +70 -0
  62. data/lib/matestack/ui/vue_js/components/toggle.rb +38 -0
  63. data/lib/matestack/ui/vue_js/components/transition.js +44 -0
  64. data/lib/matestack/ui/vue_js/components/transition.rb +40 -0
  65. data/lib/matestack/ui/vue_js/components/transition_handling_mixin.js +100 -0
  66. data/lib/matestack/ui/vue_js/components.rb +118 -0
  67. data/lib/matestack/ui/vue_js/event_hub.js +12 -0
  68. data/lib/matestack/ui/vue_js/helpers/query_params_helper.js +56 -0
  69. data/lib/matestack/ui/vue_js/index.js +94 -0
  70. data/lib/matestack/ui/vue_js/initialize.rb +10 -0
  71. data/lib/matestack/ui/vue_js/utils.rb +67 -0
  72. data/lib/matestack/ui/vue_js/version.rb +7 -0
  73. data/lib/matestack/ui/vue_js/vue.rb +75 -0
  74. data/lib/matestack/ui/vue_js/vue_attributes.rb +13 -0
  75. data/lib/matestack/ui/vue_js.rb +52 -0
  76. data/lib/matestack/ui/vue_js_component.rb +1 -0
  77. metadata +150 -0
@@ -0,0 +1,54 @@
1
+ module Matestack
2
+ module Ui
3
+ module VueJs
4
+ module Components
5
+ module Form
6
+ class Input < Matestack::Ui::VueJs::Components::Form::Base
7
+ vue_name 'matestack-ui-core-form-input'
8
+
9
+ def initialize(*)
10
+ super
11
+ if ctx.type.to_s == "file"
12
+ if !form_context.is_nested_form? && form_context.multipart_option != true
13
+ raise "File Upload requires `multipart: true` in Form Config"
14
+ end
15
+ if form_context.is_nested_form? && form_context.parent_form_context.multipart_option != true
16
+ raise "File Upload requires `multipart: true` in Form Config"
17
+ end
18
+ end
19
+ end
20
+
21
+ def response
22
+ div class: 'matestack-ui-core-form-input' do
23
+ label input_label, ":for": id if input_label
24
+ input input_attributes
25
+ render_errors
26
+ end
27
+ end
28
+
29
+ def component_id
30
+ "input-component-for-#{attribute_key}"
31
+ end
32
+
33
+ def input_attributes
34
+ attributes
35
+ end
36
+
37
+ def init_value
38
+ return nil if ctx.type.to_s == "file"
39
+ super
40
+ end
41
+
42
+ def vue_props
43
+ {
44
+ init_value: init_value,
45
+ key: key,
46
+ }
47
+ end
48
+
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,79 @@
1
+ import matestackEventHub from '../../event_hub'
2
+
3
+ const formInputMixin = {
4
+ inject: [
5
+ 'parentFormUid',
6
+ 'parentFormData',
7
+ 'parentFormErrors',
8
+ 'parentFormLoading',
9
+ 'parentFormIsNestedForm',
10
+ 'parentFormResetErrors',
11
+ 'parentNestedFormRuntimeId'
12
+ ],
13
+ methods: {
14
+ initialize: function(){
15
+ const self = this
16
+ let data = {};
17
+
18
+ for (let key in self.getRefs()) {
19
+ if (key.startsWith("input.")) {
20
+ let initValue = self.getRefs()[key]["attributes"]["init-value"];
21
+
22
+ self.parentFormData[key.replace("input.", "")] = null
23
+
24
+ if (initValue) {
25
+ self.setValue(initValue["value"])
26
+ self.afterInitialize(initValue["value"])
27
+ } else {
28
+ self.setValue(null)
29
+ self.afterInitialize(null)
30
+ }
31
+ }
32
+ }
33
+
34
+ },
35
+ filesAdded: function (key) {
36
+ const dataTransfer = event.dataTransfer || event.target;
37
+ const files = dataTransfer.files;
38
+ if (event.target.attributes.multiple) {
39
+ this.parentFormData[key] = [];
40
+ for (let index in files) {
41
+ if (files[index] instanceof File) {
42
+ this.parentFormData[key].push(files[index]);
43
+ }
44
+ }
45
+ } else {
46
+ this.parentFormData[key] = files[0];
47
+ }
48
+ },
49
+ inputChanged: function (key) {
50
+ if (this.parentFormIsNestedForm){
51
+ this.parentFormData["_destroy"] = false;
52
+ }
53
+ this.parentFormResetErrors(key);
54
+
55
+ },
56
+ afterInitialize: function(value){
57
+ // can be used in the main component for further initialization steps
58
+ },
59
+ setValue: function (value){
60
+ if(this.getRefs()["input."+this.props["key"]]){
61
+ this.getRefs()["input."+this.props["key"]].value = value; // reset file upload inputs properly
62
+ }
63
+ if(this.getRefs()["input."+this.props["key"]+"[]"]){
64
+ this.getRefs()["input."+this.props["key"]+"[]"].value = value; // reset multiple file upload inputs properly
65
+ }
66
+ this.parentFormData[this.props["key"]] = value;
67
+ }
68
+ },
69
+ mounted: function(){
70
+ this.registerScopedEvent("init", this.initialize, this.parentFormUid)
71
+ },
72
+ beforeUnmount: function(){
73
+ this.removeScopedEvent("init", this.initialize, this.parentFormUid)
74
+ }
75
+
76
+
77
+ }
78
+
79
+ export default formInputMixin
@@ -0,0 +1,153 @@
1
+ import { computed } from "vue";
2
+ import axios from "axios";
3
+
4
+ import matestackEventHub from "../../event_hub";
5
+ import componentMixin from "../mixin";
6
+ import componentHelpers from "../helpers";
7
+
8
+ const componentDef = {
9
+ mixins: [componentMixin],
10
+ template: componentHelpers.inlineTemplate,
11
+ data: function () {
12
+ return {
13
+ data: {},
14
+ errors: {},
15
+ isNestedForm: true,
16
+ hideNestedForm: false,
17
+ nestedFormRuntimeId: "",
18
+ nestedFormServerErrorIndex: "",
19
+ };
20
+ },
21
+ provide: function() {
22
+ return {
23
+ parentFormUid: computed(() => this.props["component_uid"]),
24
+ parentFormData: computed(() => this.data),
25
+ parentFormErrors: computed(() => this.errors),
26
+ parentNestedFormRuntimeId: computed(() => this.nestedFormRuntimeId),
27
+ parentFormMapToNestedForms: this.mapToNestedForms,
28
+ parentFormSetErrors: this.setErrors,
29
+ parentFormResetErrors: this.resetErrors,
30
+ }
31
+ },
32
+ inject: [
33
+ 'parentFormData',
34
+ 'parentFormErrors',
35
+ 'parentNestedForms',
36
+ 'parentDeletedNestedForms',
37
+ 'parentFormMapToNestedForms'
38
+ ],
39
+ methods: {
40
+ initDataKey: function (key, initValue) {
41
+ this.data[key] = initValue;
42
+ },
43
+ updateFormValue: function (key, value) {
44
+ this.data[key] = value;
45
+ },
46
+ hasErrors: function(){
47
+ //https://stackoverflow.com/a/27709663/13886137
48
+ for (var key in this.errors) {
49
+ if (this.errors[key] !== null && this.errors[key] != ""){
50
+ return true;
51
+ }
52
+ }
53
+ return false;
54
+ },
55
+ resetErrors: function (key) {
56
+ if (this.errors[key]) {
57
+ delete this.errors[key];
58
+ }
59
+ var serverErrorKey = this.props["fields_for"].replace("_attributes", "")+"["+this.nestedFormServerErrorIndex+"]."+key
60
+ if (this.parentFormErrors[serverErrorKey]) {
61
+ delete this.parentFormErrors[serverErrorKey];
62
+ }
63
+ },
64
+ setErrors: function(errors){
65
+ this.errors = errors;
66
+ },
67
+ setNestedFormServerErrorIndex: function(value){
68
+ this.nestedFormServerErrorIndex = value;
69
+ },
70
+ setErrorKey: function(key, value){
71
+ this.errors[key] = value;
72
+ },
73
+ flushErrors: function(key, value){
74
+ this.errors = {};
75
+ },
76
+ removeItem: function(){
77
+ this.data["_destroy"] = true
78
+ this.hideNestedForm = true;
79
+ var id = parseInt(this.nestedFormRuntimeId.replace("_"+this.props["fields_for"]+"_child_", ""));
80
+ this.parentDeletedNestedForms[this.props["fields_for"]].push(id);
81
+ var serverErrorKey = this.props["fields_for"].replace("_attributes", "")+"["+this.nestedFormServerErrorIndex+"]."
82
+ var self = this;
83
+ Object.keys(self.parentFormErrors).forEach(function(errorKey){
84
+ if (errorKey.lastIndexOf(serverErrorKey, 0) == 0) {
85
+ delete self.parentFormErrors[errorKey];
86
+ }
87
+ });
88
+ },
89
+ initValues: function () {
90
+ this.emitScopedEvent("init") // received by child input components
91
+ }
92
+ },
93
+ mounted: function () {
94
+ var self = this;
95
+
96
+ this.data = { "_destroy": false };
97
+
98
+ //initialize nestedForm data in parent form if required
99
+ if(this.parentFormData[this.props["fields_for"]] == undefined){
100
+ this.parentFormData[this.props["fields_for"]] = [];
101
+ }
102
+ if(this.parentNestedForms[this.props["fields_for"]] == undefined){
103
+ this.parentNestedForms[this.props["fields_for"]] = [];
104
+ }
105
+ if(this.parentDeletedNestedForms[this.props["fields_for"]] == undefined){
106
+ this.parentDeletedNestedForms[this.props["fields_for"]] = [];
107
+ }
108
+
109
+ var id = parseInt(self.getElement().querySelector('.matestack-form-fields-for').id.replace(this.props["fields_for"]+"_child_", ""))
110
+
111
+ //setup data binding for serverside rendered nested forms
112
+ if (isNaN(id)){
113
+ id = this.parentNestedForms[this.props["fields_for"]].length
114
+ this.nestedFormRuntimeId = "_"+this.props["fields_for"]+"_child_"+id
115
+ this.getElement().id = this.props["fields_for"]+"_child_"+id
116
+ this.initValues()
117
+ this.parentFormData[this.props["fields_for"]].push(this.data);
118
+ this.parentNestedForms[this.props["fields_for"]].push(this);
119
+ }
120
+
121
+ //setup data binding for runtime nested forms (dynamic add via matestack-ui-core-runtime-render)
122
+ if (!isNaN(id)){
123
+ this.nestedFormRuntimeId = "_"+this.props["fields_for"]+"_child_"+id
124
+ if(this.parentFormData[this.props["fields_for"]][id] == undefined){
125
+ //new runtime form
126
+ this.initValues()
127
+ this.parentFormData[this.props["fields_for"]].push(this.data);
128
+ this.parentNestedForms[this.props["fields_for"]].push(this);
129
+ }else{
130
+ //retreive state for existing runtime form (after remount for example)
131
+ this.data = this.parentFormData[this.props["fields_for"]][id]
132
+ if (this.data["_destroy"] == true){
133
+ this.hideNestedForm = true;
134
+ }
135
+ this.parentNestedForms[this.props["fields_for"]][id] = this;
136
+ Object.keys(this.parentFormErrors).forEach(function(errorKey){
137
+ if (errorKey.includes(".")){
138
+ let childErrorKey = errorKey.split(".")[1]
139
+ let childModelName = errorKey.split(".")[0].split("[")[0]
140
+ let childModelIndex = errorKey.split(".")[0].split("[")[1].split("]")[0]
141
+ let mappedChildModelIndex = self.parentFormMapToNestedForms(parseInt(childModelIndex), childModelName+"_attributes")
142
+ if(childModelName+"_attributes" == self.props["fields_for"] && mappedChildModelIndex == id){
143
+ self.setNestedFormServerErrorIndex(parseInt(childModelIndex))
144
+ self.setErrorKey(childErrorKey, self.parentFormErrors[errorKey])
145
+ }
146
+ }
147
+ })
148
+ }
149
+ }
150
+ }
151
+ };
152
+
153
+ export default componentDef;
@@ -0,0 +1,57 @@
1
+ module Matestack
2
+ module Ui
3
+ module VueJs
4
+ module Components
5
+ module Form
6
+ class NestedForm < Matestack::Ui::VueJs::Components::Form::Form
7
+ vue_name 'matestack-ui-core-form-nested-form'
8
+
9
+ optional :fields_for, :reject_blank
10
+
11
+ attr_accessor :prototype_template
12
+
13
+ # setup form context to allow child components like inputs to access the form configuration
14
+ def initialize(html_tag = nil, text = nil, options = {}, &block)
15
+ previous_form_context = Matestack::Ui::VueJs::Components::Form::Context.form_context
16
+ if !previous_form_context.nil?
17
+ @is_nested_form = true
18
+ @parent_form_context = previous_form_context
19
+ end
20
+ Matestack::Ui::VueJs::Components::Form::Context.form_context = self
21
+ super(html_tag, text, options, &block)
22
+ Matestack::Ui::VueJs::Components::Form::Context.form_context = previous_form_context
23
+ end
24
+
25
+ def component_id
26
+ "matestack-form-fields-for-#{context.fields_for}-#{SecureRandom.hex}"
27
+ end
28
+
29
+ def response
30
+ div class: "matestack-form-fields-for", "v-show": "vc.hideNestedForm != true", id: options[:id] do
31
+ form_input key: context.for&.class&.primary_key, type: :hidden # required for existing model mapping
32
+ form_input key: :_destroy, type: :hidden, init: true if context.reject_blank == true
33
+ yield
34
+ end
35
+ end
36
+
37
+ def vue_props
38
+ super.merge({
39
+ fields_for: ctx.fields_for,
40
+ primary_key: for_object_primary_key
41
+ })
42
+ end
43
+
44
+ def is_nested_form?
45
+ true
46
+ end
47
+
48
+ def parent_form_context
49
+ @parent_form_context
50
+ end
51
+
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,13 @@
1
+ import formRadioMixin from "./radio_mixin";
2
+ import componentMixin from "../mixin";
3
+ import componentHelpers from "../helpers";
4
+
5
+ const componentDef = {
6
+ mixins: [componentMixin, formRadioMixin],
7
+ template: componentHelpers.inlineTemplate,
8
+ data() {
9
+ return {};
10
+ }
11
+ }
12
+
13
+ export default componentDef;
@@ -0,0 +1,85 @@
1
+ module Matestack
2
+ module Ui
3
+ module VueJs
4
+ module Components
5
+ module Form
6
+ class Radio < Matestack::Ui::VueJs::Components::Form::Base
7
+ vue_name 'matestack-ui-core-form-radio'
8
+
9
+ def response
10
+ div class: 'matestack-ui-core-form-radio' do
11
+ render_options
12
+ render_errors
13
+ end
14
+ end
15
+
16
+ def render_options
17
+ radio_options.to_a.each do |item|
18
+ input radio_attributes(item)
19
+ label item_label(item), ":for": item_id(item)
20
+ end
21
+ end
22
+
23
+ def component_id
24
+ "radio-component-for-#{key}"
25
+ end
26
+
27
+ def vue_props
28
+ {
29
+ init_value: init_value,
30
+ key: key,
31
+ }
32
+ end
33
+
34
+ def radio_attributes(item)
35
+ attributes.merge({
36
+ ":id": item_id(item),
37
+ name: item_name(item),
38
+ type: :radio,
39
+ "matestack-ui-core-ref": scoped_ref("select.#{key}"),
40
+ 'value-type': value_type(item_value(radio_options.first))
41
+ }).tap do |attrs|
42
+ attrs[value_key(item)] = item_value(item)
43
+ end
44
+ end
45
+
46
+ def radio_options
47
+ @radio_options ||= options.delete(:options)
48
+ end
49
+
50
+ # calculated attributes
51
+
52
+ def item_value(item)
53
+ item.is_a?(Array) ? item.last : item
54
+ end
55
+
56
+ def item_label(item)
57
+ item.is_a?(Array) ? item.first : item
58
+ end
59
+
60
+ def item_id(item)
61
+ "#{id || key}+'_#{item_value(item)}'"
62
+ end
63
+
64
+ def item_name(item)
65
+ "#{key}_#{item_value(item)}"
66
+ end
67
+
68
+ def v_model_type
69
+ item_value(radio_options.first).is_a?(Numeric) ? 'v-model.number' : 'v-model'
70
+ end
71
+
72
+ def value_key(value)
73
+ if value.is_a?(Array)
74
+ value[1].is_a?(Numeric) ? ':value' : 'value'
75
+ else
76
+ value.is_a?(Numeric) ? ':value' : 'value'
77
+ end
78
+ end
79
+
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,75 @@
1
+ const formRadioMixin = {
2
+ inject: [
3
+ 'parentFormUid',
4
+ 'parentFormData',
5
+ 'parentFormErrors',
6
+ 'parentFormLoading',
7
+ 'parentFormIsNestedForm',
8
+ 'parentFormResetErrors',
9
+ 'parentNestedFormRuntimeId'
10
+ ],
11
+ methods: {
12
+ initialize: function(){
13
+ const self = this
14
+ let data = {};
15
+
16
+ for (let key in self.getRefs()) {
17
+ let initValue;
18
+ let valueType;
19
+
20
+ if (key.startsWith("select.")) {
21
+ initValue = self.getRefs()[key]["attributes"]["init-value"];
22
+ valueType = self.getRefs()[key]["attributes"]["value-type"];
23
+ }
24
+
25
+ if (key.startsWith("select.")) {
26
+ if (key.startsWith("select.multiple.")) {
27
+ self.parentFormData[key.replace("select.multiple.", "")] = null
28
+ if (initValue) {
29
+ self.setValue(JSON.parse(initValue["value"]));
30
+ self.afterInitialize(JSON.parse(initValue["value"]))
31
+ } else {
32
+ self.setValue([]);
33
+ self.afterInitialize([]);
34
+ }
35
+ } else {
36
+ self.parentFormData[key.replace("select.", "")] = null
37
+ if (initValue) {
38
+ if (valueType && valueType["value"] == "Integer") {
39
+ self.setValue(parseInt(initValue["value"]));
40
+ self.afterInitialize(parseInt(initValue["value"]))
41
+ } else {
42
+ self.setValue(initValue["value"]);
43
+ self.afterInitialize(initValue["value"])
44
+ }
45
+ } else {
46
+ self.setValue(null);
47
+ self.afterInitialize(null)
48
+ }
49
+ }
50
+ }
51
+ }
52
+ },
53
+ inputChanged: function (key) {
54
+ if (this.parentFormIsNestedForm){
55
+ this.parentFormData["_destroy"] = false;
56
+ }
57
+ this.parentFormResetErrors(key);
58
+ },
59
+ afterInitialize: function(value){
60
+ // can be used in the main component for further initialization steps
61
+ },
62
+ setValue: function (value){
63
+ this.parentFormData[this.props["key"]] = value
64
+ }
65
+ },
66
+ mounted: function(){
67
+ this.registerScopedEvent("init", this.initialize, this.parentFormUid)
68
+ },
69
+ beforeUnmount: function(){
70
+ this.removeScopedEvent("init", this.initialize, this.parentFormUid)
71
+ }
72
+
73
+ }
74
+
75
+ export default formRadioMixin
@@ -0,0 +1,13 @@
1
+ import formSelectMixin from "./select_mixin";
2
+ import componentMixin from "../mixin";
3
+ import componentHelpers from "../helpers";
4
+
5
+ const componentDef = {
6
+ mixins: [componentMixin, formSelectMixin],
7
+ template: componentHelpers.inlineTemplate,
8
+ data() {
9
+ return {};
10
+ }
11
+ }
12
+
13
+ export default componentDef;
@@ -0,0 +1,96 @@
1
+ module Matestack
2
+ module Ui
3
+ module VueJs
4
+ module Components
5
+ module Form
6
+ class Select < Matestack::Ui::VueJs::Components::Form::Base
7
+ vue_name 'matestack-ui-core-form-select'
8
+
9
+ def response
10
+ div class: 'matestack-ui-core-form-select' do
11
+ label input_label, ":for": id if input_label
12
+ select select_attributes do
13
+ render_options
14
+ end
15
+ render_errors
16
+ end
17
+ end
18
+
19
+ def render_options
20
+ if placeholder
21
+ option value: nil, disabled: true, selected: init_value.nil?, text: placeholder
22
+ end
23
+ select_options.to_a.each do |item|
24
+ option_config = {}.tap do |attrs|
25
+ attrs[value_key(item)] = item_value(item)
26
+ attrs[:disabled] = item_disabled?(item)
27
+ end
28
+ option item_label(item), option_config
29
+ end
30
+ end
31
+
32
+ def component_id
33
+ "select-component-for-#{key}"
34
+ end
35
+
36
+ def vue_props
37
+ {
38
+ init_value: init_value,
39
+ key: key,
40
+ }
41
+ end
42
+
43
+ def select_attributes
44
+ attributes.except(:options).merge({
45
+ multiple: multiple,
46
+ ":id": id,
47
+ "matestack-ui-core-ref": scoped_ref("select#{'.multiple' if multiple}.#{key}"),
48
+ 'value-type': value_type(select_options.first),
49
+ 'init-value': init_value,
50
+ })
51
+ end
52
+
53
+ # select options
54
+
55
+ def select_options
56
+ @select_options ||= options.delete(:options)
57
+ end
58
+
59
+ # calculated attributes
60
+
61
+ def item_value(item)
62
+ item.is_a?(Array) ? item.last : item
63
+ end
64
+
65
+ def item_label(item)
66
+ item.is_a?(Array) ? item.first : item
67
+ end
68
+
69
+ def item_id(item)
70
+ "#{key}_#{item_value(item)}"
71
+ end
72
+
73
+ def item_disabled?(item)
74
+ disabled_options && disabled_options.to_a.include?(item)
75
+ end
76
+
77
+ def v_model_type
78
+ item_value(select_options.first).is_a?(Numeric) ? 'v-model.number' : 'v-model'
79
+ end
80
+
81
+ def value_key(value)
82
+ value.is_a?(Numeric) ? ':value' : 'value'
83
+ end
84
+
85
+ # attributes
86
+
87
+ def disabled_options
88
+ @disabled_options ||= options.delete(:disabled_options)
89
+ end
90
+
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end