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,109 @@
1
+ module Matestack
2
+ module Ui
3
+ module VueJs
4
+ module Components
5
+ module Form
6
+ class Checkbox < Matestack::Ui::VueJs::Components::Form::Base
7
+ vue_name 'matestack-ui-core-form-checkbox'
8
+
9
+ def response
10
+ div class: 'matestack-ui-core-form-checkbox' do
11
+ render_options
12
+ render_errors
13
+ end
14
+ end
15
+
16
+ def render_options
17
+ if checkbox_options
18
+ render_checkbox_options
19
+ else
20
+ render_true_false_checkbox
21
+ end
22
+ end
23
+
24
+ def component_id
25
+ "checkbox-component-for-#{key}"
26
+ end
27
+
28
+ def vue_props
29
+ {
30
+ init_value: init_value,
31
+ key: key,
32
+ }
33
+ end
34
+
35
+ # checkbox rendering
36
+
37
+ def render_checkbox_options
38
+ checkbox_options.to_a.each do |item|
39
+ input checkbox_attributes(item)
40
+ label item_label(item), ":for": item_id(item)
41
+ end
42
+ end
43
+
44
+ def checkbox_attributes(item)
45
+ {
46
+ ":id": item_id(item),
47
+ type: :checkbox,
48
+ name: item_label(item),
49
+ "#{value_key(item)}": item_value(item),
50
+ "matestack-ui-core-ref": scoped_ref("select.multiple.#{key}"),
51
+ 'v-on:change': change_event,
52
+ 'init-value': (init_value || []).to_json,
53
+ 'v-bind:class': "{ '#{error_class}': #{error_key} }",
54
+ 'value-type': value_type(item),
55
+ "#{v_model_type(item)}": input_key,
56
+ }.merge(self.options)
57
+ end
58
+
59
+ def render_true_false_checkbox
60
+ input true_false_checkbox_attributes.merge(type: :hidden, ":id": nil)
61
+ input true_false_checkbox_attributes.merge(type: :checkbox, ":id": item_id(1))
62
+ label input_label, ":for": item_id(1) if input_label
63
+ end
64
+
65
+ def true_false_checkbox_attributes
66
+ attributes.merge({
67
+ 'init-value': init_value_for_single_input,
68
+ })
69
+ end
70
+
71
+ def init_value_for_single_input
72
+ if init_value == true || init_value == 1
73
+ return "true"
74
+ end
75
+ if init_value == false || init_value == 0
76
+ return "false"
77
+ end
78
+ end
79
+
80
+ # checkbox options
81
+
82
+ def checkbox_options
83
+ @checkbox_options ||= options.delete(:options)
84
+ end
85
+
86
+ # calculated attributes
87
+
88
+ def item_value(item)
89
+ item.is_a?(Array) ? item.last : item
90
+ end
91
+
92
+ def item_label(item)
93
+ item.is_a?(Array) ? item.first : item
94
+ end
95
+
96
+ def item_id(item)
97
+ "#{id}+'_#{item_value(item).to_s.gsub(" ", '_')}'"
98
+ end
99
+
100
+ def value_key(value)
101
+ value.is_a?(Numeric) ? ':value' : 'value'
102
+ end
103
+
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,90 @@
1
+ const formCheckboxMixin = {
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.") || key.startsWith("input.")) {
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
+ } else {
51
+ self.parentFormData[key.replace("input.", "")] = null
52
+ if (initValue) {
53
+ if(initValue["value"] === "true"){
54
+ self.setValue(true);
55
+ self.afterInitialize(true)
56
+ }
57
+ if(initValue["value"] === "false"){
58
+ self.setValue(false);
59
+ self.afterInitialize(false)
60
+ }
61
+ } else {
62
+ self.setValue(null);
63
+ self.afterInitialize(null)
64
+ }
65
+ }
66
+ }
67
+ },
68
+ inputChanged: function (key) {
69
+ if (this.parentFormIsNestedForm){
70
+ this.parentFormData["_destroy"] = false;
71
+ }
72
+ this.parentFormResetErrors(key);
73
+ },
74
+ afterInitialize: function(value){
75
+ // can be used in the main component for further initialization steps
76
+ },
77
+ setValue: function (value){
78
+ this.parentFormData[this.props["key"]] = value
79
+ }
80
+ },
81
+ mounted: function(){
82
+ this.registerScopedEvent("init", this.initialize, this.parentFormUid)
83
+ },
84
+ beforeUnmount: function(){
85
+ this.removeScopedEvent("init", this.initialize, this.parentFormUid)
86
+ }
87
+
88
+ }
89
+
90
+ export default formCheckboxMixin
@@ -0,0 +1,15 @@
1
+ module Matestack
2
+ module Ui
3
+ module VueJs
4
+ module Components
5
+ module Form
6
+ class Context < ActiveSupport::CurrentAttributes
7
+
8
+ attribute :form_context
9
+
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,50 @@
1
+ import componentMixin from "../mixin";
2
+ import componentHelpers from "../helpers";
3
+
4
+ const componentDef = {
5
+ mixins: [componentMixin],
6
+ template: componentHelpers.inlineTemplate,
7
+ data: function () {
8
+ return {};
9
+ },
10
+ inject: [
11
+ 'parentNestedFormRuntimeTemplates',
12
+ 'parentNestedFormRuntimeTemplateDomElements',
13
+ 'parentNestedForms'
14
+ ],
15
+ methods: {
16
+ addItem: function(key){
17
+ var templateString = JSON.parse(this.getElement().querySelector('#prototype-template-for-'+key).dataset[":template"])
18
+ var tmp_dom_elem = document.createElement('div')
19
+ tmp_dom_elem.innerHTML = templateString
20
+ var static_prototype_template_uid = tmp_dom_elem.querySelector('matestack-component-template').id.replace("uid-", "")
21
+ var dynamic_prototype_template_uid = Math.floor(Math.random() * 1000000000);
22
+ var templateString = templateString.replaceAll(static_prototype_template_uid, dynamic_prototype_template_uid);
23
+ if (this.parentNestedFormRuntimeTemplateDomElements[key] == null){
24
+ var dom_elem = document.createElement('div')
25
+ dom_elem.innerHTML = templateString
26
+ var existingItemsCount;
27
+ if (this.parentNestedForms[key] == undefined){
28
+ existingItemsCount = 0
29
+ }else{
30
+ existingItemsCount = this.parentNestedForms[key].length
31
+ }
32
+ dom_elem.querySelector('.matestack-form-fields-for').id = key+"_child_"+existingItemsCount
33
+ this.parentNestedFormRuntimeTemplateDomElements[key] = dom_elem
34
+ this.parentNestedFormRuntimeTemplates[key] = this.parentNestedFormRuntimeTemplateDomElements[key].outerHTML
35
+ }else{
36
+ var dom_elem = document.createElement('div')
37
+ dom_elem.innerHTML = templateString
38
+ var existingItemsCount = this.parentNestedForms[key].length
39
+ dom_elem.querySelector('.matestack-form-fields-for').id = key+"_child_"+existingItemsCount
40
+ this.parentNestedFormRuntimeTemplateDomElements[key].insertAdjacentHTML(
41
+ 'beforeend',
42
+ dom_elem.innerHTML
43
+ )
44
+ this.parentNestedFormRuntimeTemplates[key] = this.parentNestedFormRuntimeTemplateDomElements[key].outerHTML
45
+ }
46
+ }
47
+ }
48
+ };
49
+
50
+ export default componentDef;
@@ -0,0 +1,35 @@
1
+ module Matestack
2
+ module Ui
3
+ module VueJs
4
+ module Components
5
+ module Form
6
+ class FieldsForAddItem < Matestack::Ui::VueJs::Vue
7
+ vue_name 'matestack-ui-core-form-fields-for-add-item'
8
+
9
+ required :key
10
+ required :prototype
11
+
12
+ attr_accessor :prototype_template_json
13
+
14
+ def create_children(&block)
15
+ # first render prototype_template_json
16
+ self.prototype_template_json = context.prototype.call().to_json
17
+ # delete from children in order not to render the prototype
18
+ self.children.shift
19
+ super
20
+ end
21
+
22
+ def response
23
+ div id: "prototype-template-for-#{context.key}", "v-pre": true, data: { ":template": self.prototype_template_json }
24
+ Matestack::Ui::Core::Base.new('matestack-ui-core-runtime-render', ':template': "vc.parentNestedFormRuntimeTemplates['#{context.key}']", ':vc': 'vc')
25
+ a class: 'matestack-ui-core-form-fields-for-add-item', "@click.prevent": "vc.addItem('#{context.key}')" do
26
+ yield if block_given?
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,19 @@
1
+ module Matestack
2
+ module Ui
3
+ module VueJs
4
+ module Components
5
+ module Form
6
+ class FieldsForRemoveItem < Matestack::Ui::Component
7
+
8
+ def response
9
+ a class: 'matestack-ui-core-form-fields-for-remove-item', "@click.prevent": "vc.removeItem()" do
10
+ yield if block_given?
11
+ end
12
+ end
13
+
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,276 @@
1
+ import { inject, 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
+ import transitionHandlingMixin from '../transition_handling_mixin'
9
+
10
+ const componentDef = {
11
+ mixins: [componentMixin, transitionHandlingMixin],
12
+ template: componentHelpers.inlineTemplate,
13
+ data: function () {
14
+ return {
15
+ data: {},
16
+ errors: {},
17
+ loading: false,
18
+ isNestedForm: false,
19
+ nestedForms: {},
20
+ nestedFormRuntimeTemplates: {},
21
+ nestedFormRuntimeTemplateDomElements: {},
22
+ deletedNestedForms: {}
23
+ };
24
+ },
25
+ setup() {
26
+ // conditionally inject appNavigateTo
27
+ // form component has to work in context without wrapping app as well!
28
+ const appNavigateTo = inject('appNavigateTo', undefined)
29
+ return {
30
+ appNavigateTo
31
+ }
32
+ },
33
+ provide: function() {
34
+ return {
35
+ parentFormUid: computed(() => this.props["component_uid"]),
36
+ parentFormData: computed(() => this.data),
37
+ parentFormErrors: computed(() => this.errors),
38
+ parentFormLoading: computed(() => this.loading),
39
+ parentNestedForms: computed(() => this.nestedForms),
40
+ parentDeletedNestedForms: computed(() => this.deletedNestedForms),
41
+ parentNestedFormRuntimeTemplates: computed(() => this.nestedFormRuntimeTemplates),
42
+ parentNestedFormRuntimeTemplateDomElements: computed(() => this.nestedFormRuntimeTemplateDomElements),
43
+ parentFormMapToNestedForms: this.mapToNestedForms,
44
+ parentFormSetErrors: this.setErrors,
45
+ parentFormResetErrors: this.resetErrors,
46
+ parentFormIsNestedForm: this.isNestedForm, // need to provide this value for input components working both in form and nested form contexts
47
+ parentNestedFormRuntimeId: null, // need to provide this value for input components working both in form and nested form contexts
48
+ }
49
+ },
50
+ methods: {
51
+ initDataKey: function (key, initValue) {
52
+ this.data[key] = initValue;
53
+ },
54
+ updateFormValue: function (key, value) {
55
+ this.data[key] = value;
56
+ },
57
+ hasErrors: function(){
58
+ //https://stackoverflow.com/a/27709663/13886137
59
+ for (var key in this.errors) {
60
+ if (this.errors[key] !== null && this.errors[key] != ""){
61
+ return true;
62
+ }
63
+ }
64
+ return false;
65
+ },
66
+ resetErrors: function (key) {
67
+ if (this.errors[key]) {
68
+ delete this.errors[key];
69
+ }
70
+ },
71
+ setErrors: function(errors){
72
+ this.errors = errors;
73
+ },
74
+ setErrorKey: function(key, value){
75
+ this.errors[key] = value;
76
+ },
77
+ flushErrors: function(key, value){
78
+ this.errors = {};
79
+ },
80
+ setNestedFormsError: function(errors){
81
+ let self = this;
82
+ Object.keys(errors).forEach(function(errorKey){
83
+ if (errorKey.includes(".")){
84
+ let childErrorKey = errorKey.split(".")[1]
85
+ let childModelName = errorKey.split(".")[0].split("[")[0]
86
+ let childModelIndex = errorKey.split(".")[0].split("[")[1].split("]")[0]
87
+ let mappedChildModelIndex = self.mapToNestedForms(parseInt(childModelIndex), childModelName+"_attributes")
88
+ self.nestedForms[childModelName+"_attributes"][mappedChildModelIndex].setNestedFormServerErrorIndex(parseInt(childModelIndex))
89
+ self.nestedForms[childModelName+"_attributes"][mappedChildModelIndex].setErrorKey(childErrorKey, errors[errorKey])
90
+ }
91
+ })
92
+ },
93
+ mapToNestedForms: function(serverIndex, nestedFormKey){
94
+ var primaryKey;
95
+ if(this.props["primary_key"] != undefined){
96
+ primaryKey = this.props["primary_key"];
97
+ }else{
98
+ primaryKey = "id";
99
+ }
100
+
101
+ var formIdMap = []
102
+ var childModelKey = 0;
103
+ while(this.data[nestedFormKey].length > childModelKey){
104
+ var ignore = this.data[nestedFormKey][childModelKey]["_destroy"] == true && this.data[nestedFormKey][childModelKey][primaryKey] == null
105
+ if(!ignore){
106
+ formIdMap.push(childModelKey)
107
+ }
108
+ childModelKey++;
109
+ }
110
+
111
+ return formIdMap[serverIndex];
112
+ },
113
+ resetNestedForms: function(){
114
+ var self = this;
115
+ Object.keys(self.nestedForms).forEach(function(childModelKey){
116
+ self.nestedForms[childModelKey].forEach(function(nestedFormInstance){
117
+ if(nestedFormInstance.data["_destroy"] == true){
118
+ var destroyed = true;
119
+ }
120
+ nestedFormInstance.initValues()
121
+ if(destroyed){
122
+ nestedFormInstance.hideNestedForm = true
123
+ nestedFormInstance.data["_destroy"] = true
124
+ }
125
+ })
126
+ })
127
+ },
128
+ initValues: function () {
129
+ this.emitScopedEvent("init") // received by child input components
130
+ },
131
+ shouldResetFormOnSuccessfulSubmit() {
132
+ const self = this;
133
+ if (self.props["success"] != undefined && self.props["success"]["reset"] != undefined) {
134
+ return self.props["success"]["reset"];
135
+ } else {
136
+ return self.shouldResetFormOnSuccessfulSubmitByDefault();
137
+ }
138
+ },
139
+ shouldResetFormOnSuccessfulSubmitByDefault() {
140
+ const self = this;
141
+ if (self.props["method"] == "put") {
142
+ return false;
143
+ } else {
144
+ return true;
145
+ }
146
+ },
147
+ perform: function(){
148
+ const self = this
149
+ if (self.props["fields_for"] != null) {
150
+ return;
151
+ }
152
+
153
+ var form = this.getRefs()["form"]
154
+
155
+ if(form.checkValidity()){
156
+ self.loading = true;
157
+ if (self.props["emit"] != undefined) {
158
+ matestackEventHub.$emit(self.props["emit"]);
159
+ }
160
+ if (self.props["delay"] != undefined) {
161
+ setTimeout(function () {
162
+ self.sendRequest()
163
+ }, parseInt(self.props["delay"]));
164
+ } else {
165
+ self.sendRequest()
166
+ }
167
+ } else {
168
+ matestackEventHub.$emit('static_form_errors');
169
+ }
170
+ },
171
+ transformToFormData: function (formData, dataNode, parentKey=null) {
172
+ var self = this;
173
+ for (let key in dataNode) {
174
+ if (key.endsWith("[]")) {
175
+ for (let i in dataNode[key]) {
176
+ let file = dataNode[key][i];
177
+ if (parentKey != null) {
178
+ formData.append(self.props["for"] + parentKey + "[" + key.slice(0, -2) + "][]", file);
179
+ } else {
180
+ formData.append(self.props["for"] + "[" + key.slice(0, -2) + "][]", file);
181
+ }
182
+ }
183
+ } else {
184
+ if (Array.isArray(dataNode[key])){
185
+ dataNode[key].forEach(function(item, index){
186
+ if (parentKey != null) {
187
+ let _key = parentKey + "[" + key + "]" + "[]";
188
+ formData = self.transformToFormData(formData, item, _key)
189
+ } else {
190
+ let _key = "[" + key + "]" + "[]";
191
+ formData = self.transformToFormData(formData, item, _key)
192
+ }
193
+ })
194
+ } else {
195
+ if (dataNode[key] != null){
196
+ if (parentKey != null) {
197
+ formData.append(self.props["for"] + parentKey + "[" + key + "]", dataNode[key]);
198
+ } else {
199
+ formData.append(self.props["for"] + "[" + key + "]", dataNode[key]);
200
+ }
201
+ }
202
+ }
203
+ }
204
+ }
205
+
206
+ return formData;
207
+ },
208
+ sendRequest: function(){
209
+ const self = this;
210
+ let payload = {};
211
+ payload[self.props["for"]] = self.data;
212
+ let axios_config = {};
213
+ if (self.props["multipart"] == true ) {
214
+ let formData = new FormData();
215
+ formData = this.transformToFormData(formData, this.data)
216
+ axios_config = {
217
+ method: self.props["method"],
218
+ url: self.props["submit_path"],
219
+ data: formData,
220
+ headers: {
221
+ "X-CSRF-Token": self.getXcsrfToken(),
222
+ "Content-Type": "multipart/form-data",
223
+ },
224
+ };
225
+ } else {
226
+ axios_config = {
227
+ method: self.props["method"],
228
+ url: self.props["submit_path"],
229
+ data: payload,
230
+ headers: {
231
+ "X-CSRF-Token": self.getXcsrfToken(),
232
+ "Content-Type": "application/json",
233
+ },
234
+ };
235
+ }
236
+ axios(axios_config)
237
+ .then(function (response) {
238
+ self.loading = false;
239
+
240
+ if (self.props["success"] != undefined && self.props["success"]["emit"] != undefined) {
241
+ matestackEventHub.$emit(self.props["success"]["emit"], response.data);
242
+ }
243
+
244
+ self.successTransitionHandling(response)
245
+ self.flushErrors();
246
+
247
+ if (self.shouldResetFormOnSuccessfulSubmit())
248
+ {
249
+ self.initValues();
250
+ self.resetNestedForms();
251
+ }
252
+ })
253
+ .catch(function (error) {
254
+ self.loading = false;
255
+
256
+ if (error.response && error.response.data && error.response.data.errors) {
257
+ self.errors = error.response.data.errors;
258
+ self.setErrors(error.response.data.errors);
259
+ self.setNestedFormsError(error.response.data.errors);
260
+ }
261
+
262
+ if (self.props["failure"] != undefined && self.props["failure"]["emit"] != undefined) {
263
+ matestackEventHub.$emit(self.props["failure"]["emit"], error.response.data);
264
+ }
265
+
266
+ self.failureTransitionHandling(error)
267
+ });
268
+ },
269
+ },
270
+ mounted: function () {
271
+ this.initValues();
272
+ }
273
+
274
+ };
275
+
276
+ export default componentDef;
@@ -0,0 +1,77 @@
1
+ module Matestack
2
+ module Ui
3
+ module VueJs
4
+ module Components
5
+ module Form
6
+ class Form < Matestack::Ui::VueJs::Vue
7
+ vue_name 'matestack-ui-core-form'
8
+
9
+ optional :for, :path, :success, :failure, :multipart, :emit, :delay, :errors
10
+
11
+ # setup form context to allow child components like inputs to access the form configuration
12
+ def initialize(html_tag = nil, text = nil, options = {}, &block)
13
+ previous_form_context = Matestack::Ui::VueJs::Components::Form::Context.form_context
14
+ Matestack::Ui::VueJs::Components::Form::Context.form_context = self
15
+ super(html_tag, text, options, &block)
16
+ Matestack::Ui::VueJs::Components::Form::Context.form_context = previous_form_context
17
+ end
18
+
19
+ def response
20
+ form attributes do
21
+ yield
22
+ end
23
+ end
24
+
25
+ def attributes
26
+ {
27
+ class: 'matestack-form',
28
+ "matestack-ui-core-ref": scoped_ref('form'),
29
+ 'v-bind:class': "{ 'has-errors': vc.hasErrors(), loading: vc.loading }",
30
+ 'v-on:submit.prevent': 'vc.perform',
31
+ }
32
+ end
33
+
34
+ def vue_props
35
+ {
36
+ for: for_attribute,
37
+ submit_path: ctx.path,
38
+ method: form_method,
39
+ success: ctx.success,
40
+ failure: ctx.failure,
41
+ multipart: !!ctx.multipart,
42
+ emit: ctx.emit,
43
+ delay: ctx.delay
44
+ }
45
+ end
46
+
47
+ def for_attribute
48
+ return for_option.model_name.singular if for_option.respond_to?(:model_name)
49
+ for_option
50
+ end
51
+
52
+ def for_option
53
+ @for_option ||= ctx.for
54
+ end
55
+
56
+ def multipart_option
57
+ @multipart_option ||= ctx.multipart
58
+ end
59
+
60
+ def for_object_primary_key
61
+ context.for&.class&.primary_key rescue nil
62
+ end
63
+
64
+ def form_method
65
+ @form_method ||= options.delete(:method)
66
+ end
67
+
68
+ def is_nested_form?
69
+ false
70
+ end
71
+
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,13 @@
1
+ import formInputMixin from "./input_mixin";
2
+ import componentMixin from "../mixin";
3
+ import componentHelpers from "../helpers";
4
+
5
+ const componentDef = {
6
+ mixins: [componentMixin, formInputMixin],
7
+ template: componentHelpers.inlineTemplate,
8
+ data() {
9
+ return {};
10
+ }
11
+ }
12
+
13
+ export default componentDef;