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.
- package/.eslintrc.js +4 -1
- package/LICENSE +0 -0
- package/actions/auth/restart.js +0 -0
- package/actions/commands/copy.js +0 -0
- package/actions/dialogs/close.js +0 -0
- package/actions/dialogs/notification.js +0 -0
- package/actions/dialogs/oauth.js +0 -0
- package/actions/dialogs/reload.js +0 -0
- package/actions/http/delete.js +0 -0
- package/actions/http/patch.js +0 -0
- package/actions/http/post.js +0 -0
- package/actions/http/put.js +0 -0
- package/actions/runMultiple.js +0 -0
- package/actions/sheets/select.js +0 -0
- package/actions/snackbars/select.js +0 -0
- package/actions/windows/openWeb.js +0 -0
- package/actions/windows/print.js +0 -0
- package/components/_message.vue +0 -0
- package/components/fields/_patternText.vue +1 -1
- package/components/fields/_select.vue +1 -1
- package/components/fields/check.vue +1 -1
- package/components/fields/checkGroup.vue +4 -3
- package/components/fields/chipGroup.vue +5 -2
- package/components/fields/creditCard.vue +1 -1
- package/components/fields/dynamicGroup.vue +1 -1
- package/components/fields/dynamicSelect.vue +1 -1
- package/components/fields/file.vue +1 -1
- package/components/fields/googlePlace.vue +1 -1
- package/components/fields/hidden.vue +1 -1
- package/components/fields/location.vue +1 -1
- package/components/fields/multiUpload.vue +1 -1
- package/components/fields/otpField.vue +1 -1
- package/components/fields/phone/countries.js +0 -0
- package/components/fields/phone/sprite.css +0 -0
- package/components/fields/phone.vue +1 -1
- package/components/fields/radio.vue +1 -1
- package/components/fields/radioGroup.vue +1 -1
- package/components/fields/rating.vue +1 -1
- package/components/fields/richText.vue +1 -1
- package/components/fields/sign.vue +1 -1
- package/components/fields/stripe/stripeFields.vue +1 -1
- package/components/fields/stripe/stripeIndividualFields.vue +1 -1
- package/components/fields/stripeExternalAccount.vue +1 -1
- package/components/fields/stripeToken.vue +1 -1
- package/components/fields/text.vue +1 -1
- package/components/fields/textarea.vue +1 -1
- package/components/fields/timer.vue +1 -1
- package/components/h1.vue +0 -0
- package/components/h2.vue +0 -0
- package/components/h3.vue +0 -0
- package/components/h5.vue +0 -0
- package/components/h6.vue +0 -0
- package/components/hr.vue +0 -0
- package/components/html.vue +0 -0
- package/components/icon.vue +0 -0
- package/components/mixins/extension.js +0 -0
- package/components/mixins/generic.js +4 -14
- package/components/mixins/longClick.js +0 -0
- package/components/mixins/scrolling.js +0 -0
- package/components/mixins/styles.js +31 -9
- package/components/mixins/table/export.js +0 -0
- package/components/mixins/table/import.js +0 -0
- package/components/mixins/text.js +0 -0
- package/components/multimedia/video.vue +0 -0
- package/components/validation.js +179 -0
- package/cypress/e2e/glib-web/dialog.cy.ts +13 -0
- package/cypress/e2e/glib-web/display.cy.ts +12 -0
- package/cypress/e2e/glib-web/{test_page.cy.ts → reactivity.cy.ts} +10 -15
- package/cypress/helper.ts +7 -0
- package/keys.js +0 -0
- package/package.json +1 -1
- package/static/plugins/alignment/alignment.js +0 -0
- package/static/plugins/alignment/alignment.min.js +0 -0
- package/static/plugins/beyondgrammar/beyondgrammar.js +0 -0
- package/static/plugins/beyondgrammar/beyondgrammar.min.js +0 -0
- package/static/plugins/blockcode/blockcode.js +0 -0
- package/static/plugins/blockcode/blockcode.min.js +0 -0
- package/static/plugins/clips/clips.js +0 -0
- package/static/plugins/clips/clips.min.js +0 -0
- package/static/plugins/counter/counter.js +0 -0
- package/static/plugins/counter/counter.min.js +0 -0
- package/static/plugins/definedlinks/definedlinks.js +0 -0
- package/static/plugins/definedlinks/definedlinks.min.js +0 -0
- package/static/plugins/handle/handle.js +0 -0
- package/static/plugins/handle/handle.min.js +0 -0
- package/static/plugins/icons/icons.js +0 -0
- package/static/plugins/icons/icons.min.js +0 -0
- package/static/plugins/imageposition/imageposition.js +0 -0
- package/static/plugins/imageposition/imageposition.min.js +0 -0
- package/static/plugins/inlineformat/inlineformat.js +0 -0
- package/static/plugins/inlineformat/inlineformat.min.js +0 -0
- package/static/plugins/removeformat/removeformat.js +0 -0
- package/static/plugins/removeformat/removeformat.min.js +0 -0
- package/static/plugins/selector/selector.js +0 -0
- package/static/plugins/selector/selector.min.js +0 -0
- package/static/plugins/specialchars/specialchars.js +0 -0
- package/static/plugins/specialchars/specialchars.min.js +0 -0
- package/static/plugins/textdirection/textdirection.js +0 -0
- package/static/plugins/textdirection/textdirection.min.js +0 -0
- package/static/plugins/textexpander/textexpander.js +0 -0
- package/static/plugins/textexpander/textexpander.min.js +0 -0
- package/static/plugins/underline/underline.js +0 -0
- package/static/plugins/underline/underline.min.js +0 -0
- package/static/redactorx.css +0 -0
- package/static/redactorx.min.css +0 -0
- package/static/redactorx.min.js +0 -0
- package/static/redactorx.usm.min.js +0 -0
- package/store.js +3 -0
- package/styles/test.sass +0 -0
- package/styles/test.scss +0 -0
- package/templates/unsupported.vue +0 -0
- package/utils/dom.js +0 -0
- package/utils/helper.js +0 -0
- package/utils/type.js +0 -0
package/.eslintrc.js
CHANGED
package/LICENSE
CHANGED
|
File without changes
|
package/actions/auth/restart.js
CHANGED
|
File without changes
|
package/actions/commands/copy.js
CHANGED
|
File without changes
|
package/actions/dialogs/close.js
CHANGED
|
File without changes
|
|
File without changes
|
package/actions/dialogs/oauth.js
CHANGED
|
File without changes
|
|
File without changes
|
package/actions/http/delete.js
CHANGED
|
File without changes
|
package/actions/http/patch.js
CHANGED
|
File without changes
|
package/actions/http/post.js
CHANGED
|
File without changes
|
package/actions/http/put.js
CHANGED
|
File without changes
|
package/actions/runMultiple.js
CHANGED
|
File without changes
|
package/actions/sheets/select.js
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/actions/windows/print.js
CHANGED
|
File without changes
|
package/components/_message.vue
CHANGED
|
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="
|
|
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
|
-
|
|
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
|
-
<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,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"
|
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
|
package/components/html.vue
CHANGED
|
File without changes
|
package/components/icon.vue
CHANGED
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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)
|
|
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
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
-
|
|
1
|
+
import { testPageUrl } from "../../helper"
|
|
2
|
+
|
|
2
3
|
|
|
3
4
|
describe('reactivity', () => {
|
|
4
5
|
it('logics/set, components/set, components/replace', () => {
|
|
5
|
-
cy.visit(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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":
|
|
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
|
-
|
|
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
|
})
|
package/keys.js
CHANGED
|
File without changes
|
package/package.json
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
|
|
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/static/redactorx.css
CHANGED
|
File without changes
|
package/static/redactorx.min.css
CHANGED
|
File without changes
|
package/static/redactorx.min.js
CHANGED
|
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
|