glib-web 4.1.1 → 4.1.3

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 (114) hide show
  1. package/.eslintrc.js +4 -1
  2. package/LICENSE +0 -0
  3. package/actions/auth/restart.js +0 -0
  4. package/actions/commands/copy.js +0 -0
  5. package/actions/dialogs/close.js +0 -0
  6. package/actions/dialogs/notification.js +0 -0
  7. package/actions/dialogs/oauth.js +0 -0
  8. package/actions/dialogs/reload.js +0 -0
  9. package/actions/http/delete.js +0 -0
  10. package/actions/http/patch.js +0 -0
  11. package/actions/http/post.js +0 -0
  12. package/actions/http/put.js +0 -0
  13. package/actions/runMultiple.js +0 -0
  14. package/actions/sheets/select.js +0 -0
  15. package/actions/snackbars/select.js +0 -0
  16. package/actions/windows/openWeb.js +0 -0
  17. package/actions/windows/print.js +0 -0
  18. package/components/_message.vue +0 -0
  19. package/components/fields/_patternText.vue +1 -1
  20. package/components/fields/_select.vue +1 -1
  21. package/components/fields/check.vue +1 -1
  22. package/components/fields/checkGroup.vue +4 -3
  23. package/components/fields/chipGroup.vue +5 -2
  24. package/components/fields/creditCard.vue +1 -1
  25. package/components/fields/dynamicGroup.vue +1 -1
  26. package/components/fields/dynamicSelect.vue +1 -1
  27. package/components/fields/file.vue +1 -1
  28. package/components/fields/googlePlace.vue +1 -1
  29. package/components/fields/hidden.vue +1 -1
  30. package/components/fields/location.vue +1 -1
  31. package/components/fields/multiUpload.vue +1 -1
  32. package/components/fields/otpField.vue +1 -1
  33. package/components/fields/phone/countries.js +0 -0
  34. package/components/fields/phone/sprite.css +0 -0
  35. package/components/fields/phone.vue +1 -1
  36. package/components/fields/radio.vue +1 -1
  37. package/components/fields/radioGroup.vue +1 -1
  38. package/components/fields/rating.vue +1 -1
  39. package/components/fields/richText.vue +1 -1
  40. package/components/fields/sign.vue +1 -1
  41. package/components/fields/stripe/stripeFields.vue +1 -1
  42. package/components/fields/stripe/stripeIndividualFields.vue +1 -1
  43. package/components/fields/stripeExternalAccount.vue +1 -1
  44. package/components/fields/stripeToken.vue +1 -1
  45. package/components/fields/text.vue +1 -1
  46. package/components/fields/textarea.vue +1 -1
  47. package/components/fields/timer.vue +1 -1
  48. package/components/h1.vue +0 -0
  49. package/components/h2.vue +0 -0
  50. package/components/h3.vue +0 -0
  51. package/components/h5.vue +0 -0
  52. package/components/h6.vue +0 -0
  53. package/components/hr.vue +0 -0
  54. package/components/html.vue +0 -0
  55. package/components/icon.vue +0 -0
  56. package/components/mixins/extension.js +0 -0
  57. package/components/mixins/generic.js +4 -14
  58. package/components/mixins/longClick.js +0 -0
  59. package/components/mixins/scrolling.js +0 -0
  60. package/components/mixins/styles.js +31 -9
  61. package/components/mixins/table/export.js +0 -0
  62. package/components/mixins/table/import.js +0 -0
  63. package/components/mixins/text.js +0 -0
  64. package/components/multimedia/video.vue +0 -0
  65. package/components/validation.js +179 -0
  66. package/cypress/e2e/glib-web/dialog.cy.ts +13 -0
  67. package/cypress/e2e/glib-web/display.cy.ts +12 -0
  68. package/cypress/e2e/glib-web/{test_page.cy.ts → reactivity.cy.ts} +10 -15
  69. package/cypress/helper.ts +7 -0
  70. package/keys.js +0 -0
  71. package/package.json +1 -1
  72. package/static/plugins/alignment/alignment.js +0 -0
  73. package/static/plugins/alignment/alignment.min.js +0 -0
  74. package/static/plugins/beyondgrammar/beyondgrammar.js +0 -0
  75. package/static/plugins/beyondgrammar/beyondgrammar.min.js +0 -0
  76. package/static/plugins/blockcode/blockcode.js +0 -0
  77. package/static/plugins/blockcode/blockcode.min.js +0 -0
  78. package/static/plugins/clips/clips.js +0 -0
  79. package/static/plugins/clips/clips.min.js +0 -0
  80. package/static/plugins/counter/counter.js +0 -0
  81. package/static/plugins/counter/counter.min.js +0 -0
  82. package/static/plugins/definedlinks/definedlinks.js +0 -0
  83. package/static/plugins/definedlinks/definedlinks.min.js +0 -0
  84. package/static/plugins/handle/handle.js +0 -0
  85. package/static/plugins/handle/handle.min.js +0 -0
  86. package/static/plugins/icons/icons.js +0 -0
  87. package/static/plugins/icons/icons.min.js +0 -0
  88. package/static/plugins/imageposition/imageposition.js +0 -0
  89. package/static/plugins/imageposition/imageposition.min.js +0 -0
  90. package/static/plugins/inlineformat/inlineformat.js +0 -0
  91. package/static/plugins/inlineformat/inlineformat.min.js +0 -0
  92. package/static/plugins/removeformat/removeformat.js +0 -0
  93. package/static/plugins/removeformat/removeformat.min.js +0 -0
  94. package/static/plugins/selector/selector.js +0 -0
  95. package/static/plugins/selector/selector.min.js +0 -0
  96. package/static/plugins/specialchars/specialchars.js +0 -0
  97. package/static/plugins/specialchars/specialchars.min.js +0 -0
  98. package/static/plugins/textdirection/textdirection.js +0 -0
  99. package/static/plugins/textdirection/textdirection.min.js +0 -0
  100. package/static/plugins/textexpander/textexpander.js +0 -0
  101. package/static/plugins/textexpander/textexpander.min.js +0 -0
  102. package/static/plugins/underline/underline.js +0 -0
  103. package/static/plugins/underline/underline.min.js +0 -0
  104. package/static/redactorx.css +0 -0
  105. package/static/redactorx.min.css +0 -0
  106. package/static/redactorx.min.js +0 -0
  107. package/static/redactorx.usm.min.js +0 -0
  108. package/store.js +3 -0
  109. package/styles/test.sass +0 -0
  110. package/styles/test.scss +0 -0
  111. package/templates/unsupported.vue +0 -0
  112. package/utils/dom.js +0 -0
  113. package/utils/helper.js +0 -0
  114. package/utils/type.js +0 -0
package/.eslintrc.js CHANGED
@@ -33,6 +33,9 @@ module.exports = {
33
33
  "GLib": "readonly",
34
34
  "Utils": "readonly",
35
35
  "google": "readonly",
36
- "Stripe": "readonly"
36
+ "Stripe": "readonly",
37
+ "cy": "readonly",
38
+ "it": "readonly",
39
+ "describe": "readonly"
37
40
  }
38
41
  };
package/LICENSE CHANGED
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :style="$styles()" :class="classes()">
2
+ <div :style="$styles()" :class="classes()" v-if="!isInputIgnored">
3
3
  <!-- See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date for why we need to use `pattern` -->
4
4
  <v-text-field :color="gcolor" v-model="fieldModel" :name="fieldName" :label="spec.label" :hint="spec.hint"
5
5
  :type="type" :readonly="spec.readOnly" :disabled="inputDisabled" :min="$sanitizeValue(spec.min)"
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div ref="container" :style="$styles()" :class="classes()">
2
+ <div ref="container" :style="$styles()" :class="classes()" v-if="!isInputIgnored">
3
3
  <v-autocomplete :color="gcolor" v-model="fieldModel" :label="label" :items="normalizedOptions"
4
4
  :chips="spec.multiple" :multiple="spec.multiple" :readonly="spec.readOnly" :clearable="!spec.readOnly"
5
5
  :placeholder="spec.placeholder" :rules="rules" persistent-hint :append-icon="append.icon" validate-on="blur"
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :class="$classes()" :style="$styles()">
2
+ <div :class="$classes()" :style="$styles()" v-if="!isInputIgnored">
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-model="uncheckValue" type="hidden" :name="fieldName" />
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :style="$styles()" :class="$classes()">
2
+ <div :style="$styles()" :class="$classes()" v-if="!isInputIgnored">
3
3
  <fields-check v-for="(childView, index) in childViews" :spec="childView" :key="index"
4
4
  @oncheck="updateFieldModel"></fields-check>
5
5
  <v-input ref="validator" :model-value="fieldModel" :rules="$validation()" :name="fieldName" validate-on="input"
@@ -8,7 +8,7 @@
8
8
  <template v-if="values.length > 0">
9
9
  <input type="hidden" v-for="(value, index) in values" :value="value" :key="index" :name="fieldName" />
10
10
  </template>
11
- <input v-else type="hidden" :name="fieldName" :value="null" />
11
+ <input v-else type="hidden" :name="fieldName" :value="spec.uncheckValue" />
12
12
  </div>
13
13
  </template>
14
14
 
@@ -31,7 +31,8 @@ export default defineComponent({
31
31
  return this.spec.childViews.map((childView) => {
32
32
  const { readOnly, disabled } = this.spec;
33
33
  const parentName = this.spec.name;
34
- return Object.assign({}, { readOnly, disabled, parentName }, childView);
34
+ const value = [this.spec.value].flat().includes(childView.checkValue) ? childView.checkValue : null;
35
+ return Object.assign({}, { readOnly, disabled, parentName, value }, childView);
35
36
  });
36
37
  }
37
38
  },
@@ -1,9 +1,11 @@
1
1
  <template>
2
- <div ref="container" :style="$styles()" :class="$classes()">
2
+ <div ref="container" :style="$styles()" :class="$classes()" v-if="!isInputIgnored">
3
3
  <v-chip-group :color="gcolor" v-model="fieldModel" @update:modelValue="onChange()" :multiple="spec.multiple" column>
4
4
  <v-chip v-for="(option, index) in spec.options" :key="index" filter :variant="variant">{{
5
5
  option.text }}</v-chip>
6
6
  </v-chip-group>
7
+ <v-input ref="validator" :model-value="fieldModel" :rules="$validation()" :name="fieldName" validate-on="input"
8
+ :disabled="inputDisabled"></v-input>
7
9
  <input v-for="(item, index) in indexToValue(fieldModel)" :key="index" type="hidden" :disabled="inputDisabled"
8
10
  :name="fieldName" :value="item" />
9
11
  </div>
@@ -12,7 +14,7 @@
12
14
  <script>
13
15
  import { defineComponent } from "vue";
14
16
  import inputVariant from "../mixins/inputVariant";
15
- import { triggerOnInput } from "../composable/form";
17
+ import { triggerOnChange, triggerOnInput } from "../composable/form";
16
18
 
17
19
  export default defineComponent({
18
20
  mixins: [inputVariant],
@@ -25,6 +27,7 @@ export default defineComponent({
25
27
  const containerEl = this.$refs.container;
26
28
  if (containerEl) {
27
29
  triggerOnInput(containerEl);
30
+ triggerOnChange(containerEl);
28
31
  }
29
32
  },
30
33
  indexToValue(value) {
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :style="$styles()" :class="$classes()">
2
+ <div :style="$styles()" :class="$classes()" v-if="!isInputIgnored">
3
3
  <div class="stretcher">
4
4
  <StripeIndividualFields v-if="$classes().includes('individual')" :spec="spec" ref="delegate"
5
5
  :on-complete="_retrieveToken" :on-error="_displayError" />
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :style="$styles()" :class="$classes()">
2
+ <div :style="$styles()" :class="$classes()" v-if="!isInputIgnored">
3
3
  <div v-for="(group, groupIndex) in groupSpecs" :key="`group${groupIndex}`">
4
4
  <input v-if="isDeleted(groupIndex)" type="hidden" :name="`${spec.name}[${groupIndex}][_destroy]`" value="1" />
5
5
  <div :style="{ display: isDeleted(groupIndex) ? 'none' : 'block' }">
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :style="$styles()">
2
+ <div :style="$styles()" v-if="!isInputIgnored">
3
3
  <v-autocomplete ref="autocomplete" v-model="model" :items="allItems" :loading="$isBusy"
4
4
  :v-model:search-input="search" :label="spec.label" hide-no-data hide-selected no-filter return-object
5
5
  :chips="true" :deletable-chips="true" :multiple="spec.multiple">
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div ref="fileUploadContainer" :style="$styles()" :class="$classes()">
2
+ <div ref="fileUploadContainer" :style="$styles()" :class="$classes()" v-if="!isInputIgnored">
3
3
  <label v-if="spec.label" class="v-label v-label--active">{{ spec.label }}</label>
4
4
  <div class="preview-container" :class="[fileTitle ? 'uploaded' : '']">
5
5
  <v-avatar v-if="placeholder.type == 'avatar'" :style="$styles(placeholder)">
@@ -1,7 +1,7 @@
1
1
  <!-- TODO: This probably can be merged with latLong-v1 or map-v1, i.e. add infoWindow support to latLong or map -->
2
2
 
3
3
  <template>
4
- <v-container fluid class="pa-0">
4
+ <v-container fluid class="pa-0" v-if="!isInputIgnored">
5
5
  <div class="v-input v-text-field theme--light">
6
6
  <div class="v-input__control">
7
7
  <div class="v-input__slot">
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <input type="hidden" :name="fieldName" :value="fieldModel" :disabled="inputDisabled" />
2
+ <input type="hidden" :name="fieldName" :value="fieldModel" :disabled="inputDisabled" v-if="!isInputIgnored" />
3
3
  </template>
4
4
 
5
5
  <script>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :style="$styles()" :class="$classes()">
2
+ <div :style="$styles()" :class="$classes()" v-if="!isInputIgnored">
3
3
 
4
4
  <fields-text ref="autocomplete" type="text" :spec="spec"></fields-text>
5
5
 
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :style="$styles()" :class="$classes()">
2
+ <div :style="$styles()" :class="$classes()" v-if="!isInputIgnored">
3
3
  <div ref="container" @click="handleClick" @drop="handleDrop" @dragover="handleDragOver" @dragleave="handleDragLeave"
4
4
  class="gdrop-file border-[2px]">
5
5
  <input ref="fileSelect" type="file" multiple style="display: none">
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div ref="otp" :style="$styles()" :class="$classes()">
2
+ <div ref="otp" :style="$styles()" :class="$classes()" v-if="!isInputIgnored">
3
3
  <v-otp-input ref="field" v-model="fieldModel" :name="fieldName" :disabled="inputDisabled" :rounded="4"
4
4
  :max-width="maxWidth" type="spec.type || 'number'" :length="length" :variant="variant"
5
5
  @change="$executeOnChange()" />
File without changes
File without changes
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :style="$styles()" :class="$classes()">
2
+ <div :style="$styles()" :class="$classes()" v-if="!isInputIgnored">
3
3
  <v-phone-input :guessCountry="guessCountry" displayFormat="e164" :defaultCountry="defaultCountry" :color="gcolor"
4
4
  v-model="fieldModel" :label="spec.label" :name="fieldName" :hint="spec.hint" :placeholder="spec.placeholder"
5
5
  :maxlength="spec.maxLength || 255" :readonly="spec.readOnly" :rules="$validation()"
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :class="$classes()" :style="$styles()">
2
+ <div :class="$classes()" :style="$styles()" v-if="!isInputIgnored">
3
3
  <v-radio :label="spec.label" :value="(spec.value || '').presence() || vuetifyEmptyString" :readonly="spec.readOnly"
4
4
  :on-icon="spec.onIcon" :off-icon="spec.offIcon" @click="$onClick()" :color="gcolor"
5
5
  :class="spec.imageUrl || spec.icon ? 'custom-radio' : ''">
@@ -5,7 +5,7 @@
5
5
  -->
6
6
  <v-radio-group v-model="fieldModel" :name="fieldName" :readonly="spec.readOnly" :disabled="inputDisabled"
7
7
  :rules="$validation()" :inline="spec.row" validate-on="blur" @change="$executeOnChange()" :class="$classes()"
8
- :style="$styles()">
8
+ :style="$styles()" v-if="!isInputIgnored">
9
9
  <div v-for="(childView, index) in spec.childViews" :key="index" style="width: 100%;">
10
10
  <glib-component :spec="childSpec(childView)" />
11
11
  </div>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div>
2
+ <div v-if="!isInputIgnored">
3
3
  <v-rating v-model="fieldModel" :name="fieldName" empty-icon="star_outline" full-icon="star" half-icon="star_half"
4
4
  :half-increments="spec.halfIncrements" hover length="5" :readonly="spec.readOnly" :disabled="inputDisabled"
5
5
  :color="spec.color" :bg-color="spec.color" :size="spec.size"></v-rating>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div ref="container" :style="$styles()" :class="$classes()">
2
+ <div ref="container" :style="$styles()" :class="$classes()" v-if="!isInputIgnored">
3
3
  <v-tabs v-model="mode" fixed-tabs>
4
4
  <v-tab @click="onRichTextClicked">Editor</v-tab>
5
5
  <v-tab @click="onRawTextClicked">Code</v-tab>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :class="$classes()" :style="$styles()">
2
+ <div :class="$classes()" :style="$styles()" v-if="!isInputIgnored">
3
3
  <div class="glib-canvas-container">
4
4
  <canvas style="width: 100%; height: 100%" @mousedown="handleDrawStart" @mousemove="handleDrawing"
5
5
  @mouseup="handleDrawEnd" @touchstart="handleDrawStart" @touchmove="handleDrawing" @touchend="handleDrawEnd"
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div>
3
- <div ref="container">
3
+ <div ref="container" v-if="!isInputIgnored">
4
4
  <!-- A Stripe Element will be inserted here. -->
5
5
  </div>
6
6
  </div>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div>
2
+ <div v-if="!isInputIgnored">
3
3
  <div class="field">
4
4
  <div class="outlined">
5
5
  <div id="cardNumber" ref="cardNumber" class="input"></div>
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :style="$styles()" :class="$classes()">
2
+ <div :style="$styles()" :class="$classes()" v-if="!isInputIgnored">
3
3
  <v-text-field v-model="accountNumber" label="Account Number" placeholder="000123456" :variant="variant"
4
4
  :rules="accountNumberRules" :error-messages="errorMessages" @keyup="$onTyping({ duration: 200 })" />
5
5
 
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :style="$styles()" :class="$classes()">
2
+ <div :style="$styles()" :class="$classes()" v-if="!isInputIgnored">
3
3
  <StripeIndividualFields v-if="$classes().includes('individual')" :spec="spec" :on-complete="_retrieveToken"
4
4
  :on-error="_displayError" />
5
5
  <StripeFields v-else :spec="spec" :on-complete="_retrieveToken" :on-error="_displayError" />
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :style="$styles()" :class="$classes()">
2
+ <div :style="$styles()" :class="$classes()" v-if="!isInputIgnored">
3
3
  <v-text-field :color="gcolor" ref="field" v-model="fieldModel" :label="spec.label" :name="fieldName"
4
4
  :placeholder="spec.placeholder" :density="density" :hint="spec.hint" :maxlength="spec.maxLength || 255"
5
5
  :readonly="spec.readOnly" :disabled="inputDisabled" :type="config.type" :rules="rules"
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :style="styles()" :class="classes()">
2
+ <div :style="styles()" :class="classes()" v-if="!isInputIgnored">
3
3
  <v-textarea :color="gcolor" v-model="fieldModel" :label="spec.label" :name="fieldName" :hint="spec.hint"
4
4
  :placeholder="spec.placeholder" :maxlength="spec.maxLength || 255" :readonly="spec.readOnly" :height="height"
5
5
  :rules="$validation()" counter :outlined="$classes().includes('outlined')" :disabled="inputDisabled"
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :style="$styles()" :class="classes()">
2
+ <div :style="$styles()" :class="classes()" v-if="!isInputIgnored">
3
3
  <div v-if="days_mode">
4
4
  <div align="center">
5
5
  <v-row align="center" justify="center">
package/components/h1.vue CHANGED
File without changes
package/components/h2.vue CHANGED
File without changes
package/components/h3.vue CHANGED
File without changes
package/components/h5.vue CHANGED
File without changes
package/components/h6.vue CHANGED
File without changes
package/components/hr.vue CHANGED
File without changes
File without changes
File without changes
File without changes
@@ -1,4 +1,5 @@
1
1
  import { vueApp } from "../../store";
2
+ import { ValidationFactory } from "../validation";
2
3
 
3
4
  export default {
4
5
  methods: {
@@ -24,20 +25,9 @@ export default {
24
25
  $validation(rules) {
25
26
  var augmentedRules = rules || [];
26
27
  Utils.type.ifObject(this.spec.validation, val => {
27
- Utils.type.ifObject(val.required, spec => {
28
- augmentedRules = augmentedRules.concat([
29
- v => (v ? true : spec.message)
30
- ]);
31
- });
32
- Utils.type.ifObject(val.format, spec => {
33
- augmentedRules = augmentedRules.concat([
34
- v => {
35
- if (v && !v.toString().match(spec.regex)) {
36
- return spec.message;
37
- }
38
- return true;
39
- }
40
- ]);
28
+ Object.keys(val).forEach((key) => {
29
+ const validator = ValidationFactory.getValidator(key, val[key]);
30
+ augmentedRules = augmentedRules.concat([validator.build.bind(validator)]);
41
31
  });
42
32
  });
43
33
  return augmentedRules;
File without changes
File without changes
@@ -3,6 +3,7 @@ import { fieldModels, watchFieldModels } from "../composable/conditional";
3
3
  import { dirtySpecs } from "../composable/dirtyState";
4
4
  import { determineColor } from "../../utils/constant";
5
5
  import Action from "../../action";
6
+ import { vueApp } from "../../store";
6
7
 
7
8
  const NUMBER_PRECISION = 2;
8
9
  const isNeedToBeFixed = (val, component) => {
@@ -18,6 +19,7 @@ export default {
18
19
  _submitWhenNotDisplayed: !this.spec || !Utils.type.isNotNull(this.spec.submitWhenNotDisplayed) ? false : !!this.spec.submitWhenNotDisplayed,
19
20
  _watchers: [],
20
21
  _isValueChanged: false,
22
+ ignoredInputs: new Set(),
21
23
  // Some components do not support null or empty string value, so we need to use an intermediary value.
22
24
  // See https://github.com/vuetifyjs/vuetify/issues/8876
23
25
  vuetifyEmptyString: "<EMPTY_STRING>"
@@ -39,9 +41,25 @@ export default {
39
41
  gcolor() {
40
42
  if (!this.spec) return '';
41
43
  return determineColor(this.spec.styleClasses, this.spec.color || 'primary');
44
+ },
45
+ isInputIgnored() {
46
+ return vueApp.ignoredInputs.has(this.fieldName) && !this._submitWhenNotDisplayed;
42
47
  }
43
48
  },
44
49
  watch: {
50
+ _show: {
51
+ handler(val) {
52
+ this.ignoredInputs.forEach((input) => vueApp.ignoredInputs.delete(input));
53
+ this.ignoredInputs.clear();
54
+ if (!val && this.$el && this.$el instanceof HTMLElement && !this._submitWhenNotDisplayed) {
55
+ Array.from(this.$el.querySelectorAll('input,select,textarea')).forEach((el) => {
56
+ this.ignoredInputs.add(el.name);
57
+ vueApp.ignoredInputs.add(el.name);
58
+ });
59
+ }
60
+ },
61
+ // immediate: true
62
+ },
45
63
  fieldModel: function (val) {
46
64
  if (val === this.vuetifyEmptyString) {
47
65
  val = "";
@@ -114,7 +132,7 @@ export default {
114
132
  // this._watchers.push(watcher1);
115
133
  // }
116
134
 
117
- if (this.spec && (this.spec.showIf || this.spec.loadIf) && this.$jsonLogicEnabled()) {
135
+ if (this.spec && (this.spec.showIf || this.spec.loadIf)) {
118
136
  watcher2 = watchFieldModels(this.spec.showIf || this.spec.loadIf, (value) => {
119
137
  const oldValue = this._show;
120
138
 
@@ -124,6 +142,10 @@ export default {
124
142
  this._show = false;
125
143
  }
126
144
 
145
+ // if (this.spec.showIf) {
146
+ // this._submitWhenNotDisplayed = true;
147
+ // }
148
+
127
149
  if (oldValue != value) {
128
150
  this.$nextTick(() => {
129
151
  // Call either onIfTrue or onIfFalse.
@@ -266,14 +288,14 @@ export default {
266
288
  if (Utils.type.isNotNull(newSpec.displayed)) vm._show = newSpec.displayed;
267
289
  vm._submitWhenNotDisplayed = newSpec.submitWhenNotDisplayed;
268
290
 
269
- if (vm.$el && vm.$el == typeof HTMLElement) {
270
- const els = vm.$el.querySelectorAll('input,textarea');
271
- if (!vm.submitWhenNotDisplayed) {
272
- els.forEach((el) => el.disabled = true);
273
- } else {
274
- els.forEach((el) => el.disabled = false);
275
- }
276
- }
291
+ // if (vm.$el) {
292
+ // const els = vm.$el.querySelectorAll('input,textarea');
293
+ // if (!vm.submitWhenNotDisplayed) {
294
+ // els.forEach((el) => el.disabled = true);
295
+ // } else {
296
+ // els.forEach((el) => el.disabled = false);
297
+ // }
298
+ // }
277
299
 
278
300
  Object.assign(this.spec, newSpec);
279
301
  },
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,179 @@
1
+ class AbstractValidator {
2
+ constructor(validationOptions) {
3
+ this.validationOptions = validationOptions;
4
+ }
5
+
6
+ build(model) {
7
+ return true;
8
+ }
9
+
10
+ isAllowBlank() {
11
+ return !!this.validationOptions.allow_blank || !!this.validationOptions.allow_nil;
12
+ }
13
+ }
14
+
15
+ function isPresent(value) {
16
+ if (value == undefined) return false;
17
+ if (value == null) return false;
18
+ if (Array.isArray(value) && value.length <= 0) return false;
19
+ if (typeof value == 'string' && value.length <= 0) return false;
20
+ if (typeof value == 'object' && Object.keys(value).length <= 0) return false;
21
+
22
+ return true;
23
+ }
24
+
25
+ class PresenceValidator extends AbstractValidator {
26
+ build(model) {
27
+ return isPresent(model) ? true : this.validationOptions.message;
28
+ }
29
+ }
30
+ class RequiredValidator extends PresenceValidator { }
31
+
32
+ class AbsenceValidator extends AbstractValidator {
33
+ build(model) {
34
+ return !isPresent(model) ? true : this.validationOptions.message;
35
+ }
36
+ }
37
+
38
+ class AcceptanceValidator extends AbstractValidator {
39
+ build(model) {
40
+ if (this.isAllowBlank() && !isPresent(model)) return true;
41
+
42
+ const { accept } = this.validationOptions;
43
+ return accept.includes(model) ? true : this.validationOptions.message;
44
+ }
45
+ }
46
+
47
+ class NumericalityValidator extends AbstractValidator {
48
+ build(model) {
49
+ if (this.isAllowBlank() && !isPresent(model)) return true;
50
+
51
+ let result = true;
52
+ ['greater_than', 'greater_than_or_equal_to', 'equal_to', 'less_than', 'less_than_or_equal_to', 'other_than', 'odd', 'even'].forEach((key) => {
53
+ let count = this.validationOptions[key];
54
+ if (!isPresent(count)) return;
55
+ if (this.validate(key, count, model)) return;
56
+
57
+ result = this.errorMessage(key, count);
58
+ });
59
+
60
+ return result;
61
+ }
62
+
63
+ validate(key, count, value) {
64
+ const obj = {
65
+ 'greater_than': () => count < value,
66
+ 'greater_than_or_equal_to': () => count <= value,
67
+ 'equal_to': () => count == value,
68
+ 'less_than': () => count > value,
69
+ 'less_than_or_equal_to': () => count >= value,
70
+ 'other_than': () => count != value,
71
+ 'in': () => count.includes(value),
72
+ 'odd': () => value % 2 == 1,
73
+ 'even': () => value % 2 == 0
74
+ };
75
+
76
+ return obj[key]();
77
+ }
78
+
79
+ errorMessage(key, count) {
80
+ const message = this.validationOptions.message;
81
+ if (typeof message == 'string') return message;
82
+
83
+ return message[key].replace('%{count}', count);
84
+ }
85
+ }
86
+
87
+ class FormatValidator extends AbstractValidator {
88
+ build(model) {
89
+ if (this.isAllowBlank() && !isPresent(model)) return true;
90
+
91
+ const regex = this.validationOptions.with || this.validationOptions.without || this.validationOptions.regex;
92
+ let match = !!(model || '').match(regex);
93
+ match = this.isInverse() ? !match : match;
94
+
95
+ return match ? true : this.validationOptions.message;
96
+ }
97
+
98
+ isInverse() {
99
+ return !!this.validationOptions.without;
100
+ }
101
+ }
102
+
103
+ class InclusionValidator extends AbstractValidator {
104
+ build(model) {
105
+ if (this.isAllowBlank() && !isPresent(model)) return true;
106
+
107
+ const within = this.validationOptions.in || this.validationOptions.within;
108
+
109
+ return within.includes(model) ? true : this.validationOptions.message;
110
+ }
111
+ }
112
+
113
+ class ExclusionValidator extends AbstractValidator {
114
+ build(model) {
115
+ if (this.isAllowBlank() && !isPresent(model)) return true;
116
+
117
+ const within = this.validationOptions.in || this.validationOptions.within;
118
+
119
+ return !within.includes(model) ? true : this.validationOptions.message;
120
+ }
121
+ }
122
+
123
+ class LengthValidator extends AbsenceValidator {
124
+ build(model) {
125
+ model ||= '';
126
+ if (this.isAllowBlank() && !isPresent(model)) return true;
127
+
128
+ const { minimum, maximum } = this.validationOptions;
129
+ let result;
130
+ if (isPresent(minimum)) {
131
+ result = model.length > minimum ? true : this.errorMessage('too_short', minimum);
132
+ }
133
+ if (result !== true) return result;
134
+ if (isPresent(maximum)) {
135
+ result = model.length < maximum ? true : this.errorMessage('too_long', maximum);
136
+ }
137
+ if (result !== true) return result;
138
+ if (isPresent(this.validationOptions.is)) {
139
+ result = model.length === this.validationOptions.is ? true : this.errorMessage('wrong_length', this.validationOptions.is);
140
+ }
141
+ if (result !== true) return result;
142
+ if (isPresent(this.validationOptions.in)) {
143
+ result = (model.length >= this.validationOptions.is || model.length <= this.validatorOptions.is) ? true : this.errorMessage('wrong_length', this.validationOptions.in);
144
+ }
145
+
146
+ return result;
147
+ }
148
+
149
+ errorMessage(key, count) {
150
+ const message = this.validationOptions.message;
151
+ const singular = count <= 1;
152
+ if (typeof message == 'string') {
153
+ return message.replace('%{count}', count);
154
+ }
155
+
156
+ return message[key][singular ? 'one' : 'other'].replace('%{count}', count);
157
+ }
158
+ }
159
+
160
+ const clsMap = {
161
+ 'absence': AbsenceValidator,
162
+ 'presence': PresenceValidator,
163
+ 'required': RequiredValidator,
164
+ 'acceptance': AcceptanceValidator,
165
+ 'numericality': NumericalityValidator,
166
+ 'format': FormatValidator,
167
+ 'inclusion': InclusionValidator,
168
+ 'exclusion': ExclusionValidator,
169
+ 'length': LengthValidator
170
+ };
171
+
172
+ class ValidationFactory {
173
+ static getValidator(validatorName, validatorOptions) {
174
+ return new clsMap[validatorName](validatorOptions);
175
+ }
176
+ }
177
+
178
+ export { ValidationFactory }
179
+
@@ -0,0 +1,13 @@
1
+ import { testPageUrl } from "../../helper"
2
+
3
+ describe('dialog', () => {
4
+ it('updateExisting', () => {
5
+ cy.visit(testPageUrl())
6
+ cy.contains('Dialog updateExisting').click()
7
+ cy.get('.v-dialog h1').should('contain.text', 'Hello world')
8
+ cy.get('.v-dialog .v-icon').should('exist')
9
+ cy.get('.v-dialog').contains('change dialog content').click()
10
+ cy.get('.v-dialog h1').should('contain.text', 'Hello world (updated)')
11
+ cy.get('.v-dialog .v-icon').should('not.exist')
12
+ })
13
+ })
@@ -0,0 +1,12 @@
1
+ import { testPageUrl } from "../../helper"
2
+
3
+ describe('display', () => {
4
+ it('form validity', () => {
5
+ cy.visit(testPageUrl())
6
+
7
+ cy.get('.fields-select .v-field__clearable').first().click()
8
+ cy.contains('submit (if form valid)').should('have.class', 'v-btn--disabled')
9
+ cy.contains('hide select').click()
10
+ cy.contains('submit (if form valid)').should('not.have.class', 'v-btn--disabled')
11
+ })
12
+ })
@@ -1,8 +1,9 @@
1
- const TEST_PAGE = 'http://localhost:3000/glib/json_ui_garage?path=test_page%2Findex'
1
+ import { testPageUrl } from "../../helper"
2
+
2
3
 
3
4
  describe('reactivity', () => {
4
5
  it('logics/set, components/set, components/replace', () => {
5
- cy.visit(TEST_PAGE)
6
+ cy.visit(testPageUrl())
6
7
 
7
8
  // submit button should be clickabl e
8
9
  cy.contains('submit (if form valid)').should('not.have.class', 'v-btn--disabled')
@@ -16,15 +17,15 @@ describe('reactivity', () => {
16
17
 
17
18
  cy.get('.fields-check input[type="checkbox"]').first().click()
18
19
 
19
- // cy.contains('submit (if form valid)').should('have.class', 'v-btn--disabled')
20
+ cy.contains('submit (if form valid)').should('have.class', 'v-btn--disabled')
20
21
 
21
22
  cy.get('.fields-radio input[type="radio"]').first().click()
22
23
 
23
- // cy.contains('submit (if form valid)').should('have.class', 'v-btn--disabled')
24
+ cy.contains('submit (if form valid)').should('have.class', 'v-btn--disabled')
24
25
 
25
26
  cy.get('.fields-chipGroup .v-chip').first().click()
26
27
 
27
- // cy.contains('submit (if form valid)').should('not.have.class', 'v-btn--disabled')
28
+ cy.contains('submit (if form valid)').should('not.have.class', 'v-btn--disabled')
28
29
 
29
30
  cy.get('button').contains('submit').first().click()
30
31
 
@@ -32,7 +33,9 @@ describe('reactivity', () => {
32
33
  Form Data:
33
34
  {
34
35
  "date": "2024-07-27",
35
- "select": "option99",
36
+ "select": [
37
+ "option99"
38
+ ],
36
39
  "chip_group": "option99",
37
40
  "text": "Doe John",
38
41
  "textarea": "The quick brown fox jumps over the lazy dog"
@@ -41,13 +44,5 @@ Form Data:
41
44
  cy.get('.unformatted').should('contain.text', result)
42
45
  })
43
46
 
44
- it('dialog', () => {
45
- cy.visit(TEST_PAGE)
46
- cy.contains('Dialog updateExisting').click()
47
- cy.get('.v-dialog h1').should('contain.text', 'Hello world')
48
- cy.get('.v-dialog .v-icon').should('exist')
49
- cy.get('.v-dialog').contains('change dialog content').click()
50
- cy.get('.v-dialog h1').should('contain.text', 'Hello world (updated)')
51
- cy.get('.v-dialog .v-icon').should('not.exist')
52
- })
47
+
53
48
  })
@@ -0,0 +1,7 @@
1
+ const DEV_TEST_PAGE = 'http://localhost:3000/glib/json_ui_garage?path=test_page%2Findex'
2
+
3
+ function testPageUrl() {
4
+ return DEV_TEST_PAGE;
5
+ }
6
+
7
+ export { testPageUrl }
package/keys.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glib-web",
3
- "version": "4.1.1",
3
+ "version": "4.1.3",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/store.js CHANGED
@@ -18,6 +18,7 @@ export const vueApp = reactive({
18
18
  richTextValues: {},
19
19
  draggedComponent: null,
20
20
  lastNavigationCount: null,
21
+ ignoredInputs: new Set(),
21
22
  tooltipSpec: {},
22
23
  bottomBanners: {},
23
24
  uploader: {},
@@ -42,6 +43,8 @@ export const glibevent = reactive({
42
43
  });
43
44
 
44
45
  function glibEventHandler(e) {
46
+ vueApp.ignoredInputs = new Set();
47
+
45
48
  const { onUnload } = jsonView.page;
46
49
  if (onUnload) {
47
50
  Action.execute(onUnload, {});
package/styles/test.sass CHANGED
File without changes
package/styles/test.scss CHANGED
File without changes
File without changes
package/utils/dom.js CHANGED
File without changes
package/utils/helper.js CHANGED
File without changes
package/utils/type.js CHANGED
File without changes