pui9-components 1.16.4
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.
- package/README.md +43 -0
- package/dist/demo.html +10 -0
- package/dist/pui9-components.common.js +81953 -0
- package/dist/pui9-components.common.js.map +1 -0
- package/dist/pui9-components.css +5 -0
- package/dist/pui9-components.umd.js +81963 -0
- package/dist/pui9-components.umd.js.map +1 -0
- package/dist/pui9-components.umd.min.js +308 -0
- package/dist/pui9-components.umd.min.js.map +1 -0
- package/package-lock.json +15945 -0
- package/package.json +78 -0
- package/src/App.vue +117 -0
- package/src/components/PuiCheckbox.vue +105 -0
- package/src/components/PuiCodeEditor.vue +123 -0
- package/src/components/PuiDateField.vue +1004 -0
- package/src/components/PuiField.vue +30 -0
- package/src/components/PuiFieldSet.vue +27 -0
- package/src/components/PuiFormFooter.vue +64 -0
- package/src/components/PuiFormFooterBtns.vue +118 -0
- package/src/components/PuiFormHeader.vue +25 -0
- package/src/components/PuiFormLoading.vue +12 -0
- package/src/components/PuiFormMiniAudit.vue +53 -0
- package/src/components/PuiMasterDetail.vue +96 -0
- package/src/components/PuiModalDialog.vue +87 -0
- package/src/components/PuiModalDialogForm.vue +205 -0
- package/src/components/PuiMultiSelect.vue +499 -0
- package/src/components/PuiNumberField.vue +503 -0
- package/src/components/PuiPasswordField.vue +105 -0
- package/src/components/PuiRadioGroup.vue +105 -0
- package/src/components/PuiRichTextEditor.vue +117 -0
- package/src/components/PuiSelect.vue +1638 -0
- package/src/components/PuiSelectDetailDialog.vue +106 -0
- package/src/components/PuiSelectTextService.vue +61 -0
- package/src/components/PuiSpinnerField.vue +484 -0
- package/src/components/PuiSwitch.vue +104 -0
- package/src/components/PuiTextArea.vue +203 -0
- package/src/components/PuiTextField.vue +272 -0
- package/src/dateTimeUtils.js +78 -0
- package/src/index.js +73 -0
- package/src/main.js +33 -0
- package/src/mixins/PuiFormComponentMixin.js +81 -0
- package/src/mixins/PuiMultiSelectMixin.js +106 -0
- package/src/mixins/PuiUtilsNumberMixin.js +19 -0
- package/src/plugins/vuetify.js +32 -0
- package/src/tests/TestAutocomplete.vue +138 -0
- package/src/tests/TestCodeEditor.vue +48 -0
- package/src/tests/TestField.vue +22 -0
- package/src/tests/TestFieldSet.vue +30 -0
- package/src/tests/TestInputCheckbox.vue +53 -0
- package/src/tests/TestInputDate.vue +146 -0
- package/src/tests/TestInputNumber.vue +77 -0
- package/src/tests/TestInputRadioGroup.vue +86 -0
- package/src/tests/TestInputSpinner.vue +77 -0
- package/src/tests/TestInputSwitch.vue +52 -0
- package/src/tests/TestInputText.vue +120 -0
- package/src/tests/TestInputTextArea.vue +73 -0
- package/src/tests/TestMultiSelect.vue +127 -0
- package/src/tests/TestPuiForm.vue +68 -0
- package/src/tests/TestRichTextEditor.vue +54 -0
- package/src/utils.js +148 -0
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pui9-components",
|
|
3
|
+
"description": "PUI9 Basic Form Components",
|
|
4
|
+
"author": {
|
|
5
|
+
"name": "Prodevelop S.L."
|
|
6
|
+
},
|
|
7
|
+
"version": "1.16.4",
|
|
8
|
+
"license": "Copyright",
|
|
9
|
+
"main": "dist/pui9-components.common.js",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"serve": "vue-cli-service serve",
|
|
12
|
+
"build-bundle": "vue-cli-service build --target lib --name pui9-components ./src/index.js",
|
|
13
|
+
"prepare": "npm run build-bundle",
|
|
14
|
+
"lint": "vue-cli-service lint"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@tinymce/tinymce-vue": "3.2.0",
|
|
18
|
+
"current-device": "0.10.2",
|
|
19
|
+
"moment": "2.29.1",
|
|
20
|
+
"moment-timezone": "0.5.33",
|
|
21
|
+
"vue-codemirror": "4.0.6",
|
|
22
|
+
"vue-infinite-loading": "2.4.5",
|
|
23
|
+
"sanitize-html": "2.7.3",
|
|
24
|
+
"vuedraggable": "2.24.3"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@fortawesome/fontawesome-pro": "5.15.4",
|
|
28
|
+
"@vue/cli-plugin-babel": "4.5.13",
|
|
29
|
+
"@vue/cli-plugin-eslint": "4.5.13",
|
|
30
|
+
"@vue/cli-service": "4.5.13",
|
|
31
|
+
"autoprefixer": "9.8.6",
|
|
32
|
+
"babel-eslint": "10.1.0",
|
|
33
|
+
"css-loader": "0.28.11",
|
|
34
|
+
"core-js": "3.17.2",
|
|
35
|
+
"deepmerge": "4.2.2",
|
|
36
|
+
"eslint": "6.8.0",
|
|
37
|
+
"eslint-plugin-vue": "6.2.2",
|
|
38
|
+
"postcss-css-variables": "0.18.0",
|
|
39
|
+
"postcss-import": "12.0.1",
|
|
40
|
+
"postcss-loader": "4.1.0",
|
|
41
|
+
"postcss-nested": "4.2.3",
|
|
42
|
+
"postcss-url": "8.0.0",
|
|
43
|
+
"sass": "1.27.0",
|
|
44
|
+
"sass-loader": "10.0.2",
|
|
45
|
+
"stylus": "0.54.8",
|
|
46
|
+
"stylus-loader": "3.0.2",
|
|
47
|
+
"vue": "2.6.14",
|
|
48
|
+
"vue-i18n": "8.25.0",
|
|
49
|
+
"vue-cli-plugin-vuetify": "2.4.1",
|
|
50
|
+
"vue-template-compiler": "2.6.14",
|
|
51
|
+
"vuetify-loader": "1.7.3",
|
|
52
|
+
"vuetify": "2.3.23",
|
|
53
|
+
"vuex": "3.6.2"
|
|
54
|
+
},
|
|
55
|
+
"eslintConfig": {
|
|
56
|
+
"root": true,
|
|
57
|
+
"env": {
|
|
58
|
+
"node": true
|
|
59
|
+
},
|
|
60
|
+
"extends": [
|
|
61
|
+
"plugin:vue/essential",
|
|
62
|
+
"eslint:recommended"
|
|
63
|
+
],
|
|
64
|
+
"parserOptions": {
|
|
65
|
+
"parser": "babel-eslint"
|
|
66
|
+
},
|
|
67
|
+
"rules": {}
|
|
68
|
+
},
|
|
69
|
+
"browserslist": [
|
|
70
|
+
"> 1%",
|
|
71
|
+
"last 2 versions"
|
|
72
|
+
],
|
|
73
|
+
"files": [
|
|
74
|
+
"dist/*",
|
|
75
|
+
"src/*",
|
|
76
|
+
"*.json"
|
|
77
|
+
]
|
|
78
|
+
}
|
package/src/App.vue
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-app>
|
|
3
|
+
<v-app-bar app color="primary" dark>
|
|
4
|
+
<div class="d-flex align-center">
|
|
5
|
+
<h2>PUI9 Basic Components Library</h2>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
<v-spacer></v-spacer>
|
|
9
|
+
|
|
10
|
+
<v-btn href="https://confluence.prodevelop.es/pages/viewpage.action?pageId=163217879" target="_blank" text>
|
|
11
|
+
<span class="mr-2">Documentation</span>
|
|
12
|
+
<v-icon>mdi-open-in-new</v-icon>
|
|
13
|
+
</v-btn>
|
|
14
|
+
</v-app-bar>
|
|
15
|
+
|
|
16
|
+
<v-content style="height: 100vh; overflow-y: auto;">
|
|
17
|
+
<v-container>
|
|
18
|
+
<v-tabs show-arrows>
|
|
19
|
+
<v-tab ripple>PuiFieldSet</v-tab>
|
|
20
|
+
<v-tab ripple>PuiField</v-tab>
|
|
21
|
+
<v-tab ripple>PuiTextArea</v-tab>
|
|
22
|
+
<v-tab ripple>PuiTextField</v-tab>
|
|
23
|
+
<v-tab ripple>PuiNumberField</v-tab>
|
|
24
|
+
<v-tab ripple>PuiSpinnerField</v-tab>
|
|
25
|
+
<v-tab ripple>PuiDateField</v-tab>
|
|
26
|
+
<v-tab ripple>PuiRadioGroup</v-tab>
|
|
27
|
+
<v-tab ripple>PuiCheckbox</v-tab>
|
|
28
|
+
<v-tab ripple>PuiSwitch</v-tab>
|
|
29
|
+
<v-tab ripple>PuiMultiSelect</v-tab>
|
|
30
|
+
<v-tab ripple>PuiCodeEditor</v-tab>
|
|
31
|
+
<v-tab ripple>PuiRichTextEditor</v-tab>
|
|
32
|
+
<v-tab ripple>PuiForm</v-tab>
|
|
33
|
+
|
|
34
|
+
<v-tab-item lazy>
|
|
35
|
+
<test-field-set></test-field-set>
|
|
36
|
+
</v-tab-item>
|
|
37
|
+
<v-tab-item lazy>
|
|
38
|
+
<test-field></test-field>
|
|
39
|
+
</v-tab-item>
|
|
40
|
+
<v-tab-item lazy>
|
|
41
|
+
<test-input-text-area></test-input-text-area>
|
|
42
|
+
</v-tab-item>
|
|
43
|
+
<v-tab-item lazy>
|
|
44
|
+
<test-input-text></test-input-text>
|
|
45
|
+
</v-tab-item>
|
|
46
|
+
<v-tab-item lazy>
|
|
47
|
+
<test-input-number></test-input-number>
|
|
48
|
+
</v-tab-item>
|
|
49
|
+
<v-tab-item lazy>
|
|
50
|
+
<test-input-spinner></test-input-spinner>
|
|
51
|
+
</v-tab-item>
|
|
52
|
+
<v-tab-item lazy>
|
|
53
|
+
<test-input-date></test-input-date>
|
|
54
|
+
</v-tab-item>
|
|
55
|
+
<v-tab-item lazy>
|
|
56
|
+
<test-input-radio-group></test-input-radio-group>
|
|
57
|
+
</v-tab-item>
|
|
58
|
+
<v-tab-item lazy>
|
|
59
|
+
<test-input-checkbox></test-input-checkbox>
|
|
60
|
+
</v-tab-item>
|
|
61
|
+
<v-tab-item lazy>
|
|
62
|
+
<test-input-switch></test-input-switch>
|
|
63
|
+
</v-tab-item>
|
|
64
|
+
<v-tab-item lazy>
|
|
65
|
+
<test-multi-select></test-multi-select>
|
|
66
|
+
</v-tab-item>
|
|
67
|
+
<v-tab-item lazy>
|
|
68
|
+
<test-code-editor></test-code-editor>
|
|
69
|
+
</v-tab-item>
|
|
70
|
+
<v-tab-item lazy>
|
|
71
|
+
<test-rich-text-editor></test-rich-text-editor>
|
|
72
|
+
</v-tab-item>
|
|
73
|
+
<v-tab-item lazy>
|
|
74
|
+
<test-pui-form></test-pui-form>
|
|
75
|
+
</v-tab-item>
|
|
76
|
+
</v-tabs>
|
|
77
|
+
</v-container>
|
|
78
|
+
</v-content>
|
|
79
|
+
</v-app>
|
|
80
|
+
</template>
|
|
81
|
+
|
|
82
|
+
<script>
|
|
83
|
+
import TestFieldSet from '@/tests/TestFieldSet';
|
|
84
|
+
import TestField from '@/tests/TestField';
|
|
85
|
+
import TestInputTextArea from '@/tests/TestInputTextArea';
|
|
86
|
+
import TestInputText from '@/tests/TestInputText';
|
|
87
|
+
import TestInputNumber from '@/tests/TestInputNumber';
|
|
88
|
+
import TestInputSpinner from '@/tests/TestInputSpinner';
|
|
89
|
+
import TestInputDate from '@/tests/TestInputDate';
|
|
90
|
+
import TestInputRadioGroup from '@/tests/TestInputRadioGroup';
|
|
91
|
+
import TestInputCheckbox from '@/tests/TestInputCheckbox';
|
|
92
|
+
import TestInputSwitch from '@/tests/TestInputSwitch';
|
|
93
|
+
import TestMultiSelect from '@/tests/TestMultiSelect';
|
|
94
|
+
import TestCodeEditor from '@/tests/TestCodeEditor';
|
|
95
|
+
import TestRichTextEditor from '@/tests/TestRichTextEditor';
|
|
96
|
+
import TestPuiForm from '@/tests/TestPuiForm';
|
|
97
|
+
|
|
98
|
+
export default {
|
|
99
|
+
name: 'App',
|
|
100
|
+
components: {
|
|
101
|
+
TestFieldSet,
|
|
102
|
+
TestField,
|
|
103
|
+
TestInputTextArea,
|
|
104
|
+
TestInputText,
|
|
105
|
+
TestInputNumber,
|
|
106
|
+
TestInputSpinner,
|
|
107
|
+
TestInputDate,
|
|
108
|
+
TestInputRadioGroup,
|
|
109
|
+
TestInputCheckbox,
|
|
110
|
+
TestInputSwitch,
|
|
111
|
+
TestMultiSelect,
|
|
112
|
+
TestCodeEditor,
|
|
113
|
+
TestRichTextEditor,
|
|
114
|
+
TestPuiForm
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
</script>
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-checkbox
|
|
3
|
+
:class="isRequired"
|
|
4
|
+
class="ml-2 mr-2"
|
|
5
|
+
:label="getLabel"
|
|
6
|
+
:rules="getRules"
|
|
7
|
+
v-model="internalModel"
|
|
8
|
+
@change="updateValue"
|
|
9
|
+
v-bind="allProps"
|
|
10
|
+
:ripple="false"
|
|
11
|
+
:false-value="falseValue"
|
|
12
|
+
:true-value="trueValue"
|
|
13
|
+
color="primary"
|
|
14
|
+
:error="internalError"
|
|
15
|
+
></v-checkbox>
|
|
16
|
+
</template>
|
|
17
|
+
|
|
18
|
+
<script>
|
|
19
|
+
import PuiFormComponentMixin from '../mixins/PuiFormComponentMixin';
|
|
20
|
+
|
|
21
|
+
export default {
|
|
22
|
+
name: 'PuiCheckbox',
|
|
23
|
+
mixins: [PuiFormComponentMixin],
|
|
24
|
+
props: {
|
|
25
|
+
value: {
|
|
26
|
+
required: false
|
|
27
|
+
},
|
|
28
|
+
rules: {
|
|
29
|
+
type: Array,
|
|
30
|
+
default: () => {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
// falseValue en lugar de 'false-value' para que funcione. Lo mismo con el true
|
|
35
|
+
falseValue: {
|
|
36
|
+
type: [Boolean, String, Number],
|
|
37
|
+
default: false,
|
|
38
|
+
required: false
|
|
39
|
+
},
|
|
40
|
+
trueValue: {
|
|
41
|
+
type: [Boolean, String, Number],
|
|
42
|
+
default: true,
|
|
43
|
+
required: false
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
computed: {
|
|
47
|
+
getRules() {
|
|
48
|
+
const rules = [...this.rules];
|
|
49
|
+
if (this.required) {
|
|
50
|
+
var func = (value) => !!value || this.requiredMessage;
|
|
51
|
+
var func2 = () => !this.internalError;
|
|
52
|
+
var func3 = () => {
|
|
53
|
+
if (this.internalModel === false) {
|
|
54
|
+
return this.requiredMessage;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
};
|
|
58
|
+
rules.push(func, func2, func3);
|
|
59
|
+
}
|
|
60
|
+
return rules;
|
|
61
|
+
},
|
|
62
|
+
isRequired() {
|
|
63
|
+
return { 'v-input--checkbox--required': this.required };
|
|
64
|
+
},
|
|
65
|
+
requiredMessage() {
|
|
66
|
+
return this.$t('pui9.error.field_selected');
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
watch: {
|
|
70
|
+
value(val) {
|
|
71
|
+
this.internalModel = val;
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
created() {
|
|
75
|
+
this.initialValue = this.value;
|
|
76
|
+
this.internalModel = this.value;
|
|
77
|
+
|
|
78
|
+
// Hay que pasar el value a string para que si llega del servidor '1' (por poner un ejemplo) el
|
|
79
|
+
// checkbox lo detecte como activo
|
|
80
|
+
if (this.value && typeof this.value !== 'boolean') {
|
|
81
|
+
this.internalModel = this.value.toString();
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
methods: {
|
|
85
|
+
updateValue(value) {
|
|
86
|
+
this.$emit('input', value);
|
|
87
|
+
this.checkValue();
|
|
88
|
+
},
|
|
89
|
+
checkValue() {
|
|
90
|
+
this.clearMessages();
|
|
91
|
+
if (this.required) {
|
|
92
|
+
if (this.internalModel === false) {
|
|
93
|
+
this.showErrorMessage();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
clearMessages() {
|
|
98
|
+
this.internalError = false;
|
|
99
|
+
},
|
|
100
|
+
showErrorMessage() {
|
|
101
|
+
this.internalError = true;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
</script>
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<v-layout lazy>
|
|
3
|
+
<div v-if="hasLabel()">
|
|
4
|
+
<label>{{ this.label }}</label>
|
|
5
|
+
<label class="codemirror-label-required" v-if="required">*</label>
|
|
6
|
+
</div>
|
|
7
|
+
<v-flex xs12 md12 lg12>
|
|
8
|
+
<v-layout wrap>
|
|
9
|
+
<textarea id="codemirror" name="codemirror" ref="codemirror" v-model="data"></textarea>
|
|
10
|
+
<v-text-field v-if="required" v-model="data" :rules="getRules" style="display: none"></v-text-field>
|
|
11
|
+
<div class="codemirror-error-message">
|
|
12
|
+
<label class="codemirror-label-error">{{ $t('pui9.error.field_selected') }}</label>
|
|
13
|
+
</div>
|
|
14
|
+
</v-layout>
|
|
15
|
+
</v-flex>
|
|
16
|
+
</v-layout>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script>
|
|
20
|
+
import CodeMirror from 'codemirror';
|
|
21
|
+
import 'codemirror/lib/codemirror.css';
|
|
22
|
+
import 'codemirror/theme/base16-dark.css';
|
|
23
|
+
import 'codemirror/mode/javascript/javascript.js';
|
|
24
|
+
import 'codemirror/mode/htmlmixed/htmlmixed.js';
|
|
25
|
+
import 'codemirror/mode/css/css.js';
|
|
26
|
+
import 'codemirror/mode/xml/xml.js';
|
|
27
|
+
import 'codemirror/mode/python/python.js';
|
|
28
|
+
|
|
29
|
+
export default {
|
|
30
|
+
name: 'PuiCodeEditor',
|
|
31
|
+
props: {
|
|
32
|
+
mode: {
|
|
33
|
+
type: String,
|
|
34
|
+
required: true
|
|
35
|
+
},
|
|
36
|
+
label: {
|
|
37
|
+
type: String,
|
|
38
|
+
default: ''
|
|
39
|
+
},
|
|
40
|
+
value: {
|
|
41
|
+
type: String,
|
|
42
|
+
default: ''
|
|
43
|
+
},
|
|
44
|
+
required: {
|
|
45
|
+
type: Boolean,
|
|
46
|
+
default: false
|
|
47
|
+
},
|
|
48
|
+
validationErrors: {
|
|
49
|
+
type: Boolean,
|
|
50
|
+
default: false
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
computed: {
|
|
54
|
+
externalValue() {
|
|
55
|
+
return this.value;
|
|
56
|
+
},
|
|
57
|
+
getRules() {
|
|
58
|
+
const rules = [];
|
|
59
|
+
if (this.required) {
|
|
60
|
+
rules.push((data) => !!data || 'error');
|
|
61
|
+
}
|
|
62
|
+
return rules;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
data() {
|
|
66
|
+
return {
|
|
67
|
+
data: this.value,
|
|
68
|
+
editor: null
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
mounted() {
|
|
72
|
+
this.createEditor();
|
|
73
|
+
},
|
|
74
|
+
watch: {
|
|
75
|
+
data(newValue) {
|
|
76
|
+
this.checkContent();
|
|
77
|
+
const cursor = this.editor.getCursor();
|
|
78
|
+
this.editor.setValue(newValue);
|
|
79
|
+
this.$emit('input', newValue);
|
|
80
|
+
this.editor.setCursor(cursor);
|
|
81
|
+
},
|
|
82
|
+
externalValue(newValue) {
|
|
83
|
+
this.data = newValue;
|
|
84
|
+
},
|
|
85
|
+
validationErrors() {
|
|
86
|
+
this.checkContent();
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
methods: {
|
|
90
|
+
createEditor() {
|
|
91
|
+
const self = this;
|
|
92
|
+
this.editor = CodeMirror.fromTextArea(this.$refs.codemirror, {
|
|
93
|
+
mode: this.mode,
|
|
94
|
+
lineNumbers: true
|
|
95
|
+
});
|
|
96
|
+
this.editor.on('change', (editor) => {
|
|
97
|
+
this.data = editor.getValue();
|
|
98
|
+
self.$emit('input', this.data);
|
|
99
|
+
});
|
|
100
|
+
this.editor.on('blur', () => {
|
|
101
|
+
this.checkContent();
|
|
102
|
+
});
|
|
103
|
+
},
|
|
104
|
+
hasLabel() {
|
|
105
|
+
return this.label !== undefined;
|
|
106
|
+
},
|
|
107
|
+
checkContent() {
|
|
108
|
+
var errorMsg = this.$el.getElementsByClassName('codemirror-error-message');
|
|
109
|
+
var codeContainer = this.$el.getElementsByClassName('CodeMirror');
|
|
110
|
+
|
|
111
|
+
if (this.required) {
|
|
112
|
+
if (this.data === null || this.data === '') {
|
|
113
|
+
errorMsg[0].style.display = 'block';
|
|
114
|
+
codeContainer[0].classList.add('codemirror-error-code');
|
|
115
|
+
} else {
|
|
116
|
+
errorMsg[0].style.display = 'none';
|
|
117
|
+
codeContainer[0].classList.remove('codemirror-error-code');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
</script>
|