glib-web 4.41.1 → 4.42.1

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.
@@ -0,0 +1,24 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Read(//home/hgani/workspace/glib-web/app/views/json_ui/garage/**)",
5
+ "Read(//home/hgani/workspace/glib-web-npm/doc/garage/**)",
6
+ "Read(//home/hgani/workspace/glib-web-npm/doc/common/**)",
7
+ "Bash(find:*)",
8
+ "Bash(npx cypress run:*)",
9
+ "Read(//home/hgani/workspace/glib-web/**)",
10
+ "Bash(curl:*)",
11
+ "Bash(pkill:*)",
12
+ "Bash(gh pr list:*)",
13
+ "WebSearch",
14
+ "WebFetch(domain:vuetifyjs.com)",
15
+ "Bash(lsof:*)",
16
+ "Bash(readlink:*)",
17
+ "WebFetch(domain:github.com)",
18
+ "Bash(npm run dev)",
19
+ "Bash(npm run)"
20
+ ],
21
+ "deny": [],
22
+ "ask": []
23
+ }
24
+ }
@@ -1,6 +1,16 @@
1
1
  export default class {
2
2
  execute(properties, component) {
3
- const target = GLib.component.findById(properties.targetId) || component;
3
+ let target = component;
4
+
5
+ if (properties.targetId) {
6
+ target = GLib.component.findById(properties.targetId);
7
+
8
+ if (!target) {
9
+ console.warn("Component ID not found for form submission:", properties.targetId);
10
+ target = component;
11
+ }
12
+ }
13
+
4
14
  target.$dispatchEvent("forms/directSubmit", {
5
15
  url: properties.overrideUrl,
6
16
  method: properties.overrideMethod,
@@ -2,6 +2,7 @@ import jsonLogic from 'json-logic-js';
2
2
  import merge from 'lodash.merge';
3
3
  import { nextTick } from "vue";
4
4
  import { sanitize } from "../../components/composable/date";
5
+ import { htmlElement } from "../../components/helper";
5
6
  import { isPresent } from "../../utils/type";
6
7
  import { getFormData as _getFormData } from "../../components/composable/form";
7
8
 
@@ -94,6 +95,16 @@ export default class {
94
95
  if (!targetComponent) {
95
96
  console.warn("Component ID not found", id);
96
97
  }
98
+ Utils.type.ifObject(targetComponent, (component) => {
99
+ const element = htmlElement(component);
100
+ Utils.type.ifObject(element, (el) => {
101
+ Utils.type.ifFunction(el.closest, () => {
102
+ if (!el.closest('form')) {
103
+ console.warn("Target component is not inside a form", component.viewId || id);
104
+ }
105
+ });
106
+ });
107
+ });
97
108
  return targetComponent;
98
109
  }).filter((comp) => comp);
99
110
 
@@ -1,7 +1,9 @@
1
1
  import { Chart, Colors } from "chart.js";
2
2
  import chartDataLabels from 'chartjs-plugin-datalabels';
3
3
  import doughnutLabel from 'chartjs-plugin-doughnutlabel-v3';
4
- import { settings, Vue, vueApp } from "../..";
4
+ import { settings } from "../../utils/settings";
5
+ import { vueApp } from "../../store";
6
+ import * as TypeUtils from "../../utils/type";
5
7
  import { computePosition, flip, offset } from '@floating-ui/dom';
6
8
 
7
9
  import 'chartkick/chart.js';
@@ -15,8 +17,18 @@ Chart.register(Colors);
15
17
  if (settings.chartPlugin.htmlLegendPlugin) Chart.register(settings.chartPlugin.htmlLegendPlugin);
16
18
 
17
19
  import VueChartkick from 'vue-chartkick';
18
- import { computed } from "vue";
19
- Vue.use(VueChartkick);
20
+ import { computed, getCurrentInstance } from "vue";
21
+
22
+ let chartkickInstalled = false;
23
+ const installChartkick = () => {
24
+ if (chartkickInstalled) return;
25
+ const instance = getCurrentInstance();
26
+ const app = instance?.appContext?.app;
27
+ if (TypeUtils.isObject(app) && TypeUtils.isFunction(app.use)) {
28
+ app.use(VueChartkick);
29
+ chartkickInstalled = true;
30
+ }
31
+ };
20
32
 
21
33
  const multipleDataSeries = (dataSeries) => {
22
34
  return dataSeries.map((value) => {
@@ -110,6 +122,7 @@ const getData = (multiple, dataSeries, context) => {
110
122
  };
111
123
 
112
124
  function useChart({ dataSeries, spec, multiple = true }) {
125
+ installChartkick();
113
126
  const isDonut = [spec.styleClasses].flat().includes('donut');
114
127
  const { datalabels, centerLabel, customTooltip } = spec.plugins || {};
115
128
  const legend = spec.legend || { display: true };
@@ -198,4 +211,4 @@ function useChart({ dataSeries, spec, multiple = true }) {
198
211
  }
199
212
 
200
213
 
201
- export { useChart };
214
+ export { useChart };
@@ -1,5 +1,6 @@
1
1
  import { getCurrentInstance, inject, nextTick, onBeforeUnmount, onBeforeUpdate, onMounted, provide, ref, watch } from "vue";
2
2
  import { closest, htmlElement } from "../helper";
3
+ import { isArray, isFunction } from "../../utils/type.js";
3
4
 
4
5
  const setBusy = (htmlElement, value) => {
5
6
  const event = new Event('forms/setBusy', { bubbles: true });
@@ -13,6 +14,33 @@ const triggerOnChange = (htmlElement) => {
13
14
 
14
15
  const triggerOnInput = (htmlElement) => nextTick(() => htmlElement.dispatchEvent(new Event('input', { bubbles: true })));
15
16
 
17
+ const getCheckboxNames = (el) => {
18
+ const checkboxNames = new Set();
19
+ const nonCheckboxNames = new Set();
20
+ if (!el || !isFunction(el.querySelectorAll)) return checkboxNames;
21
+
22
+ el.querySelectorAll('[name]').forEach((input) => {
23
+ const name = input.name;
24
+ if (input instanceof HTMLInputElement && input.type === 'checkbox') {
25
+ if (!nonCheckboxNames.has(name)) checkboxNames.add(name);
26
+ return;
27
+ }
28
+ nonCheckboxNames.add(name);
29
+ checkboxNames.delete(name);
30
+ });
31
+
32
+ return checkboxNames;
33
+ };
34
+
35
+ const warnDuplicateNames = (key, seenNames, warnedNames, checkboxNames) => {
36
+ if (seenNames.has(key) && !warnedNames.has(key) && !checkboxNames.has(key)) {
37
+ console.warn(`Multiple inputs share the same name: "${key}".`);
38
+ warnedNames.add(key);
39
+ return;
40
+ }
41
+ seenNames.add(key);
42
+ };
43
+
16
44
  const getFormData = (el, ignoredFields = new Set()) => {
17
45
  if (!el) return {};
18
46
  if (!(el instanceof HTMLFormElement) && el instanceof HTMLElement) {
@@ -21,7 +49,11 @@ const getFormData = (el, ignoredFields = new Set()) => {
21
49
 
22
50
  const formData = new FormData(el);
23
51
  const obj = {};
52
+ const seenNames = new Set();
53
+ const warnedNames = new Set();
54
+ const checkboxNames = getCheckboxNames(el);
24
55
  formData.forEach((value, key) => {
56
+ warnDuplicateNames(key, seenNames, warnedNames, checkboxNames);
25
57
  if (ignoredFields.has(key)) return;
26
58
 
27
59
  // Reflect.has in favor of: object.hasOwnProperty(key)
@@ -29,7 +61,7 @@ const getFormData = (el, ignoredFields = new Set()) => {
29
61
  obj[key] = value;
30
62
  return;
31
63
  }
32
- if (!Array.isArray(obj[key])) {
64
+ if (!isArray(obj[key])) {
33
65
  obj[key] = [obj[key]];
34
66
  }
35
67
  obj[key].push(value);
@@ -118,4 +150,4 @@ function useGlibInput({ props, cacheValue = true }) {
118
150
 
119
151
  }
120
152
 
121
- export { setBusy, triggerOnChange, triggerOnInput, useGlibForm, useGlibInput, getFormData, getAllFormData };
153
+ export { setBusy, triggerOnChange, triggerOnInput, useGlibForm, useGlibInput, getFormData, getAllFormData };
@@ -1,11 +1,11 @@
1
1
  <template>
2
- <div ref="container" :style="$styles()" :class="$classes()" v-if="loadIf">
2
+ <div ref="container" :style="$styles()" :class="$classes()" v-if="loadIf" class="fields-select-wrapper">
3
3
  <!-- Set `menu-props` so the menu will never be wider than the select field.
4
4
  See https://github.com/vuetifyjs/vuetify/issues/17751 -->
5
5
  <component ref="comp" :is="compName" :color="gcolor" v-model="fieldModel" :label="label" :items="normalizedOptions"
6
- :chips="useChips" :disabled="inputDisabled" :multiple="spec.multiple" :readonly="spec.readOnly"
6
+ :disabled="inputDisabled" :multiple="spec.multiple" :readonly="spec.readOnly"
7
7
  :clearable="spec.clearable" :placeholder="spec.placeholder" :rules="$validation()" persistent-hint
8
- :append-icon="append.icon" validate-on="blur" item-title='text' :variant="variant" :closable-chips="spec.multiple"
8
+ :append-icon="append.icon" validate-on="blur" item-title='text' :variant="variant"
9
9
  :density="density" persistent-placeholder @update:modelValue="onChange" @focus="focused = true"
10
10
  @blur="focused = false" :menu-props="{ maxWidth: 0 }">
11
11
 
@@ -23,7 +23,7 @@
23
23
  <select-item-default v-else :context="props" :item="item" :spec="spec"></select-item-default>
24
24
  </div>
25
25
  </template>
26
-
26
+
27
27
  <template v-slot:prepend-item>
28
28
  <template v-if="spec.prependSelectAll">
29
29
  <v-list-item title="Select All" @click="checkAll">
@@ -39,6 +39,41 @@
39
39
  <common-responsive v-if="spec.header" :spec="spec.header" />
40
40
  </template>
41
41
 
42
+ <template v-if="useChips" #selection="{ item, index }">
43
+ <v-chip
44
+ v-if="index < maxVisibleChips"
45
+ :density="density"
46
+ closable
47
+ @click:close="removeItem(item)"
48
+ >
49
+ <span>{{ item.title }}</span>
50
+ </v-chip>
51
+ <v-chip
52
+ v-if="!expanded && chipExceedsTwoLines && visibleChipCount < fieldModel.length && index === visibleChipCount"
53
+ :density="density"
54
+ clickable
55
+ @click="expanded = true"
56
+ class="text-caption expansion-chip"
57
+ variant="outlined"
58
+ color="primary"
59
+ >
60
+ {{ fieldModel.length - visibleChipCount }} more
61
+ <common-icon :spec="{ material: { name: 'expand_more' } }" class="ml-1" />
62
+ </v-chip>
63
+ <v-chip
64
+ v-if="expanded && chipExceedsTwoLines && index === fieldModel.length - 1"
65
+ :density="density"
66
+ clickable
67
+ @click="collapseChips"
68
+ class="text-caption expansion-chip"
69
+ variant="outlined"
70
+ color="primary"
71
+ >
72
+ Show less
73
+ <common-icon :spec="{ material: { name: 'expand_less' } }" class="ml-1" />
74
+ </v-chip>
75
+ </template>
76
+
42
77
  <template v-slot:append-item v-if="spec.footer">
43
78
  <common-responsive :spec="footer" />
44
79
  </template>
@@ -59,10 +94,10 @@
59
94
  import inputVariant from '../mixins/inputVariant';
60
95
  import { determineDensity } from "../../utils/constant";
61
96
  import { triggerOnChange, triggerOnInput, useGlibInput } from "../composable/form";
62
- import { isBoolean } from '../../utils/type';
97
+ import { isBoolean, isArray } from '../../utils/type';
63
98
 
64
99
  import { useGlibSelectable, watchNoneOfAbove } from '../composable/selectable';
65
- import { ref, defineExpose } from 'vue';
100
+ import { ref, defineExpose, computed, watch, nextTick, onMounted, onUnmounted } from 'vue';
66
101
  import SelectItemDefault from "./_selectItemDefault.vue";
67
102
  import SelectItemWithImage from "./_selectItemWithImage.vue";
68
103
  import SelectItemWithIcon from "./_selectItemWithIcon.vue";
@@ -85,6 +120,166 @@ export default {
85
120
  const options = ref(props.spec.options);
86
121
  const comp = ref(null);
87
122
  const append = props.spec.append || {};
123
+ const expanded = ref(false);
124
+ const chipExceedsMaxLines = ref(false);
125
+ const visibleChipCount = ref(Infinity);
126
+
127
+ // Constants for chip line calculation
128
+ const DEFAULT_MAX_LINES = 2;
129
+ const DEFAULT_LINE_HEIGHT = 40;
130
+ const CHIP_GAP = 12; // Gap between chips + margins
131
+
132
+ // Computed property for determining how many chips to show
133
+ const maxVisibleChips = computed(() => {
134
+ if (!expanded.value) {
135
+ return visibleChipCount.value;
136
+ }
137
+ // When expanded, show all chips except reserve space for "Show less" if needed
138
+ return chipExceedsMaxLines.value ? fieldModel.value.length - 1 : fieldModel.value.length;
139
+ });
140
+
141
+ // Helper function to find the container that holds all chips
142
+ const findChipsContainer = (allChips) => {
143
+ if (allChips.length === 0) return null;
144
+
145
+ let container = allChips[0].parentElement;
146
+ // Walk up the DOM to find a container that has multiple chips
147
+ while (container && container.querySelectorAll('.v-chip').length <= 1) {
148
+ container = container.parentElement;
149
+ }
150
+ return container;
151
+ };
152
+
153
+ // Method to check if chips exceed max lines
154
+ const checkChipLines = (isResizeTriggered = false) => {
155
+ if (!comp.value) return;
156
+
157
+ // Get max lines config: 0 = no limit, null/undefined = default 2
158
+ const maxLines = props.spec.maxChipLines ?? DEFAULT_MAX_LINES;
159
+
160
+ // If maxLines is 0, don't limit chips at all
161
+ if (maxLines === 0) {
162
+ chipExceedsMaxLines.value = false;
163
+ visibleChipCount.value = Infinity;
164
+ return;
165
+ }
166
+
167
+ // Skip the measurement logic if this is a resize-triggered event and we're collapsed
168
+ // This prevents incorrect measurements when collapsed with fewer chips visible
169
+ if (isResizeTriggered && !expanded.value && chipExceedsMaxLines.value) {
170
+ return;
171
+ }
172
+
173
+ // Try different selectors to find the correct container
174
+ let selectionEl = comp.value.$el.querySelector('.v-select__selection, .v-autocomplete__selection');
175
+ if (!selectionEl) {
176
+ // Fallback: try to find the component root and look for chips there
177
+ selectionEl = comp.value.$el;
178
+ }
179
+
180
+ // Find all chips
181
+ const allChips = comp.value.$el.querySelectorAll('.v-chip');
182
+
183
+ // Early return if no chips
184
+ if (allChips.length === 0) {
185
+ chipExceedsMaxLines.value = false;
186
+ visibleChipCount.value = Infinity;
187
+ return;
188
+ }
189
+
190
+ // Find the common parent of all chips
191
+ const chipsContainer = findChipsContainer(allChips);
192
+
193
+ // Get the height of a single line dynamically from actual chip height
194
+ // This adapts to density settings, custom styles, and theme changes
195
+ const lineHeight = allChips[0].offsetHeight || DEFAULT_LINE_HEIGHT;
196
+ const currentHeight = chipsContainer ? chipsContainer.scrollHeight : selectionEl.scrollHeight;
197
+ const lines = Math.floor(currentHeight / lineHeight);
198
+
199
+ const exceedsMaxLines = lines > maxLines;
200
+
201
+ if (exceedsMaxLines) {
202
+ // Calculate how many chips fit in maxLines using line-by-line simulation
203
+ const chips = chipsContainer ? chipsContainer.querySelectorAll('.v-chip') : allChips;
204
+ const containerWidth = chipsContainer ? chipsContainer.offsetWidth : selectionEl.offsetWidth;
205
+
206
+ let currentLineWidth = 0;
207
+ let currentLine = 1;
208
+ let count = 0;
209
+
210
+ // Simulate actual chip wrapping line by line
211
+ for (const chip of chips) {
212
+ const chipWidth = chip.offsetWidth + CHIP_GAP;
213
+
214
+ // Check if chip fits on current line
215
+ if (currentLineWidth + chipWidth > containerWidth) {
216
+ // Move to next line
217
+ currentLine++;
218
+ currentLineWidth = chipWidth;
219
+
220
+ if (currentLine > maxLines) {
221
+ break; // Exceeded max lines
222
+ }
223
+ } else {
224
+ // Fits on current line
225
+ currentLineWidth += chipWidth;
226
+ }
227
+
228
+ count++;
229
+ }
230
+
231
+ // Only limit if we actually exceeded maxLines during simulation
232
+ if (currentLine > maxLines || count < chips.length) {
233
+ // Some chips didn't fit - reserve space for expansion chip
234
+ visibleChipCount.value = Math.max(1, count - 1);
235
+ chipExceedsMaxLines.value = true;
236
+ } else {
237
+ // All chips fit within maxLines - show them all!
238
+ visibleChipCount.value = Infinity;
239
+ chipExceedsMaxLines.value = false;
240
+ }
241
+ } else {
242
+ visibleChipCount.value = Infinity;
243
+ chipExceedsMaxLines.value = false;
244
+ }
245
+ };
246
+
247
+ // Watch for changes in model and expansion state
248
+ watch([fieldModel, expanded], () => {
249
+ nextTick(() => {
250
+ checkChipLines();
251
+ });
252
+ });
253
+
254
+ // Add resize observer to recalculate on window resize
255
+ onMounted(() => {
256
+ const resizeObserver = new ResizeObserver(() => {
257
+ // CRITICAL: Don't recalculate when collapsed
258
+ // The collapsed state has fewer chips visible, giving wrong measurements
259
+ // Only measure on resize when expanded (showing all chips)
260
+ if (!expanded.value && chipExceedsMaxLines.value) {
261
+ return; // Skip resize-triggered recalculation when collapsed
262
+ }
263
+ checkChipLines(true); // Pass true to indicate this is a resize-triggered calculation
264
+ });
265
+
266
+ const observeComponent = () => {
267
+ if (comp.value && comp.value.$el) {
268
+ resizeObserver.observe(comp.value.$el);
269
+ return true;
270
+ }
271
+ return false;
272
+ };
273
+
274
+ // Try to observe immediately, or wait a bit for component to mount
275
+ if (!observeComponent()) {
276
+ setTimeout(observeComponent, 100);
277
+ }
278
+
279
+ onUnmounted(() => {
280
+ resizeObserver.disconnect();
281
+ });
282
+ });
88
283
 
89
284
  const valueForDisableAll = props.spec.valueForDisableAll;
90
285
  const { checkAll, isAllSelected, isIndeterminate } = useGlibSelectable({ model: fieldModel, options: options, valueForDisableAll });
@@ -92,13 +287,41 @@ export default {
92
287
  watchNoneOfAbove({ model: fieldModel, options: options, valueForDisableAll });
93
288
  }
94
289
 
290
+ // Method to handle chip collapse
291
+ function collapseChips() {
292
+ expanded.value = false;
293
+ // IMPORTANT: Force recalculation with multiple nextTick calls to ensure DOM is fully updated
294
+ nextTick(() => {
295
+ checkChipLines(false);
296
+ // IMPORTANT: Second nextTick is necessary because DOM updates are asynchronous and
297
+ // the first measurement may occur before all chips are properly removed/added
298
+ // Do not remove this nested nextTick - it's required for correct functionality
299
+ nextTick(() => {
300
+ checkChipLines(false);
301
+ });
302
+ });
303
+ }
304
+
95
305
  // This is a public method that is called by other parts of the code, do not delete it.
96
306
  function toggle() {
97
307
  comp.value.menu = !comp.value.menu;
98
308
  }
99
309
  defineExpose(['toggle']);
100
310
 
101
- return { fieldModel, checkAll, isIndeterminate, isAllSelected, append, toggle, comp };
311
+ return {
312
+ fieldModel,
313
+ checkAll,
314
+ isIndeterminate,
315
+ isAllSelected,
316
+ append,
317
+ toggle,
318
+ comp,
319
+ expanded,
320
+ chipExceedsTwoLines: chipExceedsMaxLines,
321
+ visibleChipCount,
322
+ maxVisibleChips,
323
+ collapseChips
324
+ };
102
325
  },
103
326
  data() {
104
327
  return {
@@ -178,6 +401,20 @@ export default {
178
401
  triggerOnChange(containerEl);
179
402
  }
180
403
  },
404
+ removeItem(item) {
405
+ // fieldModel may not be an array when useChips is true but multiple is false.
406
+ // This can happen when spec.useChips is explicitly set to true while spec.multiple is false.
407
+ // In this scenario, fieldModel is a single value (not an array), so we need to handle both cases.
408
+ if (isArray(this.fieldModel)) {
409
+ const index = this.fieldModel.indexOf(item.value);
410
+ if (index >= 0) {
411
+ this.fieldModel.splice(index, 1);
412
+ }
413
+ } else {
414
+ // Single select mode - clear the value
415
+ this.fieldModel = null;
416
+ }
417
+ },
181
418
  $registryEnabled() {
182
419
  return false;
183
420
  }
@@ -212,4 +449,21 @@ export default {
212
449
  display: flex;
213
450
  align-items: center;
214
451
  }
452
+
453
+ .expansion-chip {
454
+ transition: all 0.2s ease-in-out;
455
+ box-sizing: content-box;
456
+ margin-left: 1px;
457
+
458
+ &:hover {
459
+ background-color: rgba(0, 0, 0, 0.04) !important;
460
+ transform: translateY(-1px);
461
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
462
+ }
463
+
464
+ &:active {
465
+ transform: translateY(0);
466
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
467
+ }
468
+ }
215
469
  </style>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :class="$classes()" :style="$styles()" v-if="loadIf" @click="$onClick()">
2
+ <div :class="$classes()" :style="$styles()" v-if="loadIf" @click="onClick($event)">
3
3
  <!-- This hidden field should always be there to make sure the submitted param is not empty,
4
4
  which could cause "Not accessible" error on the server. -->
5
5
  <input v-if="showUncheck" v-model="uncheckValue" type="hidden" :name="fieldName" />
@@ -70,6 +70,10 @@ export default {
70
70
  };
71
71
  },
72
72
  methods: {
73
+ onClick(event) {
74
+ event.stopPropagation(); // Prevent event bubbling to parent thumbnail
75
+ this.$onClick();
76
+ },
73
77
  _linkFieldModels(valueChanged) {
74
78
  if (!this.parentModel && valueChanged) {
75
79
  this.fieldModel = this.spec.value;
@@ -42,7 +42,7 @@ export default {
42
42
  // This regex follows the RFC 5321 standard for email validation,
43
43
  // with a slight improvement: it does not allow emails without a proper domain (e.g., "user@test" is invalid, must be "user@test.com").
44
44
  //https://stackoverflow.com/questions/13992403/regex-validation-of-email-addresses-according-to-rfc5321-rfc5322
45
- /^([!#-'*+\/-9=?A-Z^-~-]+(\.[!#-'*+\/-9=?A-Z^-~-]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([!#-'*+\/-9=?A-Z^-~-]+\.[!#-'*+\/-9=?A-Z^-~-]+|\[[\t -Z^-~]*])$/i.test(
45
+ /^([!#-'*+\/-9=?A-Z^-~-]+(\.[!#-'*+\/-9=?A-Z^-~-]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@([A-Z0-9-]+\.)+[A-Z]{2,}$/i.test(
46
46
  v
47
47
  ) ||
48
48
  "E-mail must be valid",
@@ -43,7 +43,7 @@ export default {
43
43
  Utils.type.ifObject(this.spec.validation, val => {
44
44
  Object.keys(val).forEach((key) => {
45
45
  const validator = ValidationFactory.getValidator(key, val[key]);
46
- augmentedRules = augmentedRules.concat([validator.build.bind(validator)]);
46
+ augmentedRules = [validator.build.bind(validator), ...augmentedRules];
47
47
  });
48
48
  });
49
49
  return augmentedRules;
@@ -22,7 +22,6 @@ export default {
22
22
  if (spec && spec.id && this.$registryEnabled()) {
23
23
 
24
24
  const id = this.viewId;
25
-
26
25
  const existingComponent = GLib.component.findById(id);
27
26
  // A component with the same ID in a different page shouldn't be considered a
28
27
  // duplicate. See `utils/components#deregister` for more details.
@@ -122,35 +122,30 @@ export default {
122
122
  },
123
123
  methods: {
124
124
  applyStyles(styles, spec) {
125
- if (spec.gap) {
126
- styles['column-gap'] = `${spec.gap.y}px`;
127
- styles['row-gap'] = `${spec.gap.x}px`;
128
- if (spec.gap.all) {
129
- styles['gap'] = `${spec.gap.all}px`;
130
- }
131
- }
132
-
133
- if (spec.padding) {
125
+ Utils.type.ifObject(spec.gap, gap => {
126
+ Utils.type.ifNumber(gap.all, all => (styles["gap"] = `${all}px`));
127
+ Utils.type.ifNumber(gap.x, x => (styles["column-gap"] = `${x}px`));
128
+ Utils.type.ifNumber(gap.y, y => (styles["row-gap"] = `${y}px`));
129
+ });
134
130
 
135
- Utils.type.ifObject(spec.padding, padding => {
136
- Utils.type.ifNumber(
137
- padding.top || padding.y || padding.all,
138
- top => (styles["padding-top"] = `${top}px`)
139
- );
140
- Utils.type.ifNumber(
141
- padding.bottom || padding.y || padding.all,
142
- bottom => (styles["padding-bottom"] = `${bottom}px`)
143
- );
144
- Utils.type.ifNumber(
145
- padding.left || padding.x || padding.all,
146
- left => (styles["padding-left"] = `${left}px`)
147
- );
148
- Utils.type.ifNumber(
149
- padding.right || padding.x || padding.all,
150
- right => (styles["padding-right"] = `${right}px`)
151
- );
152
- });
153
- }
131
+ Utils.type.ifObject(spec.padding, padding => {
132
+ Utils.type.ifNumber(
133
+ padding.top || padding.y || padding.all,
134
+ top => (styles["padding-top"] = `${top}px`)
135
+ );
136
+ Utils.type.ifNumber(
137
+ padding.bottom || padding.y || padding.all,
138
+ bottom => (styles["padding-bottom"] = `${bottom}px`)
139
+ );
140
+ Utils.type.ifNumber(
141
+ padding.left || padding.x || padding.all,
142
+ left => (styles["padding-left"] = `${left}px`)
143
+ );
144
+ Utils.type.ifNumber(
145
+ padding.right || padding.x || padding.all,
146
+ right => (styles["padding-right"] = `${right}px`)
147
+ );
148
+ });
154
149
  },
155
150
  }
156
151
  };
@@ -135,9 +135,6 @@ export default {
135
135
  const onChange = this.spec.onChange || this.spec.onChangeAndLoad;
136
136
  this.formCtx = { form: this.$refs.form };
137
137
  const onChangeHandler = () => {
138
- if (this.$refs.form) {
139
- this.$refs.form.resetValidation();
140
- }
141
138
  this.formCtx = { form: this.$refs.form };
142
139
  if (onChange) this.$executeOnChange();
143
140
  };