glib-web 4.44.6 → 5.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/.github/workflows/lint.yml +2 -2
  2. package/.nycrc.json +3 -1
  3. package/README.md +9 -1
  4. package/agent/commands/generate_test.yaml +5 -5
  5. package/components/charts/series.js +23 -11
  6. package/components/component.vue +0 -5
  7. package/components/fields/checkGroup.vue +14 -7
  8. package/components/fields/richText2.vue +33 -3
  9. package/components/fields/upload.vue +5 -3
  10. package/components/mixins/styles.js +0 -1
  11. package/components/popover.vue +107 -78
  12. package/cypress/component/{inputUpload.cy.ts → inputUpload.cy.js} +3 -3
  13. package/cypress/component/{multiUpload.cy.ts → multiUpload.cy.js} +3 -3
  14. package/cypress/component/{placeholderUpload.cy.ts → placeholderUpload.cy.js} +3 -3
  15. package/cypress/component/{testUtils.ts → testUtils.js} +3 -15
  16. package/cypress/e2e/glib-web/{auth.cy.ts → auth.cy.js} +22 -1
  17. package/cypress/e2e/glib-web/{autoValidate.cy.ts → autoValidate.cy.js} +1 -1
  18. package/cypress/e2e/glib-web/{browsers.cy.ts → browsers.cy.js} +1 -1
  19. package/cypress/e2e/glib-web/{calendar.cy.ts → calendar.cy.js} +1 -1
  20. package/cypress/e2e/glib-web/{calendarEmptyData.cy.ts → calendarEmptyData.cy.js} +1 -1
  21. package/cypress/e2e/glib-web/{carousel.cy.ts → carousel.cy.js} +1 -1
  22. package/cypress/e2e/glib-web/{charts.cy.ts → charts.cy.js} +1 -1
  23. package/cypress/e2e/glib-web/{column.cy.ts → column.cy.js} +1 -1
  24. package/cypress/e2e/glib-web/{commands.cy.ts → commands.cy.js} +1 -1
  25. package/cypress/e2e/glib-web/{components.cy.ts → components.cy.js} +1 -1
  26. package/cypress/e2e/glib-web/{cookies.cy.ts → cookies.cy.js} +1 -1
  27. package/cypress/e2e/glib-web/{custom.cy.ts → custom.cy.js} +1 -1
  28. package/cypress/e2e/glib-web/dialog.cy.js +63 -0
  29. package/cypress/e2e/glib-web/{dialogOpen.cy.ts → dialogOpen.cy.js} +1 -1
  30. package/cypress/e2e/glib-web/{dirtyState.cy.ts → dirtyState.cy.js} +9 -24
  31. package/cypress/e2e/glib-web/{display.cy.ts → display.cy.js} +1 -1
  32. package/cypress/e2e/glib-web/{fields.cy.ts → fields.cy.js} +1 -1
  33. package/cypress/e2e/glib-web/{fieldsCaptcha.cy.ts → fieldsCaptcha.cy.js} +1 -1
  34. package/cypress/e2e/glib-web/fieldsCreditCard.cy.js +22 -0
  35. package/cypress/e2e/glib-web/fieldsDateTime.cy.js +48 -0
  36. package/cypress/e2e/glib-web/{fieldsDynamicSelect.cy.ts → fieldsDynamicSelect.cy.js} +1 -1
  37. package/cypress/e2e/glib-web/fieldsLocation.cy.js +40 -0
  38. package/cypress/e2e/glib-web/fieldsOtp.cy.js +68 -0
  39. package/cypress/e2e/glib-web/fieldsPhone.cy.js +87 -0
  40. package/cypress/e2e/glib-web/fieldsRating.cy.js +91 -0
  41. package/cypress/e2e/glib-web/fieldsRichText.cy.js +136 -0
  42. package/cypress/e2e/glib-web/{fieldsSelect.cy.ts → fieldsSelect.cy.js} +1 -1
  43. package/cypress/e2e/glib-web/{fieldsSign.cy.ts → fieldsSign.cy.js} +1 -1
  44. package/cypress/e2e/glib-web/fieldsStripeToken.cy.js +47 -0
  45. package/cypress/e2e/glib-web/{fieldsTimer.cy.ts → fieldsTimer.cy.js} +1 -1
  46. package/cypress/e2e/glib-web/fieldsUpload.cy.js +159 -0
  47. package/cypress/e2e/glib-web/{fieldsUrlFragment.cy.ts → fieldsUrlFragment.cy.js} +1 -1
  48. package/cypress/e2e/glib-web/{flow.cy.ts → flow.cy.js} +1 -1
  49. package/cypress/e2e/glib-web/{form.cy.ts → form.cy.js} +1 -1
  50. package/cypress/e2e/glib-web/{formDynamic.cy.ts → formDynamic.cy.js} +1 -1
  51. package/cypress/e2e/glib-web/{forms.cy.ts → forms.cy.js} +1 -1
  52. package/cypress/e2e/glib-web/{grid.cy.ts → grid.cy.js} +1 -1
  53. package/cypress/e2e/glib-web/{horizontal.cy.ts → horizontal.cy.js} +1 -1
  54. package/cypress/e2e/glib-web/{http.cy.ts → http.cy.js} +1 -1
  55. package/cypress/e2e/glib-web/{image.cy.ts → image.cy.js} +1 -1
  56. package/cypress/e2e/glib-web/{lifecycle.cy.ts → lifecycle.cy.js} +1 -1
  57. package/cypress/e2e/glib-web/{list.cy.ts → list.cy.js} +1 -1
  58. package/cypress/e2e/glib-web/{listEditable.cy.ts → listEditable.cy.js} +1 -1
  59. package/cypress/e2e/glib-web/{listsAppend.cy.ts → listsAppend.cy.js} +1 -1
  60. package/cypress/e2e/glib-web/{logicsSet.cy.ts → logicsSet.cy.js} +1 -1
  61. package/cypress/e2e/glib-web/{multimediaVideo.cy.ts → multimediaVideo.cy.js} +1 -1
  62. package/cypress/e2e/glib-web/{pagination.cy.ts → pagination.cy.js} +1 -1
  63. package/cypress/e2e/glib-web/{panels.cy.ts → panels.cy.js} +1 -1
  64. package/cypress/e2e/glib-web/{panelsBulkEdit2.cy.ts → panelsBulkEdit2.cy.js} +1 -1
  65. package/cypress/e2e/glib-web/{popovers.cy.ts → popovers.cy.js} +1 -1
  66. package/cypress/e2e/glib-web/{progressCircle.cy.ts → progressCircle.cy.js} +1 -1
  67. package/cypress/e2e/glib-web/{responsive.cy.ts → responsive.cy.js} +1 -1
  68. package/cypress/e2e/glib-web/{scroll.cy.ts → scroll.cy.js} +1 -1
  69. package/cypress/e2e/glib-web/{selectable.cy.ts → selectable.cy.js} +1 -1
  70. package/cypress/e2e/glib-web/{sheets.cy.ts → sheets.cy.js} +1 -1
  71. package/cypress/e2e/glib-web/{snackbars.cy.ts → snackbars.cy.js} +1 -1
  72. package/cypress/e2e/glib-web/{split.cy.ts → split.cy.js} +1 -1
  73. package/cypress/e2e/glib-web/{storageItems.cy.ts → storageItems.cy.js} +1 -1
  74. package/cypress/e2e/glib-web/{table.cy.ts → table.cy.js} +1 -1
  75. package/cypress/e2e/glib-web/{timeline.cy.ts → timeline.cy.js} +1 -1
  76. package/cypress/e2e/glib-web/{timeouts.cy.ts → timeouts.cy.js} +1 -1
  77. package/cypress/e2e/glib-web/{ul.cy.ts → ul.cy.js} +1 -1
  78. package/cypress/e2e/glib-web/{vertical.cy.ts → vertical.cy.js} +1 -1
  79. package/cypress/e2e/glib-web/{web.cy.ts → web.cy.js} +1 -1
  80. package/cypress/e2e/glib-web/window.cy.js +21 -0
  81. package/cypress/e2e/glib-web/{windows.cy.ts → windows.cy.js} +34 -2
  82. package/cypress/helper.js +19 -0
  83. package/cypress/support/{commands.ts → commands.js} +2 -2
  84. package/cypress/support/component.js +27 -0
  85. package/cypress/support/{e2e.ts → e2e.js} +18 -3
  86. package/{cypress.config.ts → cypress.config.js} +3 -2
  87. package/cypress.yml.example +6 -7
  88. package/doc/TESTING.md +2 -2
  89. package/package.json +1 -1
  90. package/components/composable/dropable.js +0 -52
  91. package/components/fields/googlePlace.vue +0 -162
  92. package/components/mixins/tooltip.js +0 -57
  93. package/cypress/e2e/glib-web/dialog.cy.ts +0 -25
  94. package/cypress/e2e/glib-web/fieldsUpload.cy.ts +0 -48
  95. package/cypress/e2e/glib-web/multiupload.cy.ts +0 -25
  96. package/cypress/e2e/glib-web/window.cy.ts +0 -14
  97. package/cypress/helper.ts +0 -7
  98. package/cypress/support/component.ts +0 -12
@@ -2,9 +2,9 @@ name: Lint
2
2
 
3
3
  on:
4
4
  push:
5
- branches:
6
- - "**"
5
+ branches: [main]
7
6
  pull_request:
7
+ branches: [main]
8
8
 
9
9
  jobs:
10
10
  lint:
package/.nycrc.json CHANGED
@@ -32,6 +32,8 @@
32
32
  "extensions/*",
33
33
  "components/treeView.vue",
34
34
  "actions/files/*",
35
- "actions/bottom_banners/*"
35
+ "actions/bottom_banners/*",
36
+ "plugins/vuetify.js",
37
+ "components/composable/upload_delegator.js"
36
38
  ]
37
39
  }
package/README.md CHANGED
@@ -6,6 +6,7 @@
6
6
  - Edit settings.json
7
7
  - `CTRL+SHIFT+P` -> `Preferences: Open User Settings (JSON)` -- This will open an editor for `settings.json`.
8
8
  - Copy content of `settings.json.example` into the editor.
9
+ - Disable format-on-save for Volar to avoid formatting conflicts with ESLint.
9
10
 
10
11
  ## Set up Javascript CI
11
12
 
@@ -19,7 +20,7 @@ module.exports = defineConfig({
19
20
  e2e: {
20
21
  specPattern: 'node_modules/glib-web/cypress/e2e',
21
22
  defaultBrowser: 'chrome',
22
- supportFile: 'node_modules/glib-web/cypress/support/e2e.{js,jsx,ts,tsx}'
23
+ supportFile: 'node_modules/glib-web/cypress/support/e2e.js'
23
24
  },
24
25
  });
25
26
  ```
@@ -29,6 +30,13 @@ module.exports = defineConfig({
29
30
  - Run rails server `bin/rails s`
30
31
  - Execute `yarn run cypress run`
31
32
 
33
+ ## Run Cypress tests (glib-web-npm)
34
+
35
+ 1. Clone and set up the backend repo (`glib-web`) because Cypress tests require matching `test_page/*` fixtures.
36
+ 2. In `glib-web`, link this package: `yarn link glib-web`.
37
+ 3. In project that use `glib-web`, start Rails: `bin/rails s` and `bin/vite dev` separately.
38
+ 4. In this repo, run tests: `yarn test`.
39
+
32
40
  ## Best practices
33
41
 
34
42
  - To prevent circular dependencies between components:
@@ -7,7 +7,7 @@ description: >
7
7
  inputs:
8
8
  doc_dir: doc/garage/test_page
9
9
  test_dir: cypress/e2e/glib-web
10
- test_helper: cypress/helper.ts
10
+ test_helper: cypress/helper.js
11
11
  ai_test_prompt: |
12
12
  Generate a Cypress e2e test for the glib test page: {{page_slug}}.
13
13
  Inputs you can use:
@@ -79,10 +79,10 @@ steps:
79
79
 
80
80
  - id: collect-test-page-slugs
81
81
  instruction: |
82
- Scan every *.cy.ts under {{inputs.test_dir}} and extract all occurrences of
82
+ Scan every *.cy.js under {{inputs.test_dir}} and extract all occurrences of
83
83
  testPageUrl('...'). Collect the string values into test_page_slugs.
84
84
  If a file contains no testPageUrl calls, derive a fallback slug by:
85
- - Removing the .cy.ts suffix.
85
+ - Removing the .cy.js suffix.
86
86
  - Converting camelCase to snake_case.
87
87
  Output: test_page_slugs.
88
88
 
@@ -102,8 +102,8 @@ steps:
102
102
  - id: scaffold-missing-tests
103
103
  instruction: |
104
104
  For each slug in missing_page_slugs:
105
- 1) Derive a filename by converting snake_case to camelCase and append ".cy.ts".
106
- Example: file_upload_new -> fileUploadNew.cy.ts
105
+ 1) Derive a filename by converting snake_case to camelCase and append ".cy.js".
106
+ Example: file_upload_new -> fileUploadNew.cy.js
107
107
  2) Create {{inputs.test_dir}}/<filename> if it does not already exist.
108
108
  3) Write generated_tests_map[<slug>] to the file.
109
109
  Output: created_test_files.
@@ -33,7 +33,7 @@ const installChartkick = () => {
33
33
  const multipleDataSeries = (dataSeries) => {
34
34
  return dataSeries.map((value) => {
35
35
  let points = null;
36
- if (Array.isArray(value.points)) {
36
+ if (TypeUtils.isArray(value.points)) {
37
37
  points = value.points.reduce((prev, curr) => {
38
38
  return Object.assign(prev, { [curr.x]: curr.y });
39
39
  }, {});
@@ -73,7 +73,11 @@ const getOrCreateTooltip = (chart) => {
73
73
 
74
74
  const externalTooltipHandler = (multiple, dataSeries) => {
75
75
  return (context) => {
76
- const tooltipData = getData(multiple, dataSeries, context.tooltip.dataPoints[0]);
76
+ const tooltipContext = TypeUtils.isObject(context) && TypeUtils.isObject(context.tooltip) ? context.tooltip : null;
77
+ const dataPoints = TypeUtils.isObject(tooltipContext) ? tooltipContext.dataPoints : null;
78
+ if (!TypeUtils.isArray(dataPoints) || dataPoints.length === 0) return;
79
+
80
+ const tooltipData = getData(multiple, dataSeries, dataPoints[0]);
77
81
 
78
82
  if (!tooltipData) return;
79
83
 
@@ -111,9 +115,13 @@ const externalTooltipHandler = (multiple, dataSeries) => {
111
115
  };
112
116
 
113
117
  const getData = (multiple, dataSeries, context) => {
118
+ if (!TypeUtils.isArray(dataSeries) || !TypeUtils.isObject(context)) return null;
119
+
114
120
  const { dataIndex, datasetIndex } = context;
121
+ if (!TypeUtils.isNumber(dataIndex) || !TypeUtils.isNumber(datasetIndex)) return null;
122
+
115
123
  const dataset = dataSeries[datasetIndex];
116
- if (multiple && Array.isArray(dataset.points) && dataset.points[dataIndex]) {
124
+ if (multiple && TypeUtils.isObject(dataset) && TypeUtils.isArray(dataset.points) && dataset.points[dataIndex]) {
117
125
  return dataset.points[dataIndex];
118
126
  }
119
127
  if (!multiple && dataSeries[dataIndex]) {
@@ -123,15 +131,16 @@ const getData = (multiple, dataSeries, context) => {
123
131
 
124
132
  function useChart({ dataSeries, spec, multiple = true }) {
125
133
  installChartkick();
134
+ const normalizedDataSeries = TypeUtils.isArray(dataSeries) ? dataSeries : [];
126
135
  const isDonut = [spec.styleClasses].flat().includes('donut');
127
136
  const { datalabels, centerLabel, customTooltip } = spec.plugins || {};
128
137
  const legend = spec.legend || { display: true };
129
138
 
130
139
  let series = null;
131
140
  if (multiple) {
132
- series = computed(() => multipleDataSeries(dataSeries));
141
+ series = computed(() => multipleDataSeries(normalizedDataSeries));
133
142
  } else {
134
- series = computed(() => singleDataSeries(dataSeries));
143
+ series = computed(() => singleDataSeries(normalizedDataSeries));
135
144
  }
136
145
 
137
146
  let colors = undefined;
@@ -175,12 +184,15 @@ function useChart({ dataSeries, spec, multiple = true }) {
175
184
  }
176
185
 
177
186
  const { dataIndex, datasetIndex } = context;
178
- const dataset = dataSeries[datasetIndex];
179
- if (multiple && Array.isArray(dataset.points) && dataset.points[dataIndex].label) {
180
- val = dataset.points[dataIndex].label;
187
+ const dataset = normalizedDataSeries[datasetIndex];
188
+ if (multiple && TypeUtils.isObject(dataset) && TypeUtils.isArray(dataset.points)) {
189
+ const point = dataset.points[dataIndex];
190
+ if (TypeUtils.isObject(point) && point.label) {
191
+ val = point.label;
192
+ }
181
193
  }
182
- if (!multiple && dataSeries[dataIndex].label) {
183
- val = dataSeries[dataIndex].label;
194
+ if (!multiple && TypeUtils.isObject(normalizedDataSeries[dataIndex]) && normalizedDataSeries[dataIndex].label) {
195
+ val = normalizedDataSeries[dataIndex].label;
184
196
  }
185
197
 
186
198
  return val;
@@ -195,7 +207,7 @@ function useChart({ dataSeries, spec, multiple = true }) {
195
207
  if (customTooltip) {
196
208
  options.plugins.tooltip = {
197
209
  enabled: false,
198
- external: externalTooltipHandler(multiple, dataSeries)
210
+ external: externalTooltipHandler(multiple, normalizedDataSeries)
199
211
  };
200
212
  }
201
213
 
@@ -15,7 +15,6 @@
15
15
  /> -->
16
16
 
17
17
  <!-- <fields-latLong v-else-if="spec.view == 'fields/latLong-v1'" :spec="spec" /> -->
18
- <fields-googlePlace v-else-if="spec.view == 'fields/googlePlace-v1'" ref="delegate" :spec="spec" />
19
18
 
20
19
  <!-- <panels-responsive v-else-if="spec.view == 'panels/scroll-v1'" :spec="spec" /> -->
21
20
 
@@ -72,7 +71,6 @@ import TextAreaField from "./fields/textarea.vue";
72
71
  const RichTextField2 = defineAsyncComponent(() => import("./fields/richText2.vue"));
73
72
  // import NewRichTextField from "./fields/newRichText.vue";
74
73
  const FileField = defineAsyncComponent(() => import("./fields/file.vue"));
75
- const MultiUploadField = defineAsyncComponent(() => import("./fields/multiUpload.vue"));
76
74
  const UploadField = defineAsyncComponent(() => import('./fields/upload.vue'));
77
75
  import SignField from "./fields/sign.vue";
78
76
  import SelectField from "./fields/_select.vue";
@@ -85,7 +83,6 @@ import CheckField from "./fields/check.vue";
85
83
  import DateField from "./fields/date.vue";
86
84
  import DateTimeField from "./fields/datetime.vue";
87
85
  const LocationField = defineAsyncComponent(() => import("./fields/location.vue"));
88
- import GooglePlaceField from "./fields/googlePlace.vue";
89
86
  // import DynamicGroupField from "./fields/dynamicGroup.vue";
90
87
  import DynamicGroupField from "./fields/dynamicGroup2.vue";
91
88
  import StripeTokenField from "./fields/stripeToken.vue";
@@ -179,7 +176,6 @@ export default {
179
176
  "fields-richText": RichTextField2,
180
177
  // "fields-newRichText": NewRichTextField,
181
178
  "fields-file": FileField,
182
- "fields-multiUpload": MultiUploadField,
183
179
  "fields-upload": UploadField,
184
180
  "fields-sign": SignField,
185
181
  "fields-select": SelectField,
@@ -192,7 +188,6 @@ export default {
192
188
  "fields-date": DateField,
193
189
  "fields-datetime": DateTimeField,
194
190
  "fields-location": LocationField,
195
- "fields-googlePlace": GooglePlaceField,
196
191
  "fields-dynamicGroup": DynamicGroupField,
197
192
  "fields-stripeToken": StripeTokenField,
198
193
  "fields-stripeExternalAccount": StripeExternalAccount,
@@ -19,6 +19,14 @@ import GlibBase from "../base/glibBase.js";
19
19
  import { defineComponent, ref, provide, toRef } from "vue";
20
20
  import { useGlibInput } from "../composable/form";
21
21
  import { useGlibSelectable, watchNoneOfAbove } from "../composable/selectable";
22
+ import { isArray, isNull, isString } from "../../utils/type";
23
+
24
+ const normalizeValue = (value) => {
25
+ if (isNull(value)) return [];
26
+ if (isArray(value)) return value;
27
+ if (isString(value)) return value.length > 0 ? [value] : [];
28
+ return [value];
29
+ };
22
30
 
23
31
  export default defineComponent({
24
32
  extends: GlibBase,
@@ -39,7 +47,7 @@ export default defineComponent({
39
47
  const parentSpec = props.spec;
40
48
  provide('parentSpec', parentSpec);
41
49
 
42
- const fieldModel = toRef(props.spec.value);
50
+ const fieldModel = toRef(normalizeValue(props.spec.value));
43
51
  provide('parentModel', fieldModel);
44
52
 
45
53
  useGlibInput({ props });
@@ -60,18 +68,17 @@ export default defineComponent({
60
68
  }
61
69
 
62
70
  // watch(
63
- // () => props.spec,
64
- // (spec) => {
65
- // fieldModel.value = [spec.value || []].flat();
66
- // },
67
- // { immediate: true, deep: true }
71
+ // () => props.spec.value,
72
+ // (value) => {
73
+ // fieldModel.value = normalizeValue(value);
74
+ // }
68
75
  // );
69
76
 
70
77
  return { options, fieldModel, checkAll };
71
78
  },
72
79
  computed: {
73
80
  values() {
74
- return this.fieldModel || [];
81
+ return normalizeValue(this.fieldModel);
75
82
  }
76
83
  },
77
84
  watch: {
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div v-if="loadIf" :style="$styles()" :class="$classes()">
2
+ <div v-if="loadIf" :style="$styles()" :class="[$classes(), { 'glib-quill-disabled': inputDisabled }]">
3
3
  <div ref="editor"></div>
4
4
  <input type="hidden" :name="fieldName" :value="producedValue" />
5
5
  <template v-if="Object.keys(files).length > 0">
@@ -51,6 +51,7 @@ import { useFileUtils } from "../composable/file";
51
51
  import { setBusyWhenUploading, uploadFiles } from "../composable/upload";
52
52
  import dom from "../../utils/dom";
53
53
  import RawText from "./rawText.vue";
54
+ import { isBoolean } from "../../utils/type";
54
55
 
55
56
  const { Item, makeKey } = useFileUtils();
56
57
 
@@ -74,6 +75,15 @@ export default defineComponent({
74
75
  const files = ref({});
75
76
  setBusyWhenUploading({ files });
76
77
 
78
+ const inputDisabled = computed(() => {
79
+ const disabled = instance.proxy.inputDisabled;
80
+ return isBoolean(disabled) ? disabled : false;
81
+ });
82
+ const isReadOnly = computed(() => {
83
+ const readOnly = props.spec.readOnly;
84
+ return (isBoolean(readOnly) ? readOnly : false) || inputDisabled.value;
85
+ });
86
+
77
87
 
78
88
  function sanitizedValue() {
79
89
  if (!quill) return props.spec.value || '';
@@ -254,11 +264,12 @@ export default defineComponent({
254
264
  }
255
265
  onMounted(() => {
256
266
  quill = new Quill(editor.value, {
257
- readOnly: props.spec.readOnly,
267
+ readOnly: isReadOnly.value,
258
268
  placeholder: props.spec.placeholder,
259
269
  theme: 'snow',
260
270
  modules
261
271
  });
272
+ quill.enable(!isReadOnly.value);
262
273
 
263
274
  let value = props.spec.value;
264
275
  switch (accept.value) {
@@ -296,7 +307,12 @@ export default defineComponent({
296
307
  }
297
308
  });
298
309
 
299
- return { producedValue, editor, files, rawTextProps };
310
+ watch(isReadOnly, (readOnly) => {
311
+ if (!quill) return;
312
+ quill.enable(!readOnly);
313
+ });
314
+
315
+ return { producedValue, editor, files, rawTextProps, inputDisabled };
300
316
  }
301
317
  });
302
318
  </script>
@@ -344,4 +360,18 @@ export default defineComponent({
344
360
  max-height: 300px;
345
361
  overflow-y: auto;
346
362
  }
363
+
364
+ .glib-quill-disabled .ql-editor {
365
+ caret-color: transparent;
366
+ cursor: not-allowed;
367
+ }
368
+
369
+ .glib-quill-disabled .ql-toolbar {
370
+ opacity: var(--v-disabled-opacity);
371
+ cursor: not-allowed;
372
+ }
373
+
374
+ .glib-quill-disabled .ql-container {
375
+ opacity: var(--v-disabled-opacity);
376
+ }
347
377
  </style>
@@ -29,9 +29,11 @@ const childSpec = computed(() => {
29
29
  return Object.assign({}, props.spec, { placeholderView: null }, props.spec.placeholderView);
30
30
  } else if (props.spec.inputView) {
31
31
  return Object.assign({}, props.spec, { inputView: null }, props.spec.inputView);
32
- } else {
33
- return Object.assign({}, props.spec, { multiProgressView: null }, props.spec.placeholderView);
32
+ } else if (props.spec.multiProgressView) {
33
+ return Object.assign({}, props.spec, { multiProgressView: null }, props.spec.multiProgressView);
34
34
  }
35
+
36
+ return props.spec;
35
37
  });
36
38
 
37
39
  function trigger() {
@@ -43,4 +45,4 @@ function reset() {
43
45
  }
44
46
 
45
47
  defineExpose({trigger, reset})
46
- </script>
48
+ </script>
@@ -131,7 +131,6 @@ export default {
131
131
  const forceUpdate = (Math.random() + 1).toString(36).substring(7);
132
132
  if (item.view.startsWith('charts/')) return forceUpdate;
133
133
  if (item.view.startsWith('fields/richText')) return forceUpdate;
134
- if (item.view.startsWith('fields/multiUpload')) return forceUpdate;
135
134
  if (item.view.startsWith('panels/custom')) return forceUpdate;
136
135
 
137
136
  const childViewLength = item.childViews ? item.childViews.length : 0;
@@ -1,100 +1,129 @@
1
1
  <template>
2
- <!-- Placement options:
3
- | 'top'
4
- | 'top-start'
5
- | 'top-end'
6
- | 'right'
7
- | 'right-start'
8
- | 'right-end'
9
- | 'bottom'
10
- | 'bottom-start'
11
- | 'bottom-end'
12
- | 'left'
13
- | 'left-start'
14
- | 'left-end'
2
+ <!-- Placement options:
3
+ | 'top'
4
+ | 'top-start'
5
+ | 'top-end'
6
+ | 'right'
7
+ | 'right-start'
8
+ | 'right-end'
9
+ | 'bottom'
10
+ | 'bottom-start'
11
+ | 'bottom-end'
12
+ | 'left'
13
+ | 'left-start'
14
+ | 'left-end'
15
15
  -->
16
16
 
17
- <common-responsive v-if="toggle" :key="key" ref="container" :class="`views-popovers ${spec.styleClass}`"
18
- :spec="spec.body" />
19
-
17
+ <common-responsive v-if="toggle" :key="key" ref="container" :class="`views-popovers ${spec.styleClass}`"
18
+ :spec="popoverBody" />
20
19
  </template>
21
20
 
22
21
  <script>
23
22
  import { popovers } from "../store";
24
23
  import bus from "../utils/eventBus";
25
24
  import { driver } from "driver.js";
26
- import 'driver.js/dist/driver.css';
25
+ import "driver.js/dist/driver.css";
27
26
  import { strandom } from "./helper";
28
27
  import { APP_ID } from "..";
29
28
  import GlibBase from "./base/glibBase.js";
29
+ import * as TypeUtils from "../utils/type";
30
30
 
31
31
  export default {
32
32
  extends: GlibBase,
33
- props: ['spec', 'reference', 'placeholder', 'styleClass'],
34
- data() {
35
- const allowClose = this.spec.overlay ? this.spec.overlay.closeOnFocus : true;
36
- return {
37
- key: null,
38
- toggle: true,
39
- driverObj: driver({
40
- allowClose,
41
- onDestroyed: () => {
42
- this.close();
43
- }
44
- }),
45
- };
33
+ props: ["spec", "reference", "placeholder", "styleClass"],
34
+ data() {
35
+ const allowClose = this.spec.overlay ? this.spec.overlay.closeOnFocus : true;
36
+ return {
37
+ key: null,
38
+ toggle: true,
39
+ driverObj: driver({
40
+ allowClose,
41
+ onDestroyed: () => {
42
+ this.close();
43
+ }
44
+ }),
45
+ busOpenHandler: null,
46
+ busCloseHandler: null,
47
+ onAppClick: null,
48
+ onResize: null,
49
+ body: null,
50
+ };
51
+ },
52
+ computed: {
53
+ popoverBody() {
54
+ if (TypeUtils.isNotNull(this.body)) {
55
+ return this.body;
56
+ }
57
+ return this.spec.body;
58
+ }
59
+ },
60
+ mounted() {
61
+ popovers.value.push(this);
62
+ this.busOpenHandler = (body) => {
63
+ this.body = body;
64
+ this.key = strandom();
65
+ };
66
+ bus.$on(`popovers/open-${this.spec.key}`, this.busOpenHandler);
67
+ },
68
+ methods: {
69
+ $mounted() {
70
+ const appEl = document.getElementById(APP_ID);
71
+ this.busCloseHandler = () => {
72
+ if (appEl) {
73
+ appEl.removeEventListener("click", this.onAppClick);
74
+ }
75
+ this.close();
76
+ };
77
+ bus.$once(`popover/close-${this.spec.key}`, this.busCloseHandler);
78
+ if (!this.spec.persistent) {
79
+ this.onAppClick = this.handleClose;
80
+ if (appEl) {
81
+ appEl.addEventListener("click", this.onAppClick);
82
+ }
83
+ this.onResize = () => this.close();
84
+ window.addEventListener("resize", this.onResize);
85
+ }
86
+ if (this.spec.overlay) {
87
+ this.driverObj.highlight({ element: this.reference });
88
+ }
46
89
  },
47
- mounted() {
48
- popovers.value.push(this);
49
- bus.$on(`popovers/open-${this.spec.key}`, (body) => {
50
- Object.assign(this.spec, { body });
51
- this.key = strandom();
52
- });
90
+ $tearDown() {
91
+ if (TypeUtils.isFunction(this.busCloseHandler)) {
92
+ bus.$off(`popover/close-${this.spec.key}`, this.busCloseHandler);
93
+ }
94
+ if (TypeUtils.isFunction(this.busOpenHandler)) {
95
+ bus.$off(`popovers/open-${this.spec.key}`, this.busOpenHandler);
96
+ }
97
+ if (!this.spec.persistent) {
98
+ const appEl = document.getElementById(APP_ID);
99
+ if (TypeUtils.isFunction(this.onAppClick) && appEl) {
100
+ appEl.removeEventListener("click", this.onAppClick);
101
+ }
102
+ if (TypeUtils.isFunction(this.onResize)) {
103
+ window.removeEventListener("resize", this.onResize);
104
+ }
105
+ }
53
106
  },
54
- methods: {
55
- $mounted() {
56
- const appEl = document.getElementById(APP_ID);
57
- bus.$once(`popover/close-${this.spec.key}`, () => {
58
- appEl.removeEventListener('click', this.handleClose);
59
- this.close();
60
- });
61
- if (!this.spec.persistent) {
62
- appEl.addEventListener('click', this.handleClose);
63
- window.addEventListener('resize', () => this.close());
64
- }
65
- if (this.spec.overlay) {
66
- this.driverObj.highlight({ element: this.reference });
67
- }
68
-
69
- },
70
- $tearDown() {
71
- bus.$off(`popover/close-${this.spec.key}`);
72
- bus.$off(`popover/open-${this.spec.key}`);
73
- if (!this.spec.persistent) {
74
- appEl.removeEventListener('click', this.handleClose);
75
- window.removeEventListener('resize', () => this.close());
76
- }
77
- },
78
- handleClose(event) {
79
- let element = null;
80
- if (this.$refs.container) {
81
- element = this.$refs.container.$el;
82
- } else {
83
- element = this.$el;
84
- }
85
- const isClickInside = element.contains(event.target);
107
+ handleClose(event) {
108
+ let element = null;
109
+ if (this.$refs.container) {
110
+ element = this.$refs.container.$el;
111
+ } else {
112
+ element = this.$el;
113
+ }
114
+ const isClickInside = element.contains(event.target);
86
115
 
87
- if (!isClickInside) {
88
- this.close();
89
- }
90
- },
91
- close() {
92
- if (this.placeholder) this.placeholder.remove();
93
- if (this.driverObj) this.driverObj.destroy();
94
- this.toggle = false;
95
- popovers.value.remove(this);
96
- }
116
+ if (!isClickInside) {
117
+ this.close();
118
+ }
119
+ },
120
+ close() {
121
+ if (this.placeholder) this.placeholder.remove();
122
+ if (this.driverObj) this.driverObj.destroy();
123
+ this.toggle = false;
124
+ popovers.value.remove(this);
97
125
  }
126
+ }
98
127
  };
99
128
  </script>
100
129
 
@@ -2,14 +2,14 @@ import inputUpload from "../../components/fields/inputUpload.vue";
2
2
  import Uploader from "../../utils/glibDirectUpload";
3
3
  import { mountWithGlib, restoreUploaderStartStub, setupGlibGlobals } from "./testUtils";
4
4
 
5
- const buildSpec = (overrides: Record<string, unknown> = {}) => ({
5
+ const buildSpec = (overrides = {}) => ({
6
6
  name: "user[file]",
7
7
  label: "Upload file",
8
8
  accepts: { fileType: "txt" },
9
9
  ...overrides,
10
10
  });
11
11
 
12
- const mountComponent = (spec: Record<string, unknown>) => {
12
+ const mountComponent = (spec) => {
13
13
  mountWithGlib(inputUpload, spec);
14
14
  };
15
15
 
@@ -24,7 +24,7 @@ describe("inputUpload", () => {
24
24
 
25
25
  it("uploads via direct upload and sets hidden signed ids", () => {
26
26
  cy.stub(Uploader.prototype, "start")
27
- .callsFake((callback: (error: unknown, blob: { signed_id: string }) => void) => {
27
+ .callsFake((callback) => {
28
28
  callback(null, { signed_id: "signed-123" });
29
29
  })
30
30
  .as("directUploadStart");
@@ -2,7 +2,7 @@ import multiUpload from "../../components/fields/multiUpload.vue";
2
2
  import Uploader from "../../utils/glibDirectUpload";
3
3
  import { mountWithGlib, restoreUploaderStartStub, setupGlibGlobals } from "./testUtils";
4
4
 
5
- const buildSpec = (overrides: Record<string, unknown> = {}) => ({
5
+ const buildSpec = (overrides = {}) => ({
6
6
  name: "user[files][]",
7
7
  accepts: { fileType: "txt" },
8
8
  placeholder: "Drop files",
@@ -10,7 +10,7 @@ const buildSpec = (overrides: Record<string, unknown> = {}) => ({
10
10
  ...overrides,
11
11
  });
12
12
 
13
- const mountComponent = (spec: Record<string, unknown>) => {
13
+ const mountComponent = (spec) => {
14
14
  mountWithGlib(multiUpload, spec);
15
15
  };
16
16
 
@@ -25,7 +25,7 @@ describe("multiUpload", () => {
25
25
 
26
26
  it("uploads via direct upload and sets hidden signed ids", () => {
27
27
  cy.stub(Uploader.prototype, "start")
28
- .callsFake((callback: (error: unknown, blob: { signed_id: string }) => void) => {
28
+ .callsFake((callback) => {
29
29
  callback(null, { signed_id: "signed-123" });
30
30
  })
31
31
  .as("directUploadStart");
@@ -2,7 +2,7 @@ import placeholderUpload from "../../components/fields/placeholderUpload.vue";
2
2
  import Uploader from "../../utils/glibDirectUpload";
3
3
  import { mountWithGlib, restoreUploaderStartStub, setupGlibGlobals } from "./testUtils";
4
4
 
5
- const buildSpec = (overrides: Record<string, unknown> = {}) => ({
5
+ const buildSpec = (overrides = {}) => ({
6
6
  name: "user[file]",
7
7
  type: "image",
8
8
  width: 120,
@@ -12,7 +12,7 @@ const buildSpec = (overrides: Record<string, unknown> = {}) => ({
12
12
  ...overrides,
13
13
  });
14
14
 
15
- const mountComponent = (spec: Record<string, unknown>) => {
15
+ const mountComponent = (spec) => {
16
16
  mountWithGlib(placeholderUpload, spec);
17
17
  };
18
18
 
@@ -27,7 +27,7 @@ describe("placeholderUpload", () => {
27
27
 
28
28
  it("uploads via direct upload and sets hidden signed id", () => {
29
29
  cy.stub(Uploader.prototype, "start")
30
- .callsFake((callback: (error: unknown, blob: { signed_id: string }) => void) => {
30
+ .callsFake((callback) => {
31
31
  callback(null, { signed_id: "signed-123" });
32
32
  })
33
33
  .as("directUploadStart");