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.
Files changed (60) hide show
  1. package/README.md +43 -0
  2. package/dist/demo.html +10 -0
  3. package/dist/pui9-components.common.js +81953 -0
  4. package/dist/pui9-components.common.js.map +1 -0
  5. package/dist/pui9-components.css +5 -0
  6. package/dist/pui9-components.umd.js +81963 -0
  7. package/dist/pui9-components.umd.js.map +1 -0
  8. package/dist/pui9-components.umd.min.js +308 -0
  9. package/dist/pui9-components.umd.min.js.map +1 -0
  10. package/package-lock.json +15945 -0
  11. package/package.json +78 -0
  12. package/src/App.vue +117 -0
  13. package/src/components/PuiCheckbox.vue +105 -0
  14. package/src/components/PuiCodeEditor.vue +123 -0
  15. package/src/components/PuiDateField.vue +1004 -0
  16. package/src/components/PuiField.vue +30 -0
  17. package/src/components/PuiFieldSet.vue +27 -0
  18. package/src/components/PuiFormFooter.vue +64 -0
  19. package/src/components/PuiFormFooterBtns.vue +118 -0
  20. package/src/components/PuiFormHeader.vue +25 -0
  21. package/src/components/PuiFormLoading.vue +12 -0
  22. package/src/components/PuiFormMiniAudit.vue +53 -0
  23. package/src/components/PuiMasterDetail.vue +96 -0
  24. package/src/components/PuiModalDialog.vue +87 -0
  25. package/src/components/PuiModalDialogForm.vue +205 -0
  26. package/src/components/PuiMultiSelect.vue +499 -0
  27. package/src/components/PuiNumberField.vue +503 -0
  28. package/src/components/PuiPasswordField.vue +105 -0
  29. package/src/components/PuiRadioGroup.vue +105 -0
  30. package/src/components/PuiRichTextEditor.vue +117 -0
  31. package/src/components/PuiSelect.vue +1638 -0
  32. package/src/components/PuiSelectDetailDialog.vue +106 -0
  33. package/src/components/PuiSelectTextService.vue +61 -0
  34. package/src/components/PuiSpinnerField.vue +484 -0
  35. package/src/components/PuiSwitch.vue +104 -0
  36. package/src/components/PuiTextArea.vue +203 -0
  37. package/src/components/PuiTextField.vue +272 -0
  38. package/src/dateTimeUtils.js +78 -0
  39. package/src/index.js +73 -0
  40. package/src/main.js +33 -0
  41. package/src/mixins/PuiFormComponentMixin.js +81 -0
  42. package/src/mixins/PuiMultiSelectMixin.js +106 -0
  43. package/src/mixins/PuiUtilsNumberMixin.js +19 -0
  44. package/src/plugins/vuetify.js +32 -0
  45. package/src/tests/TestAutocomplete.vue +138 -0
  46. package/src/tests/TestCodeEditor.vue +48 -0
  47. package/src/tests/TestField.vue +22 -0
  48. package/src/tests/TestFieldSet.vue +30 -0
  49. package/src/tests/TestInputCheckbox.vue +53 -0
  50. package/src/tests/TestInputDate.vue +146 -0
  51. package/src/tests/TestInputNumber.vue +77 -0
  52. package/src/tests/TestInputRadioGroup.vue +86 -0
  53. package/src/tests/TestInputSpinner.vue +77 -0
  54. package/src/tests/TestInputSwitch.vue +52 -0
  55. package/src/tests/TestInputText.vue +120 -0
  56. package/src/tests/TestInputTextArea.vue +73 -0
  57. package/src/tests/TestMultiSelect.vue +127 -0
  58. package/src/tests/TestPuiForm.vue +68 -0
  59. package/src/tests/TestRichTextEditor.vue +54 -0
  60. package/src/utils.js +148 -0
@@ -0,0 +1,1638 @@
1
+ <template>
2
+ <!-- DESKTOP -->
3
+ <div v-if="!isMobile">
4
+ <div v-if="toplabel" class="ml-1 mr-1">
5
+ <v-layout>
6
+ <v-flex xs12>
7
+ <label v-if="getLabel === '$nbsp;'">&nbsp;</label>
8
+ <label v-else :class="getLabelRequiredClass">{{ getLabel }}</label>
9
+ </v-flex>
10
+ </v-layout>
11
+ <v-layout>
12
+ <v-flex
13
+ :class="
14
+ (prependInnerIconRead || prependInnerIconUpdate) && prependInnerIconInsert
15
+ ? 'xs10'
16
+ : (prependInnerIconRead || prependInnerIconUpdate) && !prependInnerIconInsert
17
+ ? 'xs11'
18
+ : 'xs12'
19
+ "
20
+ >
21
+ <v-autocomplete
22
+ v-model="selectedItems"
23
+ class="pui-select"
24
+ :class="getEditedClass"
25
+ solo
26
+ flat
27
+ @click:append="menuArrow"
28
+ ref="arrowUp"
29
+ :attach="attach ? true : false"
30
+ :autocomplete="!filterServerSide"
31
+ :no-filter="filterServerSide"
32
+ :readonly="readonly"
33
+ :return-object="return_object"
34
+ :clearable="clearable"
35
+ :label="label"
36
+ :items="theItems"
37
+ :error="internalError"
38
+ :error-messages="internalErrorMessages"
39
+ :item-text="itemText"
40
+ :item-value="itemValue"
41
+ :search-input.sync="search"
42
+ :required="required"
43
+ :rules="getRules"
44
+ :disabled="disabled"
45
+ :multiple="multiple"
46
+ :placeholder="getPlaceholder"
47
+ :filter="filter"
48
+ v-bind="allProps"
49
+ @focus="focusValue"
50
+ @blur="checkValue"
51
+ :hide-details="hideDetails"
52
+ >
53
+ <template slot="append-item" v-if="modelName">
54
+ <infinite-loading @infinite="loading === false && getMoreItemsFromPuiList(search)" ref="infiniteLoading">
55
+ <span style="font-weight: bold" slot="no-more">{{ allShownMesage }}</span>
56
+ <span slot="no-results"></span>
57
+ </infinite-loading>
58
+ </template>
59
+ <template v-slot:item="{ item, attrs, on }">
60
+ <template v-if="!itemTemplate">
61
+ <v-list-item v-bind="attrs" v-on="on" class="pui-select__item">
62
+ <v-list-item-content class="pl-3">
63
+ <pui-select-text-service :item="item" :itemText="itemText" />
64
+ </v-list-item-content>
65
+ <v-list-item-action class="pr-3" v-if="attrs['aria-selected'] === 'true'">
66
+ <v-icon small class="pui-select__item-icon">fa fa-check</v-icon>
67
+ </v-list-item-action>
68
+ </v-list-item>
69
+ </template>
70
+ <template v-else>
71
+ <slot name="theTemplate" :item="item" :selected="attrs.selected"></slot>
72
+ </template>
73
+ </template>
74
+ <template slot="selection" slot-scope="{ item, selected, parent }">
75
+ <template v-if="selectTemplate">
76
+ <slot name="selectionTemplate" :item="item"></slot>
77
+ </template>
78
+ <template v-else-if="multiple === true">
79
+ <v-chip color="grey lighten-2" :input-value="selected" label small tabindex="-1">
80
+ <pui-select-text-service :item="item" type="select" :itemText="itemText" />
81
+ <v-icon small @click.native.stop.prevent.capture="parent.selectItem(item)">close</v-icon>
82
+ </v-chip>
83
+ </template>
84
+ <template v-else>
85
+ <pui-select-text-service
86
+ :truncate="!isDisabled"
87
+ :writing="isMenuOpened"
88
+ :disabled="disabled"
89
+ :item="item"
90
+ type="select"
91
+ :itemText="itemText"
92
+ />
93
+ </template>
94
+ </template>
95
+ </v-autocomplete>
96
+ </v-flex>
97
+ <v-flex xs1 v-if="prependInnerIconUpdate || prependInnerIconRead">
98
+ <v-btn v-if="prependInnerIconUpdate" class="pui-select__prepend-inner-icon--desktop" icon @click="goToDetail('update')">
99
+ <v-icon>{{ prependInnerIconUpdate }}</v-icon>
100
+ </v-btn>
101
+ <v-btn v-else-if="prependInnerIconRead" class="pui-select__prepend-inner-icon--desktop" icon @click="goToDetail('read')">
102
+ <v-icon>{{ prependInnerIconRead }}</v-icon>
103
+ </v-btn>
104
+ </v-flex>
105
+ <v-flex xs1 v-if="prependInnerIconInsert">
106
+ <v-btn v-if="prependInnerIconInsert" class="pui-select__prepend-inner-icon--desktop" icon @click="goToDetail('create')">
107
+ <v-icon>{{ prependInnerIconInsert }}</v-icon>
108
+ </v-btn>
109
+ </v-flex>
110
+ </v-layout>
111
+ </div>
112
+ <div v-else class="ml-1 mr-1">
113
+ <v-layout>
114
+ <v-flex :class="labelColumnStyles ? labelColumnStyles : 'xs12 sm6 md4 xl3'">
115
+ <label :class="getLabelRequiredClass">{{ getLabel }}</label>
116
+ </v-flex>
117
+ <v-flex
118
+ :class="
119
+ valueColumnStyles
120
+ ? valueColumnStyles
121
+ : !prependInnerIconRead && !prependInnerIconUpdate && !prependInnerIconInsert
122
+ ? 'xs12 sm6 md8 xl9'
123
+ : 'xs10 sm5 md7 xl8'
124
+ "
125
+ >
126
+ <v-autocomplete
127
+ v-model="selectedItems"
128
+ class="pui-select"
129
+ :class="getEditedClass"
130
+ solo
131
+ flat
132
+ @click:append="menuArrow"
133
+ ref="arrowUp"
134
+ :attach="attach ? true : false"
135
+ :autocomplete="!filterServerSide"
136
+ :no-filter="filterServerSide"
137
+ :readonly="readonly"
138
+ :return-object="return_object"
139
+ :clearable="clearable"
140
+ :label="label"
141
+ :error="internalError"
142
+ :error-messages="internalErrorMessages"
143
+ :items="theItems"
144
+ :item-text="itemText"
145
+ :item-value="itemValue"
146
+ :search-input.sync="search"
147
+ :required="required"
148
+ :rules="getRules"
149
+ :disabled="isDisabled"
150
+ :multiple="multiple"
151
+ :placeholder="getPlaceholder"
152
+ :filter="filter"
153
+ v-bind="allProps"
154
+ @focus="focusValue"
155
+ @blur="checkValue"
156
+ :hide-details="hideDetails"
157
+ >
158
+ <template slot="append-item" v-if="modelName">
159
+ <infinite-loading @infinite="loading === false && getMoreItemsFromPuiList(search)" ref="infiniteLoading">
160
+ <span style="font-weight: bold" slot="no-more">{{ allShownMesage }}</span>
161
+ <span slot="no-results"></span>
162
+ </infinite-loading>
163
+ </template>
164
+ <template v-slot:item="{ item, attrs, on }">
165
+ <template v-if="!itemTemplate">
166
+ <v-list-item v-bind="attrs" v-on="on" class="pui-select__item">
167
+ <v-list-item-content class="pl-3">
168
+ <pui-select-text-service :item="item" :itemText="itemText" />
169
+ </v-list-item-content>
170
+ <v-list-item-action class="pr-3" v-if="attrs['aria-selected'] === 'true'">
171
+ <v-icon small class="pui-select__item-icon">fa fa-check</v-icon>
172
+ </v-list-item-action>
173
+ </v-list-item>
174
+ </template>
175
+ <template v-else>
176
+ <slot name="theTemplate" :item="item" :selected="attrs.selected" :tile="attrs.tile"></slot>
177
+ </template>
178
+ </template>
179
+ <template slot="selection" slot-scope="{ item, selected, parent }">
180
+ <template v-if="selectTemplate === true">
181
+ <slot name="selectionTemplate" :item="item"></slot>
182
+ </template>
183
+ <template v-else-if="multiple === true">
184
+ <v-chip color="grey lighten-2" :input-value="selected" label small tabindex="-1">
185
+ <pui-select-text-service :item="item" type="select" :itemText="itemText" />
186
+ <v-icon small @click.native.stop.prevent.capture="parent.selectItem(item)">close</v-icon>
187
+ </v-chip>
188
+ </template>
189
+ <template v-else>
190
+ <pui-select-text-service
191
+ :truncate="!isDisabled"
192
+ :writing="isMenuOpened"
193
+ :item="item"
194
+ type="select"
195
+ :itemText="itemText"
196
+ />
197
+ </template>
198
+ </template>
199
+ </v-autocomplete>
200
+ </v-flex>
201
+ <v-flex xs1 v-if="prependInnerIconUpdate || prependInnerIconRead">
202
+ <v-btn v-if="prependInnerIconUpdate" class="pui-select__prepend-inner-icon--desktop" icon @click="goToDetail('update')">
203
+ <v-icon>{{ prependInnerIconUpdate }}</v-icon>
204
+ </v-btn>
205
+ <v-btn v-else-if="prependInnerIconRead" class="pui-select__prepend-inner-icon--desktop" icon @click="goToDetail('read')">
206
+ <v-icon>{{ prependInnerIconRead }}</v-icon>
207
+ </v-btn>
208
+ </v-flex>
209
+ <v-flex xs1 v-if="prependInnerIconInsert">
210
+ <v-btn v-if="prependInnerIconInsert" class="pui-select__prepend-inner-icon--desktop" icon @click="goToDetail('create')">
211
+ <v-icon>{{ prependInnerIconInsert }}</v-icon>
212
+ </v-btn>
213
+ </v-flex>
214
+ </v-layout>
215
+ </div>
216
+ <pui-select-detail-dialog
217
+ v-if="showDetailComponent"
218
+ :parentId="puiSelectId"
219
+ :componentLabel="detailComponentLabel"
220
+ :componentName="detailComponentName"
221
+ :componentPk="detailComponentPk"
222
+ :componentMethod="detailComponentMethod"
223
+ :modelName="detailModelName"
224
+ ></pui-select-detail-dialog>
225
+ </div>
226
+ <!-- MOBILE -->
227
+ <div v-else>
228
+ <v-layout>
229
+ <v-flex xs12>
230
+ <label v-if="getLabel === '$nbsp;'">&nbsp;</label>
231
+ <label v-else class="pui-select__label-mobile" :class="getLabelRequiredClass">{{ getLabel }}</label>
232
+ </v-flex>
233
+ </v-layout>
234
+ <v-layout>
235
+ <v-flex
236
+ :class="
237
+ (prependInnerIconRead || prependInnerIconUpdate) && prependInnerIconInsert
238
+ ? 'xs10'
239
+ : (prependInnerIconRead || prependInnerIconUpdate) && !prependInnerIconInsert
240
+ ? 'xs11'
241
+ : 'xs12'
242
+ "
243
+ >
244
+ <v-autocomplete
245
+ v-model="selectedItems"
246
+ class="pui-select"
247
+ :class="getEditedClass"
248
+ solo
249
+ flat
250
+ @click:append="menuArrow"
251
+ ref="arrowUp"
252
+ :attach="attach ? true : false"
253
+ :autocomplete="!filterServerSide"
254
+ :no-filter="filterServerSide"
255
+ :readonly="readonly"
256
+ :return-object="return_object"
257
+ :clearable="clearable"
258
+ :label="label"
259
+ :items="theItems"
260
+ :error="internalError"
261
+ :error-messages="internalErrorMessages"
262
+ :item-text="itemText"
263
+ :item-value="itemValue"
264
+ :search-input.sync="search"
265
+ :required="required"
266
+ :rules="getRules"
267
+ :disabled="disabled"
268
+ :multiple="multiple"
269
+ :placeholder="getPlaceholder"
270
+ :filter="filter"
271
+ v-bind="allProps"
272
+ @focus="focusValue"
273
+ @blur="checkValue"
274
+ :hide-details="hideDetails"
275
+ >
276
+ <template slot="append-item" v-if="modelName">
277
+ <infinite-loading @infinite="loading === false && getMoreItemsFromPuiList(search)" ref="infiniteLoading">
278
+ <span style="font-weight: bold" slot="no-more">{{ allShownMesage }}</span>
279
+ <span slot="no-results"></span>
280
+ </infinite-loading>
281
+ </template>
282
+ <template v-slot:item="{ item, attrs, on }">
283
+ <template v-if="!itemTemplate">
284
+ <v-list-item v-bind="attrs" v-on="on" class="pui-select__item">
285
+ <v-list-item-content class="pl-3">
286
+ <pui-select-text-service :item="item" :itemText="itemText" />
287
+ </v-list-item-content>
288
+ <v-list-item-action class="pr-3" v-if="attrs['aria-selected'] === 'true'">
289
+ <v-icon class="pui-select__item-icon">fa fa-check</v-icon>
290
+ </v-list-item-action>
291
+ </v-list-item>
292
+ </template>
293
+ <template v-else>
294
+ <slot name="theTemplate" :item="item" :selected="attrs.selected"></slot>
295
+ </template>
296
+ </template>
297
+ <template slot="selection" slot-scope="{ item, selected, parent }">
298
+ <template v-if="selectTemplate">
299
+ <slot name="selectionTemplate" :item="item"></slot>
300
+ </template>
301
+ <template v-else-if="multiple === true">
302
+ <v-chip color="grey lighten-2" :input-value="selected" label small>
303
+ <pui-select-text-service :item="item" type="select" :itemText="itemText" />
304
+ <v-icon small @click.native.stop.prevent.capture="parent.selectItem(item)">close</v-icon>
305
+ </v-chip>
306
+ </template>
307
+ <template v-else>
308
+ <pui-select-text-service
309
+ :truncate="!isDisabled"
310
+ :writing="isMenuOpened"
311
+ :item="item"
312
+ type="select"
313
+ :itemText="itemText"
314
+ />
315
+ </template>
316
+ </template>
317
+ </v-autocomplete>
318
+ </v-flex>
319
+ <v-flex xs1 v-if="prependInnerIconUpdate || prependInnerIconRead">
320
+ <v-btn v-if="prependInnerIconUpdate" class="pui-select__prepend-inner-icon--desktop" icon @click="goToDetail('update')">
321
+ <v-icon>{{ prependInnerIconUpdate }}</v-icon>
322
+ </v-btn>
323
+ <v-btn v-else-if="prependInnerIconRead" class="pui-select__prepend-inner-icon--desktop" icon @click="goToDetail('read')">
324
+ <v-icon>{{ prependInnerIconRead }}</v-icon>
325
+ </v-btn>
326
+ </v-flex>
327
+ <v-flex xs1 v-if="prependInnerIconInsert">
328
+ <v-btn v-if="prependInnerIconInsert" class="pui-select__prepend-inner-icon--desktop" icon @click="goToDetail('create')">
329
+ <v-icon>{{ prependInnerIconInsert }}</v-icon>
330
+ </v-btn>
331
+ </v-flex>
332
+ </v-layout>
333
+ <pui-select-detail-dialog
334
+ v-if="showDetailComponent"
335
+ :parentId="puiSelectId"
336
+ :componentLabel="detailComponentLabel"
337
+ :componentName="detailComponentName"
338
+ :componentPk="detailComponentPk"
339
+ :componentMethod="detailComponentMethod"
340
+ :modelName="detailModelName"
341
+ ></pui-select-detail-dialog>
342
+ </div>
343
+ </template>
344
+
345
+ <script>
346
+ import PuiSelectTextService from './PuiSelectTextService';
347
+ import PuiSelectDetailDialog from './PuiSelectDetailDialog';
348
+ import InfiniteLoading from 'vue-infinite-loading';
349
+
350
+ export default {
351
+ //TOFOLLOW
352
+ //https://github.com/vuetifyjs/vuetify/issues/5087 Al cerrar las chips del multiselect se abre el menú
353
+ name: 'PuiSelect',
354
+ components: {
355
+ PuiSelectTextService,
356
+ PuiSelectDetailDialog,
357
+ 'infinite-loading': InfiniteLoading
358
+ },
359
+ /* Properties provided by the pui-select */
360
+ props: {
361
+ value: {
362
+ required: false
363
+ },
364
+ /* Type: Boolean
365
+ Native by the v-select
366
+ If true adds a close icon to the selection*/
367
+ clearable: {
368
+ type: [Boolean],
369
+ default: false,
370
+ required: false
371
+ },
372
+ /* Type: Boolean
373
+ Native by the v-select
374
+ If true allows to select multiple items, selectedItems becomes an Array*/
375
+ multiple: {
376
+ type: [Boolean],
377
+ default: false,
378
+ required: false
379
+ },
380
+ /* Type: Boolean
381
+ If true applies a custom template slot for the list of items
382
+ The parent has to provide it*/
383
+ itemTemplate: {
384
+ type: Boolean,
385
+ default: false
386
+ },
387
+ selectTemplate: {
388
+ type: Boolean,
389
+ default: false
390
+ },
391
+ /* Type: Number {Integer}
392
+ It is used when the items come from a Service,
393
+ it will requeste paginated requests of ths number of items*/
394
+ rows: {
395
+ type: Number,
396
+ default: -1
397
+ },
398
+ disabled: {
399
+ type: [Boolean],
400
+ default: false,
401
+ required: false
402
+ },
403
+ filter: {
404
+ type: Function,
405
+ required: false
406
+ },
407
+ readonly: {
408
+ type: [Boolean],
409
+ default: false,
410
+ required: false
411
+ },
412
+ toplabel: {
413
+ type: [Boolean],
414
+ default: false,
415
+ required: false
416
+ },
417
+ placeholder: {
418
+ type: [String],
419
+ default: ' ',
420
+ required: false
421
+ },
422
+ return_object: {
423
+ type: Boolean,
424
+ default: true
425
+ },
426
+ noeditable: {
427
+ type: [Boolean],
428
+ default: false,
429
+ required: false
430
+ },
431
+ attach: {
432
+ type: String,
433
+ default: null,
434
+ required: false
435
+ },
436
+ labelColumnStyles: {
437
+ type: [String],
438
+ required: false
439
+ },
440
+ valueColumnStyles: {
441
+ type: [String],
442
+ required: false
443
+ },
444
+ hideDetails: {
445
+ type: Boolean,
446
+ default: false,
447
+ required: false
448
+ },
449
+ 'hide-selected': {
450
+ type: Boolean,
451
+ default: false,
452
+ required: false
453
+ },
454
+ 'hide-no-data': {
455
+ type: Boolean,
456
+ default: false,
457
+ required: false
458
+ },
459
+ detailModelName: {
460
+ type: String,
461
+ default: null,
462
+ required: false
463
+ },
464
+ detailComponentName: {
465
+ type: String,
466
+ default: null,
467
+ required: false
468
+ },
469
+ detailActions: {
470
+ type: Object,
471
+ default: () => {
472
+ return {
473
+ read: true,
474
+ create: true,
475
+ update: true
476
+ };
477
+ },
478
+ required: false
479
+ },
480
+ /*
481
+ Type: Array of Objects
482
+ Items provided by the parent component */
483
+ items: {
484
+ type: Array,
485
+ default: null,
486
+ required: false
487
+ },
488
+ /**
489
+ * Los items seleccionados que se pasan de inicio, se pasa en la directiva v-model al utilizar este componente
490
+ * puede ser un array de Items igual que en la propiedad :items, o un array con los id's solamente
491
+ */
492
+ itemsToSelect: {
493
+ type: Array,
494
+ default: () => []
495
+ },
496
+ /**
497
+ * The fields to be searched
498
+ */
499
+ queryFields: {
500
+ type: Array,
501
+ default: () => [],
502
+ required: false
503
+ },
504
+ /* Type: String
505
+ Native by the v-select
506
+ If Present the select will show this label in the input */
507
+ label: {
508
+ type: [String],
509
+ default: '',
510
+ required: false
511
+ },
512
+ /* Type: String
513
+ Instead of providing the items, if controller is provided it will get the items by calling this web service in @getItemsFromService or @getItemsFromPuiList */
514
+ controller: {
515
+ type: String,
516
+ default: '/puisearch',
517
+ required: false
518
+ },
519
+ /* Type: Object
520
+ The pui9 list filter object*/
521
+ pui9filter: {
522
+ type: Object,
523
+ default: null,
524
+ required: false
525
+ },
526
+ filterId: {
527
+ type: String
528
+ },
529
+ filterMap: {
530
+ type: Object,
531
+ default: null
532
+ },
533
+ filterMapOp: {
534
+ type: String,
535
+ default: 'and'
536
+ },
537
+ filterParentMap: {
538
+ type: Object,
539
+ default: null
540
+ },
541
+ fixedFilter: {
542
+ type: Object,
543
+ default: null
544
+ },
545
+ order: {
546
+ type: Object,
547
+ default: null
548
+ },
549
+ /* Type: String
550
+ Instead of providing the items, if controller is provided it will get the items by calling the controller in @getItems */
551
+ modelFormMapping: {
552
+ type: Object,
553
+ default: null,
554
+ required: false
555
+ },
556
+ /* Type: String
557
+ The items text property name */
558
+ itemText: {
559
+ type: [String, Array, Function],
560
+ default: 'text',
561
+ required: true
562
+ },
563
+ modelName: {
564
+ type: String
565
+ },
566
+ rules: {
567
+ type: Array,
568
+ default: () => {
569
+ return [];
570
+ }
571
+ },
572
+ /* Type: String
573
+ The items id property name */
574
+ itemValue: {
575
+ type: [String, Array, Function],
576
+ default: 'value',
577
+ required: false
578
+ },
579
+ /* Type: Boolean
580
+ Native by the v-select
581
+ If true adds a close icon to the selection, @model[property] */
582
+ searchable: {
583
+ type: [Boolean],
584
+ default: true,
585
+ required: false
586
+ },
587
+
588
+ /* Type: Boolean
589
+ If true applies the required rule in @rules.required */
590
+ required: {
591
+ type: [Boolean],
592
+ default: false,
593
+ required: false
594
+ },
595
+ /* Type: Number
596
+ Default number of rows for a multiselect */
597
+ rowNum: {
598
+ type: Number,
599
+ default: 1000,
600
+ required: false
601
+ },
602
+ /* Type: Boolean
603
+ Fix for reactivity, require itemsToSelect to be a computed */
604
+ reactive: {
605
+ type: Boolean,
606
+ default: false,
607
+ required: false
608
+ },
609
+ emitSelectedItemsEventOnFirstLoad: {
610
+ type: Boolean,
611
+ default: true,
612
+ required: false
613
+ }
614
+ },
615
+ data() {
616
+ return {
617
+ isMobile: false,
618
+ initialValue: null,
619
+ selectedItems: null,
620
+ page: 0,
621
+ showDetailComponent: false,
622
+ newDisabled: undefined,
623
+ hasBeenFocused: false,
624
+ itemTextMultiple: false,
625
+ itemValueMultiple: false,
626
+ itemTextNested: false,
627
+ itemValueNested: false,
628
+ search: '',
629
+ loading: false,
630
+ theItems: [],
631
+ internalError: false,
632
+ internalErrorMessages: '',
633
+ selected: false,
634
+ initialItemsToSelect: [],
635
+ internalController: null,
636
+ previousSelectedItems: undefined,
637
+ doingThings: false,
638
+ itemManuallySelected: false,
639
+ itemProgrammaticallySelected: false,
640
+ firstLoad: true,
641
+ requestDataPromise: undefined,
642
+ selectedItemsEventFirstLoad: true,
643
+ internalQueryFields: []
644
+ };
645
+ },
646
+ watch: {
647
+ modelName(modelName) {
648
+ if (modelName && this.isEmpty(this.theItems)) {
649
+ const theModel = this.$store.getters.getModelByName(modelName);
650
+ this.internalController = this.controller || theModel.url.list;
651
+ this.internalController && this.getItemsFromPuiList();
652
+ this.internalQueryFields = !this.isEmpty(this.queryFields) ? this.queryFields : theModel.columns?.map(c => c.name);
653
+ }
654
+ },
655
+ itemsToSelect: {
656
+ handler(newValue) {
657
+ if (this.isMultiSelect === true) {
658
+ this.trackItemsToSelect === true && this.selectItems();
659
+ } else {
660
+ this.reactiveHandler(newValue);
661
+ }
662
+ },
663
+ deep: true
664
+ },
665
+ fixedFilterWatcher: {
666
+ handler(newFilter, oldFilter) {
667
+ if (newFilter === oldFilter) {
668
+ return;
669
+ }
670
+ this.previousSelectedItems = this.previousSelectedItems || this.selectedItems;
671
+ this.resetItems();
672
+ this.filterItems();
673
+ },
674
+ deep: true
675
+ },
676
+ filterMapWatcher: {
677
+ handler(newFilter, oldFilter) {
678
+ if (newFilter === oldFilter) {
679
+ return;
680
+ }
681
+ this.resetItems(JSON.parse(newFilter));
682
+ this.filterItems(null);
683
+ },
684
+ deep: true
685
+ },
686
+ loading(newValue, oldValue) {
687
+ if (newValue === false && oldValue === true && !this.isEmpty(this.previousSelectedItems)) {
688
+ this.selectPreviousValidItems();
689
+ this.previousSelectedItems = undefined;
690
+ }
691
+ },
692
+ search(newValue, oldValue) {
693
+ if (this.multiple && this.isEmpty(newValue) && this.isEmpty(oldValue)) {
694
+ return;
695
+ }
696
+ this.searchable && this.filterItems(newValue);
697
+ },
698
+ selectedItems(newVal) {
699
+ if (this.reactive) {
700
+ if (this.firstLoad) {
701
+ this.firstLoad = false;
702
+ } else if (!this.itemProgrammaticallySelected) {
703
+ this.itemManuallySelected = true;
704
+ } else {
705
+ this.itemProgrammaticallySelected = false;
706
+ }
707
+ }
708
+ this.clearMessages();
709
+ if (this.modelFormMapping) {
710
+ this.$emit('input', this.replaceMapping());
711
+ } else {
712
+ this.$emit('input', newVal);
713
+ }
714
+ this.$emit('change', newVal);
715
+
716
+ if (this.emitSelectedItemsEventOnFirstLoad || !this.selectedItemsEventFirstLoad) {
717
+ this.$puiEvents.$emit(`onPuiSelect_selectedItems-${this.puiSelectId}`, { id: this.puiSelectId, model: newVal });
718
+ }
719
+ this.selectedItemsEventFirstLoad = false;
720
+ if (this.attach && this.puiSelectId && !this.multiple && newVal) {
721
+ // Need for browser to recalculate correctly getBoundingClientSelectPosition
722
+ document.getElementById(this.puiSelectId).click();
723
+ }
724
+ },
725
+ disabled(newVal) {
726
+ this.newDisabled = newVal;
727
+ if (newVal) {
728
+ this.clearMessages();
729
+ }
730
+ },
731
+ detailComponentName(newValue, oldValue) {
732
+ if (!this.isEmpty(oldValue)) {
733
+ this.$puiEvents.$off(`pui-modalDialog-${oldValue}_${this.puiSelectId}_popup-hide`);
734
+ }
735
+ if (!this.isEmpty(newValue)) {
736
+ const self = this;
737
+ this.$puiEvents.$on(`pui-modalDialog-${newValue}_${this.puiSelectId}_popup-hide`, (data) => {
738
+ self.showDetailComponent = false;
739
+ if (data) {
740
+ const newItem = {};
741
+ const itemValues = this.itemValue;
742
+ itemValues.forEach((pkValue) => {
743
+ newItem[pkValue] = data[pkValue];
744
+ });
745
+ self.itemsToSelect[0] = newItem;
746
+ self.onPuiSelectItemsToSelect = [newItem];
747
+ self.getSelectedItemsFromPuiList();
748
+ }
749
+ });
750
+ }
751
+ },
752
+ queryFields(queryFields) {
753
+ if (!this.isEmpty(queryFields)) {
754
+ this.internalQueryFields = queryFields;
755
+ } else if (this.modelName) {
756
+ const theModel = this.$store.getters.getModelByName(this.modelName);
757
+ this.internalQueryFields = theModel.columns?.map(c => c.name);
758
+ }
759
+ }
760
+ },
761
+ computed: {
762
+ allProps() {
763
+ return { ...this.$attrs, ...this.$props };
764
+ },
765
+ isMultiSelect() {
766
+ return this.$options._componentTag === 'puimultiselect';
767
+ },
768
+ getItemsFrom() {
769
+ if (this.modelName) {
770
+ return 'FromPuiList';
771
+ } else if (this.internalController) {
772
+ return 'FromService';
773
+ }
774
+ return '';
775
+ },
776
+ fixedFilterWatcher() {
777
+ return JSON.stringify(this.fixedFilter);
778
+ },
779
+ filterMapWatcher() {
780
+ return JSON.stringify(this.filterMap);
781
+ },
782
+ requiredMessage() {
783
+ return this.$t('pui9.error.field_required');
784
+ },
785
+ allShownMesage() {
786
+ return this.$t('pui9.components.select.all-items-showed');
787
+ },
788
+ isDisabled() {
789
+ if (!this.isEmpty(this.newDisabled)) {
790
+ return this.newDisabled;
791
+ }
792
+ return this.disabled;
793
+ },
794
+ filterServerSide() {
795
+ if (this.items) {
796
+ return false;
797
+ }
798
+ return true;
799
+ },
800
+ getLabel() {
801
+ return this.allProps.label;
802
+ },
803
+ getLabelRequiredClass() {
804
+ return { 'v-label--required': this.required };
805
+ },
806
+ getEditedClass() {
807
+ const editedClass = { 'v-text-field--edited': this.isEdited };
808
+ if (this.attach) {
809
+ editedClass['puiselect-' + this.attach] = true;
810
+ }
811
+ return editedClass;
812
+ },
813
+ getPlaceholder() {
814
+ var placeholder = this.placeholder;
815
+ if (this.isMobile && this.placeholder === ' ') {
816
+ placeholder = this.label;
817
+ }
818
+ return placeholder;
819
+ },
820
+ prependInnerIconRead() {
821
+ if (this.detailModelName && this.detailComponentName && this.detailActions.read) {
822
+ const model = this.$store.getters.getModelByName(this.detailModelName);
823
+ if (model && model.functionalities) {
824
+ if (this.$store.getters.hasFunctionality(model.functionalities.get)) {
825
+ return 'far fa-info-circle';
826
+ }
827
+ }
828
+ }
829
+ return null;
830
+ },
831
+ prependInnerIconUpdate() {
832
+ if (this.detailModelName && !this.disabled && this.detailActions.update) {
833
+ const model = this.$store.getters.getModelByName(this.detailModelName);
834
+ if (model && model.functionalities) {
835
+ // eslint-disable-next-line
836
+ if (this.$store.getters.hasFunctionality(model.functionalities.update)) {
837
+ return 'far fa-edit';
838
+ }
839
+ }
840
+ }
841
+ return null;
842
+ },
843
+ prependInnerIconInsert() {
844
+ if (this.detailModelName && !this.disabled && this.detailActions.create) {
845
+ const model = this.$store.getters.getModelByName(this.detailModelName);
846
+ if (model && model.functionalities) {
847
+ // eslint-disable-next-line
848
+ if (this.$store.getters.hasFunctionality(model.functionalities.insert)) {
849
+ return 'far fa-plus-circle';
850
+ }
851
+ }
852
+ }
853
+ return null;
854
+ },
855
+ getRules() {
856
+ const rules = [...this.rules];
857
+ if (this.required) {
858
+ var func = (value) => !!value || this.requiredMessage;
859
+ var func2 = () => !this.internalError || (Array.isArray(this.internalErrorMessages) && this.internalErrorMessages.length > 0);
860
+ var func3 = () => {
861
+ if (this.isEmpty(this.selectedItems)) {
862
+ return this.requiredMessage;
863
+ }
864
+ return true;
865
+ };
866
+ rules.push(func, func2, func3);
867
+ }
868
+ return rules;
869
+ },
870
+ isEdited() {
871
+ if (this.noeditable || this.disabled || this.readonly || this.selected === false) {
872
+ return false;
873
+ } else {
874
+ return this.compareInitialWithCurrentSelected();
875
+ }
876
+ },
877
+ isMenuOpened() {
878
+ return this.$refs.arrowUp ? this.$refs.arrowUp.isMenuActive || this.$refs.arrowUp.isFocused : false;
879
+ }
880
+ },
881
+ methods: {
882
+ setDropDownDirection() {
883
+ if (this.$refs.arrowUp && this.attach) {
884
+ setTimeout(() => {
885
+ const puiSelect = this.$refs.arrowUp.$el;
886
+ const dropDown = puiSelect.querySelector('.v-menu__content');
887
+ const puiSelectPositions = puiSelect.getBoundingClientRect();
888
+ const heightBrowser = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
889
+ const screenAvailableForDropDown = heightBrowser - puiSelectPositions.top;
890
+ if (screenAvailableForDropDown < parseInt(dropDown.style['max-height']?.replace('px', '')) + 10) {
891
+ dropDown.style.top = 'initial';
892
+ dropDown.style.bottom = '40px';
893
+ } else {
894
+ dropDown.style.bottom = 'initial';
895
+ dropDown.style.top = '40px';
896
+ }
897
+ }, 0);
898
+ }
899
+ },
900
+ focusValue() {
901
+ //antes estaba así pero resultaba en un bug, se cambia a como esta dos lineas abajo. Si tenia explicación que se comente ya que generaba un bug
902
+ //(this.theItems.length === this.initialItemsToSelect.length || !this.theItems.length) && this[`getItems${this.getItemsFrom}`]();
903
+ this.hasBeenFocused === false && this[`getItems${this.getItemsFrom}`]();
904
+ //never more to load on focus
905
+ this.hasBeenFocused = true;
906
+ this.$refs.arrowUp.isMenuActive = true;
907
+ this.setDropDownDirection();
908
+ },
909
+ menuArrow() {
910
+ const arrowEl = this.$refs.arrowUp;
911
+ if (arrowEl.isMenuActive) {
912
+ arrowEl.isMenuActive = false;
913
+ arrowEl.blur();
914
+ } else {
915
+ arrowEl.isFocused = true;
916
+ this.focusValue();
917
+ }
918
+ },
919
+ compareInitialWithCurrentSelected() {
920
+ if (this.multiple) {
921
+ //comprobamos existencias, luego dimensiones y por último contenido de los arrays
922
+ if (!this.initialItemsToSelect || this.selectedItems.length === 0) {
923
+ if (this.initialItemsToSelect) {
924
+ return true;
925
+ } else if (this.selectedItems.length > 0) {
926
+ return true;
927
+ }
928
+ //los dos estan vacios
929
+ return false;
930
+ }
931
+ if (!this.isEmpty(this.itemValue)) {
932
+ if (this.initialItemsToSelect.length !== this.selectedItems.length) {
933
+ return true;
934
+ } else if (this.itemValueNested === true) {
935
+ //TODO
936
+ } else if (this.itemValueMultiple === true) {
937
+ for (let index = 0, length = this.initialItemsToSelect.length; index < length; index++) {
938
+ const item = this.initialItemsToSelect[index];
939
+ const selectedItem = this.selectedItems[index];
940
+ for (let i = 0, length = this.itemValue.length; i < length; i++) {
941
+ const pkProp = this.itemValue[i];
942
+ if (item[pkProp] !== selectedItem[pkProp]) {
943
+ return true;
944
+ }
945
+ }
946
+ }
947
+ } else {
948
+ for (let i = 0, length = this.initialItemsToSelect.length; i < length; i++) {
949
+ if (this.initialItemsToSelect[i][this.itemValue] !== this.selectedItems[i][this.itemValue]) {
950
+ return true;
951
+ }
952
+ }
953
+ }
954
+ return false;
955
+ } else {
956
+ for (let i = 0, length = this.initialItemsToSelect.length; i < length; i++) {
957
+ if (this.initialItemsToSelect[i] !== this.selectedItems[i]) {
958
+ return true;
959
+ }
960
+ }
961
+ }
962
+ return false;
963
+ } else {
964
+ //comprobamos existencias y por último contenido de los objetos
965
+ if (this.isEmpty(this.initialItemsToSelect) || this.isEmpty(this.selectedItems)) {
966
+ if (this.initialItemsToSelect && this.initialItemsToSelect.length > 0) {
967
+ if (this.itemValueMultiple === true) {
968
+ return !this.isEmpty(this.initialItemsToSelect[this.itemValue[0]]);
969
+ } else {
970
+ return !this.isEmpty(this.initialItemsToSelect[this.itemValue]);
971
+ }
972
+ } else if (!this.isEmpty(this.selectedItems)) {
973
+ return true;
974
+ }
975
+ //los dos estan vacios
976
+ return false;
977
+ }
978
+ if (!this.isEmpty(this.itemValue)) {
979
+ if (this.itemValueMultiple === true) {
980
+ for (let i = 0, length = this.itemValue.length; i < length; i++) {
981
+ if (this.selectedItems[this.itemValue[i]] !== this.initialItemsToSelect[0][this.itemValue[i]]) {
982
+ return true;
983
+ }
984
+ }
985
+ return false;
986
+ } else if (this.itemValueNested === true) {
987
+ //TODO
988
+ }
989
+ return this.initialItemsToSelect[0][this.itemValue] !== this.selectedItems[this.itemValue];
990
+ }
991
+ return this.initialItemsToSelect[0] !== this.selectedItems;
992
+ }
993
+ },
994
+ checkValue() {
995
+ this.clearMessages();
996
+ if (this.required) {
997
+ if (this.isEmpty(this.selectedItems)) {
998
+ this.showErrorMessage();
999
+ }
1000
+ }
1001
+ },
1002
+ clearMessages() {
1003
+ this.internalError = false;
1004
+ this.internalErrorMessages = [];
1005
+ },
1006
+ showErrorMessage() {
1007
+ this.internalError = true;
1008
+ this.internalErrorMessages = [this.requiredMessage];
1009
+ },
1010
+ filterItems(search) {
1011
+ if (this.modelName) {
1012
+ clearTimeout(this.delayTimer);
1013
+ this.delayTimer = setTimeout(() => {
1014
+ this.getItemsFromPuiList(search);
1015
+ }, 500);
1016
+ }
1017
+ },
1018
+ insertItem() {
1019
+ //alert('TODO');
1020
+ },
1021
+ disableInput() {
1022
+ this.$el.children[0].children[0].children[0].children[0].children[0].children[1].setAttribute('disabled', '');
1023
+ this.disabledInput = true;
1024
+ },
1025
+ clearItems() {
1026
+ this.selectedItems = [];
1027
+ },
1028
+ selectItemById(id) {
1029
+ var itemValueTemp = this.itemValue;
1030
+ var selectedItem;
1031
+ for (let index = 0, length = this.theItems.length; index < length; index++) {
1032
+ var item = this.theItems[index];
1033
+ if (this.itemValueMultiple === true) {
1034
+ let allPropsEqual = false;
1035
+ for (let i = 0, length = this.itemValue.length; i < length; i++) {
1036
+ if (item[this.itemValue[i]] !== id[this.itemValue[i]]) {
1037
+ allPropsEqual = true;
1038
+ break;
1039
+ }
1040
+ }
1041
+ if (allPropsEqual === true) {
1042
+ continue;
1043
+ }
1044
+ selectedItem = this.return_object ? item : id;
1045
+ if (this.multiple === false) {
1046
+ this.selectedItems = selectedItem;
1047
+ } else {
1048
+ this.selectedItems.push(selectedItem);
1049
+ }
1050
+ //eslint-disable-next-line no-useless-return
1051
+ return;
1052
+ } else if (item[itemValueTemp] === id) {
1053
+ selectedItem = this.return_object ? item : id;
1054
+ if (this.multiple === false) {
1055
+ this.selectedItems = selectedItem;
1056
+ } else {
1057
+ this.selectedItems.push(selectedItem);
1058
+ }
1059
+ //eslint-disable-next-line no-useless-return
1060
+ return;
1061
+ } else if (item === id) {
1062
+ this.selectedItems = item;
1063
+ return;
1064
+ }
1065
+ }
1066
+ },
1067
+ goToDetail(method) {
1068
+ if (!this.isEmpty(this.selectedItems)) {
1069
+ const detailPk = {};
1070
+ let itemValues = this.itemValue;
1071
+ if (this.itemValueMultiple === false) {
1072
+ itemValues = [this.itemValue];
1073
+ }
1074
+ itemValues.forEach((pkProperty) => {
1075
+ if (!this.isEmpty(this.selectedItems[pkProperty])) {
1076
+ detailPk[pkProperty] = this.selectedItems[pkProperty];
1077
+ }
1078
+ });
1079
+
1080
+ this.detailComponentMethod = method;
1081
+ this.detailComponentLabel = this.label;
1082
+ this.detailComponentPk = this.$puiUtils.utf8ToB64(JSON.stringify(detailPk));
1083
+ this.showDetailComponent = true;
1084
+ } else if (method === 'create') {
1085
+ this.detailComponentMethod = method;
1086
+ this.detailComponentLabel = this.label;
1087
+ this.detailComponentPk = 'new';
1088
+ this.showDetailComponent = true;
1089
+ }
1090
+ },
1091
+ subscribeEvents() {
1092
+ this.$puiEvents.$on(`onPuiSelect_${this.puiSelectId}`, (newVal) => {
1093
+ this.itemsToSelect[0] = newVal;
1094
+ this.onPuiSelectItemsToSelect = [newVal];
1095
+ this.getSelectedItemsFromPuiList();
1096
+ });
1097
+ },
1098
+ unsubscribeEvents() {
1099
+ this.$puiEvents.$off(`onPuiSelect_${this.puiSelectId}`);
1100
+ this.$puiEvents.$off(`pui-modalDialog-${this.detailComponentName}_${this.puiSelectId}_popup-hide`);
1101
+ },
1102
+ replaceMapping() {
1103
+ let itemValues = this.itemValue;
1104
+ if (this.itemValueMultiple === false) {
1105
+ itemValues = [this.itemValue];
1106
+ }
1107
+ if (this.multiple !== true) {
1108
+ itemValues.forEach((pkValue) => {
1109
+ if (this.isEmpty(this.selectedItems)) {
1110
+ if (this.filterId && this.filterMap) {
1111
+ let isParentPkValue = false;
1112
+ for (const property in this.filterMap) {
1113
+ if (property === pkValue) {
1114
+ isParentPkValue = true;
1115
+ break;
1116
+ }
1117
+ }
1118
+ if (!isParentPkValue) {
1119
+ this.value[this.modelFormMapping[pkValue]] = null;
1120
+ }
1121
+ } else {
1122
+ this.value[this.modelFormMapping[pkValue]] = null;
1123
+ }
1124
+ return;
1125
+ }
1126
+ this.value[this.modelFormMapping[pkValue]] = this.selectedItems[pkValue];
1127
+ for (const property in this.selectedItems) {
1128
+ if (pkValue === property && !Object.prototype.hasOwnProperty.call(this.value, property)) {
1129
+ this.value[property] = this.selectedItems[property];
1130
+ }
1131
+ }
1132
+ if (this.filterId && this.filterMap && !this.firstLoad && !this.selectedItemsEventFirstLoad) {
1133
+ this.sendDataToParent();
1134
+ }
1135
+ });
1136
+ } else {
1137
+ this.selectedItems.forEach((item, index) => {
1138
+ itemValues.forEach((pkValue) => {
1139
+ this.value[index][this.modelFormMapping[pkValue]] = item[pkValue];
1140
+ for (var property in this.selectedItems[index]) {
1141
+ if (pkValue === property && !Object.prototype.hasOwnProperty.call(this.value[index], property)) {
1142
+ this.value[index][property] = this.selectedItems[index][property];
1143
+ }
1144
+ }
1145
+ });
1146
+ });
1147
+ }
1148
+ return this.value;
1149
+ },
1150
+ sendDataToParent() {
1151
+ const selectedObject = {};
1152
+ for (const property in this.filterMap) {
1153
+ let parentProperty = property;
1154
+ if (this.filterParentMap && !this.isEmpty(this.filterParentMap[property])) {
1155
+ parentProperty = this.filterParentMap[property];
1156
+ }
1157
+ selectedObject[parentProperty] = this.selectedItems[property];
1158
+ }
1159
+ this.$puiEvents.$emit(`onPuiSelect_${this.filterId}`, selectedObject);
1160
+ },
1161
+ /**
1162
+ * Metodo llamado por el componente infinteloading al hacer scroll, nadie más lo llama directamente
1163
+ */
1164
+ getMoreItemsFromPuiList(search) {
1165
+ this.loading = true;
1166
+ this.page++;
1167
+ const bodyRequest = this.getBodyRequest(search);
1168
+ const loadMoreItems = (response) => {
1169
+ if (response && response.data) {
1170
+ //this.processItems(response.data.data);
1171
+ this.theItems = this.theItems.concat(response.data.data);
1172
+ this.$refs.infiniteLoading.stateChanger.loaded();
1173
+ if (response.data.totalPages <= this.page) {
1174
+ this.$refs.infiniteLoading.stateChanger.complete();
1175
+ }
1176
+ }
1177
+ this.loading = false;
1178
+ };
1179
+ this.postRequest(bodyRequest, loadMoreItems);
1180
+ },
1181
+ getItemsFromService() {
1182
+ // de momento por implementar
1183
+ },
1184
+ getItemsFromPuiList(search) {
1185
+ this.page = 1;
1186
+ this.loading = true;
1187
+ const loadItems = (response) => {
1188
+ this.$refs.infiniteLoading && this.$refs.infiniteLoading.stateChanger.reset();
1189
+ if (response && response.data) {
1190
+ this.theItems = response.data.data;
1191
+ //this.processItems(this.theItems);
1192
+ if (this.selected === false) {
1193
+ this.selectItems();
1194
+ } else {
1195
+ this.checkSelectedItems();
1196
+ }
1197
+ this.$refs.infiniteLoading && this.$refs.infiniteLoading.stateChanger.loaded();
1198
+ }
1199
+ if (response.data.totalPages <= this.page) {
1200
+ this.$refs.infiniteLoading && this.$refs.infiniteLoading.stateChanger.complete();
1201
+ }
1202
+ this.loading = false;
1203
+ };
1204
+ const bodyRequest = this.getBodyRequest(search);
1205
+ this.postRequest(bodyRequest, loadItems);
1206
+ },
1207
+ getItems() {
1208
+ if (this.items) {
1209
+ this.theItems = this.items;
1210
+ }
1211
+ this.loading = false;
1212
+ //this.processItems(this.theItems);
1213
+ this.selectItems();
1214
+ },
1215
+ postRequest(body, successCallback) {
1216
+ this.$puiRequests.postRequest(this.internalController, body, successCallback, (error) => {
1217
+ console.log(error);
1218
+ });
1219
+ },
1220
+ getBodyRequest(search) {
1221
+ let paginateItemsParams = {
1222
+ model: this.modelName,
1223
+ filter: this.createFilter()
1224
+ };
1225
+ if (this.isMultiSelect === false) {
1226
+ paginateItemsParams.rows = this.rows;
1227
+ paginateItemsParams.page = this.page;
1228
+ paginateItemsParams.queryText = search;
1229
+ paginateItemsParams.queryFields = this.internalQueryFields;
1230
+ } else {
1231
+ paginateItemsParams.rows = this.rowNum;
1232
+ }
1233
+ const searchOrder = this.createOrder();
1234
+ if (searchOrder) {
1235
+ paginateItemsParams.order = searchOrder;
1236
+ }
1237
+ return paginateItemsParams;
1238
+ },
1239
+ createFilter() {
1240
+ let theFilter = this.pui9filter;
1241
+
1242
+ if (this.filterMap) {
1243
+ const group = this.createRelatedComboFilterGroup();
1244
+ if (group && group.rules && group.rules.length > 0) {
1245
+ if (theFilter) {
1246
+ theFilter.groups.push(group);
1247
+ } else {
1248
+ theFilter = group;
1249
+ }
1250
+ }
1251
+ }
1252
+
1253
+ if (this.fixedFilter && !this.isDisabled) {
1254
+ if (theFilter) {
1255
+ theFilter.groups.push(this.fixedFilter);
1256
+ } else {
1257
+ theFilter = this.fixedFilter;
1258
+ }
1259
+ }
1260
+
1261
+ return theFilter;
1262
+ },
1263
+ createRelatedComboFilterGroup() {
1264
+ const group = {
1265
+ groupOp: this.filterMapOp ? this.filterMapOp.toLowerCase() : 'and',
1266
+ rules: [],
1267
+ groups: []
1268
+ };
1269
+
1270
+ if (this.multiple !== true) {
1271
+ for (const colmodel in this.filterMap) {
1272
+ const value = this.filterMap[colmodel];
1273
+ if (Object.prototype.hasOwnProperty.call(this.filterMap, colmodel) && !this.isEmpty(value)) {
1274
+ group.rules.push({
1275
+ field: colmodel,
1276
+ op: 'eq',
1277
+ data: value
1278
+ });
1279
+ }
1280
+ }
1281
+ } else {
1282
+ // TODO: multiple with filter...
1283
+ }
1284
+
1285
+ return group;
1286
+ },
1287
+ createOrder() {
1288
+ if (!this.order) {
1289
+ return null;
1290
+ }
1291
+ const searchOrder = [];
1292
+ for (const column in this.order) {
1293
+ const direction = this.order[column];
1294
+ searchOrder.push({ column: column, direction: direction });
1295
+ }
1296
+
1297
+ return searchOrder;
1298
+ },
1299
+ checkForNestedFields(stringField) {
1300
+ if (stringField instanceof Function) {
1301
+ return false;
1302
+ }
1303
+
1304
+ return stringField.split('.').length > 1;
1305
+ },
1306
+ checkItemText() {
1307
+ this.itemTextMultiple = Array.isArray(this.itemText);
1308
+ if (this.itemTextMultiple === false) {
1309
+ this.itemTextNested = this.checkForNestedFields(this.itemText);
1310
+ }
1311
+ },
1312
+ checkItemValue() {
1313
+ this.itemValueMultiple = Array.isArray(this.itemValue);
1314
+ if (this.itemValueMultiple === false) {
1315
+ this.itemValueNested = this.checkForNestedFields(this.itemValue);
1316
+ }
1317
+ },
1318
+ getSelectedItems() {
1319
+ for (let i = 0, length = this.itemsToSelect.length; i < length; i++) {
1320
+ this.selectItemById(this.itemsToSelect[i][this.itemValue] || this.itemsToSelect[i], this.itemsToSelect[i]);
1321
+ }
1322
+ this.checkSelectedItems();
1323
+ if (!this.isEmpty(this.modelFormMapping, this.selectedItems)) {
1324
+ this.replaceMapping();
1325
+ }
1326
+ },
1327
+ getFilterRequest(itemsToSelect) {
1328
+ const filter = {
1329
+ groupOp: 'and',
1330
+ rules: [],
1331
+ groups: []
1332
+ };
1333
+ const itemValues = this.itemValueMultiple === false ? [this.itemValue] : this.itemValue;
1334
+ const itemsToSelectToSearch = itemsToSelect || this.itemsToSelect;
1335
+ itemsToSelectToSearch.forEach((item) => {
1336
+ itemValues.forEach((pkProperty) => {
1337
+ if (!this.isEmpty(item[pkProperty])) {
1338
+ filter.rules.push({ field: pkProperty, op: 'eq', data: item[pkProperty] });
1339
+ }
1340
+ });
1341
+ });
1342
+
1343
+ if (this.filterMap) {
1344
+ const group = this.createRelatedComboFilterGroup();
1345
+ if (group && group.rules && group.rules.length > 0) {
1346
+ filter.groups.push(group);
1347
+ }
1348
+ }
1349
+
1350
+ if (this.fixedFilter && !this.isDisabled) {
1351
+ filter.groups.push(this.fixedFilter);
1352
+ }
1353
+ return filter;
1354
+ },
1355
+ getSelectedItemsFromPuiList() {
1356
+ const filter = this.getFilterRequest();
1357
+ if (this.isEmpty(filter.rules) && this.isEmpty(filter.groups)) {
1358
+ if (this.firstLoad) this.firstLoad = false;
1359
+ return;
1360
+ }
1361
+
1362
+ const data = {
1363
+ model: this.modelName,
1364
+ queryFields: this.internalQueryFields,
1365
+ filter
1366
+ };
1367
+
1368
+ const searchOrder = this.createOrder();
1369
+ if (searchOrder) {
1370
+ data.order = searchOrder;
1371
+ }
1372
+
1373
+ const itemsToSelectOldValue = JSON.stringify(this.itemsToSelect);
1374
+
1375
+ let promise = new Promise((resolve) => {
1376
+ this.$puiRequests.postRequest(this.internalController, data, (response) => {
1377
+ if (response && response.data) {
1378
+ if (this.multiple === false) {
1379
+ const itemsToSelectHaveValue = this.haveItemsToSelectValue();
1380
+ if (itemsToSelectHaveValue) {
1381
+ const itemsToSelectNewValue = JSON.stringify(this.itemsToSelect);
1382
+ if (itemsToSelectNewValue != itemsToSelectOldValue && this.firstLoad) {
1383
+ this.theItems = response.data.data;
1384
+ this.selectItem(this.itemsToSelect);
1385
+ } else {
1386
+ this.selectedItems = response.data.data[0];
1387
+ }
1388
+ } else {
1389
+ this.selectedItems = this.multiple ? [] : null;
1390
+ }
1391
+ } else {
1392
+ this.selectedItems = response.data.data;
1393
+ }
1394
+ this.checkSelectedItems();
1395
+ resolve(response.data.data);
1396
+ if (this.firstLoad) this.firstLoad = false;
1397
+ }
1398
+ });
1399
+ });
1400
+
1401
+ if (!this.firstLoad) {
1402
+ this.requestDataPromise = promise;
1403
+ }
1404
+ },
1405
+ haveItemsToSelectValue() {
1406
+ const itemValues = this.itemValueMultiple === false ? [this.itemValue] : this.itemValue;
1407
+ let itemsToSelectHasValue = true;
1408
+ this.itemsToSelect.forEach((item) => {
1409
+ itemValues.forEach((pkProperty) => {
1410
+ if (this.isEmpty(item[pkProperty])) {
1411
+ itemsToSelectHasValue = false;
1412
+ }
1413
+ });
1414
+ });
1415
+ if (!itemsToSelectHasValue && this.onPuiSelectItemsToSelect) {
1416
+ itemsToSelectHasValue = true;
1417
+ this.onPuiSelectItemsToSelect.forEach((item) => {
1418
+ itemValues.forEach((pkProperty) => {
1419
+ if (this.isEmpty(item[pkProperty])) {
1420
+ itemsToSelectHasValue = false;
1421
+ }
1422
+ });
1423
+ });
1424
+ this.onPuiSelectItemsToSelect = null;
1425
+ }
1426
+ return itemsToSelectHasValue;
1427
+ },
1428
+ selectItems() {
1429
+ this.selectedItems = this.multiple ? [] : null;
1430
+ if (this.multiple === true || this.isMultiSelect) {
1431
+ this.selectedItems = [];
1432
+ }
1433
+
1434
+ // only for multiselect
1435
+ this.setAvailableItems && this.setAvailableItems();
1436
+ if (this.isEmpty(this.itemsToSelect)) {
1437
+ return;
1438
+ }
1439
+ if (this.multiple === true) {
1440
+ this.getSelectedItems();
1441
+ } else {
1442
+ this[`getSelectedItems${this.getItemsFrom}`]();
1443
+ }
1444
+ this.selected = true;
1445
+ },
1446
+ /**
1447
+ * Este método se aplica en el componente pui-select y cuando hay un controlador de pui.
1448
+ *
1449
+ * Lo que hace es: como el listado de items cuando hay un controlador es paginado, puede ser que,
1450
+ * los items a seleccionar no se encuentren en la primera página de items.
1451
+ * Por esto comprueba que si no coincide itemsToSelect y selectedItems, y si no coinciden,
1452
+ * cargará los primeros a theItems y después seleccionará
1453
+ **/
1454
+ checkSelectedItems() {
1455
+ if (this.modelName && this.isMultiSelect === false) {
1456
+ if (this.multiple === false) {
1457
+ // si es la selección inicial y itemsToSelect no esta en theItems, por tanto no se ha seleccionado
1458
+ if (this.selected === false && !this.selectedItems && this.itemsToSelect && this.itemsToSelect.length > 0) {
1459
+ this.selectedItems = this.itemsToSelect[0];
1460
+ }
1461
+
1462
+ this.selectedItems && this.theItems.unshift(this.selectedItems);
1463
+ } else {
1464
+ // si no es la selección inicial, viene de una selección por un getItems de una búsqueda, ya no utilizamos itemsToSelect
1465
+ if (this.selected === true) {
1466
+ this.selectedItems.forEach((item) => {
1467
+ this.theItems.unshift(item);
1468
+ });
1469
+ // si es la selección inicial
1470
+ } else {
1471
+ if (this.selectedItems.length < this.itemsToSelect.length) {
1472
+ this.selectedItems = [];
1473
+ this.itemsToSelect.forEach((item) => {
1474
+ this.theItems.unshift(item);
1475
+ this.selectedItems.push(item);
1476
+ });
1477
+ }
1478
+ }
1479
+ }
1480
+ }
1481
+ },
1482
+ resetItems(newValue) {
1483
+ if (this.isEmpty(newValue)) {
1484
+ this.selectedItems = this.multiple ? [] : null;
1485
+ }
1486
+ if (this.isEmpty(this.selectedItems)) {
1487
+ return;
1488
+ }
1489
+ let filtersValid = true;
1490
+ for (var pkProperty in this.filterMap) {
1491
+ let parentPkProperty = pkProperty;
1492
+ if (this.filterParentMap && this.filterParentMap[pkProperty]) {
1493
+ parentPkProperty = this.filterParentMap[pkProperty];
1494
+ }
1495
+ if (
1496
+ !this.isEmpty(newValue[pkProperty]) &&
1497
+ newValue[pkProperty] !== this.selectedItems[pkProperty] &&
1498
+ !this.isEmpty(newValue[parentPkProperty]) &&
1499
+ newValue[parentPkProperty] !== this.selectedItems[pkProperty]
1500
+ ) {
1501
+ filtersValid = false;
1502
+ }
1503
+ }
1504
+ if (!filtersValid || !this.filterMap) this.selectedItems = this.multiple ? [] : null;
1505
+ },
1506
+ selectPreviousValidItems() {
1507
+ if (this.multiple === true) {
1508
+ this.selectedItems = [];
1509
+ this.previousSelectedItems.forEach((previousItem) => {
1510
+ const strPkPrevItem = JSON.stringify(this.getPkFromItem(previousItem));
1511
+ this.theItems.forEach((requestItem) => {
1512
+ const strPkRequestItem = JSON.stringify(this.getPkFromItem(requestItem));
1513
+ if (strPkPrevItem === strPkRequestItem) {
1514
+ this.selectedItems.push(previousItem);
1515
+ }
1516
+ });
1517
+ });
1518
+ } else {
1519
+ const strPkPrevItem = JSON.stringify(this.getPkFromItem(this.previousSelectedItems));
1520
+ this.theItems.forEach((requestItem) => {
1521
+ const strPkRequestItem = JSON.stringify(this.getPkFromItem(requestItem));
1522
+ if (strPkPrevItem === strPkRequestItem) {
1523
+ this.theItems.unshift(requestItem);
1524
+ this.selectedItems = requestItem;
1525
+ }
1526
+ });
1527
+ }
1528
+ },
1529
+ getPkFromItem(item) {
1530
+ const theItemPkFields = Array.isArray(this.itemValue) ? this.itemValue : [this.itemValue];
1531
+ const objectPk = {};
1532
+ theItemPkFields.forEach((pkField) => {
1533
+ objectPk[pkField] = item[pkField];
1534
+ });
1535
+ return objectPk;
1536
+ },
1537
+ selectItem(itemToSelect) {
1538
+ this.itemProgrammaticallySelected = true;
1539
+ const newSelected = this.theItems.find((element) => {
1540
+ for (const key in itemToSelect[0]) {
1541
+ if (Object.prototype.hasOwnProperty.call(itemToSelect[0], key)) {
1542
+ if (itemToSelect[0][key] !== element[key]) return false;
1543
+ }
1544
+ }
1545
+ return true;
1546
+ });
1547
+ const filter = this.getFilterRequest(itemToSelect);
1548
+ if (this.isEmpty(newSelected) && this.modelName && filter.rules.length > 0) {
1549
+ const params = {
1550
+ model: this.modelName,
1551
+ filter: filter
1552
+ };
1553
+ this.postRequest(params, (response) => {
1554
+ if (response && response.data && response.data.data.length > 0) {
1555
+ this.theItems = this.theItems.concat(this.multiple === true ? response.data.data : [response.data.data[0]]);
1556
+ this.selectedItems = this.multiple === true ? response.data.data : response.data.data[0];
1557
+ } else {
1558
+ this.selectedItems = undefined;
1559
+ }
1560
+ });
1561
+ } else {
1562
+ this.selectedItems = newSelected;
1563
+ }
1564
+ },
1565
+ reactiveHandler(newValue) {
1566
+ if (this.reactive) {
1567
+ if ((!this.itemManuallySelected || Object.values(newValue[0]).some((x) => !x)) && !this.firstLoad) {
1568
+ this.itemManuallySelected = false;
1569
+ this.selectItem(newValue);
1570
+ } else {
1571
+ if (this.requestDataPromise) {
1572
+ this.requestDataPromise.then((theItems) => {
1573
+ if (!this.itemManuallySelected) {
1574
+ this.theItems = theItems;
1575
+ this.selectItem(newValue);
1576
+ }
1577
+ delete this.requestDataPromise;
1578
+ });
1579
+ }
1580
+ this.itemManuallySelected = false;
1581
+ }
1582
+ }
1583
+ },
1584
+ isEmpty(...values) {
1585
+ return values.some(
1586
+ (value) =>
1587
+ value === undefined ||
1588
+ value === null ||
1589
+ (typeof value === 'string' && value.trim() === '') ||
1590
+ (Array.isArray(value) && value.length === 0)
1591
+ );
1592
+ }
1593
+ },
1594
+ created() {
1595
+ this.puiSelectId = this.$attrs.id;
1596
+ this.isMobile = this.$store.getters.isMobile;
1597
+ //TODO poner itemValues como un array si viene de string, para unificar simplificar donde haya comprobaciones itemValuesMultiple
1598
+ this.itemsToSelect.forEach((item) => {
1599
+ this.initialItemsToSelect.push(item);
1600
+ });
1601
+ this.checkItemText();
1602
+ this.checkItemValue();
1603
+ this.internalQueryFields = this.queryFields;
1604
+ if (this.modelName) {
1605
+ const theModel = this.$store.getters.getModelByName(this.modelName);
1606
+ this.internalController = this.controller || theModel.url.list;
1607
+ this.internalQueryFields = !this.isEmpty(this.queryFields) ? this.queryFields : theModel.columns?.map(c => c.name);
1608
+ }
1609
+ if (this.isMultiSelect) {
1610
+ this[`getItems${this.getItemsFrom}`]();
1611
+ } else {
1612
+ this.getItems();
1613
+ }
1614
+ this.subscribeEvents();
1615
+ },
1616
+ mounted() {
1617
+ if (this.detailComponentName) {
1618
+ const self = this;
1619
+ this.$puiEvents.$on(`pui-modalDialog-${this.detailComponentName}_${this.puiSelectId}_popup-hide`, (data) => {
1620
+ self.showDetailComponent = false;
1621
+ if (data) {
1622
+ const newItem = {};
1623
+ const itemValues = this.itemValue;
1624
+ itemValues.forEach((pkValue) => {
1625
+ newItem[pkValue] = data[pkValue];
1626
+ });
1627
+ self.itemsToSelect[0] = newItem;
1628
+ self.onPuiSelectItemsToSelect = [newItem];
1629
+ self.getSelectedItemsFromPuiList();
1630
+ }
1631
+ });
1632
+ }
1633
+ },
1634
+ beforeDestroy() {
1635
+ this.unsubscribeEvents();
1636
+ }
1637
+ };
1638
+ </script>