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.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +492 -0
- data/Rakefile +64 -0
- data/lib/matestack/ui/component.rb +1 -0
- data/lib/matestack/ui/isolated_component.rb +1 -0
- data/lib/matestack/ui/vue_js/components/action.js +70 -0
- data/lib/matestack/ui/vue_js/components/action.rb +46 -0
- data/lib/matestack/ui/vue_js/components/app.js +122 -0
- data/lib/matestack/ui/vue_js/components/app.rb +46 -0
- data/lib/matestack/ui/vue_js/components/async.js +104 -0
- data/lib/matestack/ui/vue_js/components/async.rb +84 -0
- data/lib/matestack/ui/vue_js/components/cable.js +96 -0
- data/lib/matestack/ui/vue_js/components/cable.rb +69 -0
- data/lib/matestack/ui/vue_js/components/collection/content.js +96 -0
- data/lib/matestack/ui/vue_js/components/collection/content.rb +32 -0
- data/lib/matestack/ui/vue_js/components/collection/filter.js +45 -0
- data/lib/matestack/ui/vue_js/components/collection/filter.rb +29 -0
- data/lib/matestack/ui/vue_js/components/collection/filter_reset.rb +19 -0
- data/lib/matestack/ui/vue_js/components/collection/helper.rb +128 -0
- data/lib/matestack/ui/vue_js/components/collection/next.rb +19 -0
- data/lib/matestack/ui/vue_js/components/collection/order.js +45 -0
- data/lib/matestack/ui/vue_js/components/collection/order.rb +28 -0
- data/lib/matestack/ui/vue_js/components/collection/order_toggle.rb +21 -0
- data/lib/matestack/ui/vue_js/components/collection/order_toggle_indicator.rb +30 -0
- data/lib/matestack/ui/vue_js/components/collection/page.rb +21 -0
- data/lib/matestack/ui/vue_js/components/collection/previous.rb +19 -0
- data/lib/matestack/ui/vue_js/components/form/base.rb +179 -0
- data/lib/matestack/ui/vue_js/components/form/checkbox.js +13 -0
- data/lib/matestack/ui/vue_js/components/form/checkbox.rb +109 -0
- data/lib/matestack/ui/vue_js/components/form/checkbox_mixin.js +90 -0
- data/lib/matestack/ui/vue_js/components/form/context.rb +15 -0
- data/lib/matestack/ui/vue_js/components/form/fields_for_add_item.js +50 -0
- data/lib/matestack/ui/vue_js/components/form/fields_for_add_item.rb +35 -0
- data/lib/matestack/ui/vue_js/components/form/fields_for_remove_item.rb +19 -0
- data/lib/matestack/ui/vue_js/components/form/form.js +276 -0
- data/lib/matestack/ui/vue_js/components/form/form.rb +77 -0
- data/lib/matestack/ui/vue_js/components/form/input.js +13 -0
- data/lib/matestack/ui/vue_js/components/form/input.rb +54 -0
- data/lib/matestack/ui/vue_js/components/form/input_mixin.js +79 -0
- data/lib/matestack/ui/vue_js/components/form/nested_form.js +153 -0
- data/lib/matestack/ui/vue_js/components/form/nested_form.rb +57 -0
- data/lib/matestack/ui/vue_js/components/form/radio.js +13 -0
- data/lib/matestack/ui/vue_js/components/form/radio.rb +85 -0
- data/lib/matestack/ui/vue_js/components/form/radio_mixin.js +75 -0
- data/lib/matestack/ui/vue_js/components/form/select.js +13 -0
- data/lib/matestack/ui/vue_js/components/form/select.rb +96 -0
- data/lib/matestack/ui/vue_js/components/form/select_mixin.js +76 -0
- data/lib/matestack/ui/vue_js/components/form/textarea.js +13 -0
- data/lib/matestack/ui/vue_js/components/form/textarea.rb +37 -0
- data/lib/matestack/ui/vue_js/components/form/textarea_mixin.js +54 -0
- data/lib/matestack/ui/vue_js/components/helpers.js +5 -0
- data/lib/matestack/ui/vue_js/components/isolated.js +105 -0
- data/lib/matestack/ui/vue_js/components/isolated.rb +86 -0
- data/lib/matestack/ui/vue_js/components/mixin.js +66 -0
- data/lib/matestack/ui/vue_js/components/onclick.js +18 -0
- data/lib/matestack/ui/vue_js/components/onclick.rb +37 -0
- data/lib/matestack/ui/vue_js/components/page_switch.js +24 -0
- data/lib/matestack/ui/vue_js/components/page_switch.rb +35 -0
- data/lib/matestack/ui/vue_js/components/runtime_render.js +17 -0
- data/lib/matestack/ui/vue_js/components/toggle.js +70 -0
- data/lib/matestack/ui/vue_js/components/toggle.rb +38 -0
- data/lib/matestack/ui/vue_js/components/transition.js +44 -0
- data/lib/matestack/ui/vue_js/components/transition.rb +40 -0
- data/lib/matestack/ui/vue_js/components/transition_handling_mixin.js +100 -0
- data/lib/matestack/ui/vue_js/components.rb +118 -0
- data/lib/matestack/ui/vue_js/event_hub.js +12 -0
- data/lib/matestack/ui/vue_js/helpers/query_params_helper.js +56 -0
- data/lib/matestack/ui/vue_js/index.js +94 -0
- data/lib/matestack/ui/vue_js/initialize.rb +10 -0
- data/lib/matestack/ui/vue_js/utils.rb +67 -0
- data/lib/matestack/ui/vue_js/version.rb +7 -0
- data/lib/matestack/ui/vue_js/vue.rb +75 -0
- data/lib/matestack/ui/vue_js/vue_attributes.rb +13 -0
- data/lib/matestack/ui/vue_js.rb +52 -0
- data/lib/matestack/ui/vue_js_component.rb +1 -0
- 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,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;
|