quasar 2.18.3 → 2.18.5

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 (135) hide show
  1. package/dist/api/QField.json +1 -1
  2. package/dist/api/QFile.json +1 -1
  3. package/dist/api/QInput.json +1 -1
  4. package/dist/api/QSelect.json +1 -1
  5. package/dist/icon-set/bootstrap-icons.umd.prod.js +1 -1
  6. package/dist/icon-set/eva-icons.umd.prod.js +1 -1
  7. package/dist/icon-set/fontawesome-v5-pro.umd.prod.js +1 -1
  8. package/dist/icon-set/fontawesome-v5.umd.prod.js +1 -1
  9. package/dist/icon-set/fontawesome-v6-pro.umd.prod.js +1 -1
  10. package/dist/icon-set/fontawesome-v6.umd.prod.js +1 -1
  11. package/dist/icon-set/ionicons-v4.umd.prod.js +1 -1
  12. package/dist/icon-set/line-awesome.umd.prod.js +1 -1
  13. package/dist/icon-set/material-icons-outlined.umd.prod.js +1 -1
  14. package/dist/icon-set/material-icons-round.umd.prod.js +1 -1
  15. package/dist/icon-set/material-icons-sharp.umd.prod.js +1 -1
  16. package/dist/icon-set/material-icons.umd.prod.js +1 -1
  17. package/dist/icon-set/material-symbols-outlined.umd.prod.js +1 -1
  18. package/dist/icon-set/material-symbols-rounded.umd.prod.js +1 -1
  19. package/dist/icon-set/material-symbols-sharp.umd.prod.js +1 -1
  20. package/dist/icon-set/mdi-v3.umd.prod.js +1 -1
  21. package/dist/icon-set/mdi-v4.umd.prod.js +1 -1
  22. package/dist/icon-set/mdi-v5.umd.prod.js +1 -1
  23. package/dist/icon-set/mdi-v6.umd.prod.js +1 -1
  24. package/dist/icon-set/mdi-v7.umd.prod.js +1 -1
  25. package/dist/icon-set/svg-bootstrap-icons.umd.prod.js +1 -1
  26. package/dist/icon-set/svg-eva-icons.umd.prod.js +1 -1
  27. package/dist/icon-set/svg-fontawesome-v5.umd.prod.js +1 -1
  28. package/dist/icon-set/svg-fontawesome-v6.umd.prod.js +1 -1
  29. package/dist/icon-set/svg-ionicons-v4.umd.prod.js +1 -1
  30. package/dist/icon-set/svg-ionicons-v5.umd.prod.js +1 -1
  31. package/dist/icon-set/svg-ionicons-v6.umd.prod.js +1 -1
  32. package/dist/icon-set/svg-line-awesome.umd.prod.js +1 -1
  33. package/dist/icon-set/svg-material-icons-outlined.umd.prod.js +1 -1
  34. package/dist/icon-set/svg-material-icons-round.umd.prod.js +1 -1
  35. package/dist/icon-set/svg-material-icons-sharp.umd.prod.js +1 -1
  36. package/dist/icon-set/svg-material-icons.umd.prod.js +1 -1
  37. package/dist/icon-set/svg-material-symbols-outlined.umd.prod.js +1 -1
  38. package/dist/icon-set/svg-material-symbols-rounded.umd.prod.js +1 -1
  39. package/dist/icon-set/svg-material-symbols-sharp.umd.prod.js +1 -1
  40. package/dist/icon-set/svg-mdi-v6.umd.prod.js +1 -1
  41. package/dist/icon-set/svg-mdi-v7.umd.prod.js +1 -1
  42. package/dist/icon-set/svg-themify.umd.prod.js +1 -1
  43. package/dist/icon-set/themify.umd.prod.js +1 -1
  44. package/dist/lang/ar-TN.umd.prod.js +1 -1
  45. package/dist/lang/ar.umd.prod.js +1 -1
  46. package/dist/lang/az-Latn.umd.prod.js +1 -1
  47. package/dist/lang/bg.umd.prod.js +1 -1
  48. package/dist/lang/bn.umd.prod.js +1 -1
  49. package/dist/lang/bs-BA.umd.prod.js +1 -1
  50. package/dist/lang/ca.umd.prod.js +1 -1
  51. package/dist/lang/cs.umd.prod.js +1 -1
  52. package/dist/lang/da.umd.prod.js +1 -1
  53. package/dist/lang/de-CH.umd.prod.js +1 -1
  54. package/dist/lang/de-DE.umd.prod.js +1 -1
  55. package/dist/lang/de.umd.prod.js +1 -1
  56. package/dist/lang/el.umd.prod.js +1 -1
  57. package/dist/lang/en-GB.umd.prod.js +1 -1
  58. package/dist/lang/en-US.umd.prod.js +1 -1
  59. package/dist/lang/eo.umd.prod.js +1 -1
  60. package/dist/lang/es.umd.prod.js +1 -1
  61. package/dist/lang/et.umd.prod.js +1 -1
  62. package/dist/lang/eu.umd.prod.js +1 -1
  63. package/dist/lang/fa-IR.umd.prod.js +1 -1
  64. package/dist/lang/fa.umd.prod.js +1 -1
  65. package/dist/lang/fi.umd.prod.js +1 -1
  66. package/dist/lang/fr.umd.prod.js +1 -1
  67. package/dist/lang/gn.umd.prod.js +1 -1
  68. package/dist/lang/he.umd.prod.js +1 -1
  69. package/dist/lang/hi.umd.prod.js +1 -1
  70. package/dist/lang/hr.umd.prod.js +1 -1
  71. package/dist/lang/hu.umd.prod.js +1 -1
  72. package/dist/lang/id.umd.prod.js +1 -1
  73. package/dist/lang/is.umd.prod.js +1 -1
  74. package/dist/lang/it.umd.prod.js +1 -1
  75. package/dist/lang/ja.umd.prod.js +1 -1
  76. package/dist/lang/kk.umd.prod.js +1 -1
  77. package/dist/lang/km.umd.prod.js +1 -1
  78. package/dist/lang/ko-KR.umd.prod.js +1 -1
  79. package/dist/lang/kur-CKB.umd.prod.js +1 -1
  80. package/dist/lang/lt.umd.prod.js +1 -1
  81. package/dist/lang/lu.umd.prod.js +1 -1
  82. package/dist/lang/lv.umd.prod.js +1 -1
  83. package/dist/lang/mk.umd.prod.js +1 -1
  84. package/dist/lang/ml.umd.prod.js +1 -1
  85. package/dist/lang/mm.umd.prod.js +1 -1
  86. package/dist/lang/ms-MY.umd.prod.js +1 -1
  87. package/dist/lang/ms.umd.prod.js +1 -1
  88. package/dist/lang/my.umd.prod.js +1 -1
  89. package/dist/lang/nb-NO.umd.prod.js +1 -1
  90. package/dist/lang/nl.umd.prod.js +1 -1
  91. package/dist/lang/pl.umd.prod.js +1 -1
  92. package/dist/lang/pt-BR.umd.prod.js +1 -1
  93. package/dist/lang/pt.umd.prod.js +1 -1
  94. package/dist/lang/ro.umd.prod.js +1 -1
  95. package/dist/lang/ru.umd.prod.js +1 -1
  96. package/dist/lang/sk.umd.prod.js +1 -1
  97. package/dist/lang/sl.umd.prod.js +1 -1
  98. package/dist/lang/sm.umd.prod.js +1 -1
  99. package/dist/lang/sq.umd.prod.js +1 -1
  100. package/dist/lang/sr-CYR.umd.prod.js +1 -1
  101. package/dist/lang/sr.umd.prod.js +1 -1
  102. package/dist/lang/sv.umd.prod.js +1 -1
  103. package/dist/lang/ta.umd.prod.js +1 -1
  104. package/dist/lang/th.umd.prod.js +1 -1
  105. package/dist/lang/tl.umd.prod.js +1 -1
  106. package/dist/lang/tr.umd.prod.js +1 -1
  107. package/dist/lang/ug.umd.prod.js +1 -1
  108. package/dist/lang/uk.umd.prod.js +1 -1
  109. package/dist/lang/ur-PK.umd.prod.js +1 -1
  110. package/dist/lang/uz-Cyrl.umd.prod.js +1 -1
  111. package/dist/lang/uz-Latn.umd.prod.js +1 -1
  112. package/dist/lang/vi.umd.prod.js +1 -1
  113. package/dist/lang/zh-CN.umd.prod.js +1 -1
  114. package/dist/lang/zh-TW.umd.prod.js +1 -1
  115. package/dist/quasar.client.js +408 -381
  116. package/dist/quasar.css +16 -10
  117. package/dist/quasar.prod.css +1 -1
  118. package/dist/quasar.rtl.css +17 -13
  119. package/dist/quasar.rtl.prod.css +1 -1
  120. package/dist/quasar.sass +21 -22
  121. package/dist/quasar.server.prod.cjs +20 -20
  122. package/dist/quasar.server.prod.js +20 -20
  123. package/dist/quasar.umd.js +61 -34
  124. package/dist/quasar.umd.prod.js +25 -25
  125. package/dist/types/index.d.ts +26 -0
  126. package/dist/vetur/quasar-attributes.json +1 -1
  127. package/dist/vetur/quasar-tags.json +1 -1
  128. package/dist/web-types/web-types.json +1 -1
  129. package/package.json +3 -3
  130. package/src/components/field/QField.sass +21 -22
  131. package/src/components/input/use-mask.js +46 -13
  132. package/src/components/input/use-mask.json +55 -4
  133. package/src/components/pagination/QPagination.js +15 -12
  134. package/src/composables/private.use-field/use-field.js +6 -6
  135. package/src/composables/private.use-validate/use-validate.json +6 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quasar",
3
- "version": "2.18.3",
3
+ "version": "2.18.5",
4
4
  "description": "Build high-performance VueJS user interfaces (SPA, PWA, SSR, Mobile and Desktop) in record time",
5
5
  "type": "module",
6
6
  "module": "dist/quasar.client.js",
@@ -76,8 +76,8 @@
76
76
  "tinyglobby": "^0.2.10",
77
77
  "typescript": "^5.6.2",
78
78
  "vue": "^3.5.5",
79
- "eslint-config-quasar": "0.0.3",
80
- "@quasar/extras": "1.17.0"
79
+ "@quasar/extras": "1.17.0",
80
+ "eslint-config-quasar": "0.0.3"
81
81
  },
82
82
  "vetur": {
83
83
  "tags": "dist/vetur/quasar-tags.json",
@@ -131,17 +131,6 @@ $field-transition-label-right-up: .324s cubic-bezier(.4,0,.2,1)
131
131
  -webkit-animation-name: q-autofill
132
132
  -webkit-animation-fill-mode: both
133
133
 
134
- &:-webkit-autofill + .q-field__label
135
- transform: translateY(-40%) scale(.75)
136
- &[type="color"],
137
- &[type="date"],
138
- &[type="datetime-local"],
139
- &[type="month"],
140
- &[type="time"],
141
- &[type="week"]
142
- + .q-field__label
143
- transform: translateY(-40%) scale(.75)
144
-
145
134
  &:invalid
146
135
  box-shadow: none
147
136
 
@@ -201,6 +190,17 @@ $field-transition-label-right-up: .324s cubic-bezier(.4,0,.2,1)
201
190
  transition: transform $field-transition, max-width $field-transition-label-right-up
202
191
  backface-visibility: hidden
203
192
 
193
+ &:has(+ :is(.q-field__native, .q-field__input):is(
194
+ :-webkit-autofill,
195
+ [type="color"],
196
+ [type="date"],
197
+ [type="datetime-local"],
198
+ [type="month"],
199
+ [type="time"],
200
+ [type="week"]
201
+ ))
202
+ transform: translateY(-40%) scale(.75)
203
+
204
204
  &--float .q-field__label
205
205
  max-width: 133%
206
206
  transform: translateY(-40%) scale(.75)
@@ -445,17 +445,16 @@ $field-transition-label-right-up: .324s cubic-bezier(.4,0,.2,1)
445
445
  &.q-field--float .q-field__label
446
446
  transform: translateY(-30%) scale(.75)
447
447
 
448
- .q-field__native, .q-field__input
449
- &:-webkit-autofill + .q-field__label
450
- transform: translateY(-30%) scale(.75)
451
- &[type="color"],
452
- &[type="date"],
453
- &[type="datetime-local"],
454
- &[type="month"],
455
- &[type="time"],
456
- &[type="week"]
457
- + .q-field__label
458
- transform: translateY(-30%) scale(.75)
448
+ .q-field__label:has(+ :is(.q-field__native, .q-field__input):is(
449
+ :-webkit-autofill,
450
+ [type="color"],
451
+ [type="date"],
452
+ [type="datetime-local"],
453
+ [type="month"],
454
+ [type="time"],
455
+ [type="week"]
456
+ ))
457
+ transform: translateY(-30%) scale(.75)
459
458
 
460
459
  &--borderless, &--standard
461
460
 
@@ -1,4 +1,4 @@
1
- import { ref, watch, nextTick } from 'vue'
1
+ import { ref, computed, watch, nextTick } from 'vue'
2
2
 
3
3
  import { shouldIgnoreKey } from '../../utils/private.keyboard/key-composition.js'
4
4
 
@@ -12,7 +12,7 @@ const NAMED_MASKS = {
12
12
  card: '#### #### #### ####'
13
13
  }
14
14
 
15
- const TOKENS = {
15
+ const { tokenMap: DEFAULT_TOKEN_MAP, tokenKeys: DEFAULT_TOKEN_MAP_KEYS } = getTokenMap({
16
16
  '#': { pattern: '[\\d]', negate: '[^\\d]' },
17
17
 
18
18
  S: { pattern: '[a-zA-Z]', negate: '[^a-zA-Z]' },
@@ -23,29 +23,62 @@ const TOKENS = {
23
23
 
24
24
  X: { pattern: '[0-9a-zA-Z]', negate: '[^0-9a-zA-Z]', transform: v => v.toLocaleUpperCase() },
25
25
  x: { pattern: '[0-9a-zA-Z]', negate: '[^0-9a-zA-Z]', transform: v => v.toLocaleLowerCase() }
26
- }
27
-
28
- const KEYS = Object.keys(TOKENS)
29
- KEYS.forEach(key => {
30
- TOKENS[ key ].regex = new RegExp(TOKENS[ key ].pattern)
31
26
  })
32
27
 
33
- const
34
- tokenRegexMask = new RegExp('\\\\([^.*+?^${}()|([\\]])|([.*+?^${}()|[\\]])|([' + KEYS.join('') + '])|(.)', 'g'),
35
- escRegex = /[.*+?^${}()|[\]\\]/g
28
+ function getTokenMap (tokens) {
29
+ const tokenKeys = Object.keys(tokens)
30
+ const tokenMap = {}
31
+
32
+ tokenKeys.forEach(key => {
33
+ const entry = tokens[ key ]
34
+ tokenMap[ key ] = {
35
+ ...entry,
36
+ regex: new RegExp(entry.pattern)
37
+ }
38
+ })
39
+
40
+ return { tokenMap, tokenKeys }
41
+ }
42
+
43
+ function getTokenRegexMask (keys) {
44
+ return new RegExp('\\\\([^.*+?^${}()|([\\]])|([.*+?^${}()|[\\]])|([' + keys.join('') + '])|(.)', 'g')
45
+ }
36
46
 
47
+ const escRegex = /[.*+?^${}()|[\]\\]/g
48
+ const DEFAULT_TOKEN_REGEX_MASK = getTokenRegexMask(DEFAULT_TOKEN_MAP_KEYS)
37
49
  const MARKER = String.fromCharCode(1)
38
50
 
39
51
  export const useMaskProps = {
40
52
  mask: String,
41
53
  reverseFillMask: Boolean,
42
54
  fillMask: [ Boolean, String ],
43
- unmaskedValue: Boolean
55
+ unmaskedValue: Boolean,
56
+ maskTokens: Object
44
57
  }
45
58
 
46
59
  export default function (props, emit, emitValue, inputRef) {
47
60
  let maskMarked, maskReplaced, computedMask, computedUnmask, pastedTextStart, selectionAnchor
48
61
 
62
+ const tokens = computed(() => {
63
+ if (props.maskTokens === void 0 || props.maskTokens === null) {
64
+ return {
65
+ tokenMap: DEFAULT_TOKEN_MAP,
66
+ tokenRegexMask: DEFAULT_TOKEN_REGEX_MASK
67
+ }
68
+ }
69
+
70
+ const { tokenMap: customTokens } = getTokenMap(props.maskTokens)
71
+ const tokenMap = {
72
+ ...DEFAULT_TOKEN_MAP,
73
+ ...customTokens
74
+ }
75
+
76
+ return {
77
+ tokenMap,
78
+ tokenRegexMask: getTokenRegexMask(Object.keys(tokenMap))
79
+ }
80
+ })
81
+
49
82
  const hasMask = ref(null)
50
83
  const innerValue = ref(getInitialMaskedValue())
51
84
 
@@ -137,9 +170,9 @@ export default function (props, emit, emitValue, inputRef) {
137
170
  unmaskChar = '',
138
171
  negateChar = ''
139
172
 
140
- localComputedMask.replace(tokenRegexMask, (_, char1, esc, token, char2) => {
173
+ localComputedMask.replace(tokens.value.tokenRegexMask, (_, char1, esc, token, char2) => {
141
174
  if (token !== void 0) {
142
- const c = TOKENS[ token ]
175
+ const c = tokens.value.tokenMap[ token ]
143
176
  mask.push(c)
144
177
  negateChar = c.negate
145
178
  if (firstMatch === true) {
@@ -6,26 +6,77 @@
6
6
  "examples": [
7
7
  "'###-##'", "'date'", "'datetime'", "'time'", "'fulltime'", "'phone'", "'card'"
8
8
  ],
9
- "category": "behavior"
9
+ "category": "mask"
10
10
  },
11
11
 
12
12
  "fill-mask": {
13
13
  "type": [ "Boolean", "String" ],
14
14
  "desc": "Fills string with specified characters (or underscore if value is not string) to fill mask's length",
15
15
  "examples": [ "true", "'0'", "'_'" ],
16
- "category": "behavior"
16
+ "category": "mask"
17
17
  },
18
18
 
19
19
  "reverse-fill-mask": {
20
20
  "type": "Boolean",
21
21
  "desc": "Fills string from the right side of the mask",
22
- "category": "behavior"
22
+ "category": "mask"
23
23
  },
24
24
 
25
25
  "unmasked-value": {
26
26
  "type": "Boolean",
27
27
  "desc": "Model will be unmasked (won't contain tokens/separation characters)",
28
- "category": "behavior"
28
+ "category": "mask"
29
+ },
30
+
31
+ "mask-tokens": {
32
+ "type": "Object",
33
+ "desc": "Object of custom mask tokens to be added on top of the default ones; Can also override any of the default ones",
34
+ "definition": {
35
+ "...tokenCharacter": {
36
+ "type": "Object",
37
+ "desc": "The definition for the current custom mask token",
38
+ "required": true,
39
+ "definition": {
40
+ "pattern": {
41
+ "type": "String",
42
+ "required": true,
43
+ "desc": "A string representing a regular expression to match against a single character",
44
+ "examples": [ "'[0-9]'", "'[a-zA-Z]'" ]
45
+ },
46
+ "negate": {
47
+ "type": "String",
48
+ "required": true,
49
+ "desc": "A string representing a regular expression to NOT match against a single character",
50
+ "examples": [ "'[^0-9]'", "'[^a-zA-Z]'" ]
51
+ },
52
+ "transform": {
53
+ "type": "Function",
54
+ "required": false,
55
+ "desc": "A function that takes the character as argument and returns the transformed character",
56
+ "examples": [ "v => v.toLocaleUpperCase()" ],
57
+ "params": {
58
+ "char": {
59
+ "type": "String",
60
+ "required": true,
61
+ "desc": "The character being transformed",
62
+ "examples": [ "'a'", "'1'" ]
63
+ }
64
+ },
65
+ "returns": {
66
+ "type": "String",
67
+ "desc": "The transformed character"
68
+ }
69
+ }
70
+ },
71
+ "examples": [
72
+ "{ pattern: '[0-4a-eA-E]', negate: '[^0-4a-eA-E]', transform: v => v.toLocaleUpperCase() }",
73
+ "{ pattern: '[5-8]', negate: '[^5-8]' }"
74
+ ]
75
+ }
76
+ },
77
+ "examples": [ "{ C: { pattern: '[0-4a-eA-E]', negate: '[^0-4a-eA-E]', transform: v => v.toLocaleUpperCase() } }" ],
78
+ "category": "mask",
79
+ "addedIn": "v2.18.4"
29
80
  }
30
81
  }
31
82
  }
@@ -264,18 +264,19 @@ export default createComponent({
264
264
  model.value = model.value + offset
265
265
  }
266
266
 
267
- const inputEvents = computed(() => {
268
- function updateModel () {
269
- model.value = newPage.value
270
- newPage.value = null
271
- }
267
+ function updateModel () {
268
+ model.value = newPage.value
269
+ newPage.value = null
270
+ $q.platform.is.mobile === true && document.activeElement.blur()
271
+ }
272
272
 
273
- return {
274
- 'onUpdate:modelValue': val => { newPage.value = val },
275
- onKeyup: e => { isKeyCode(e, 13) === true && updateModel() },
276
- onBlur: updateModel
277
- }
278
- })
273
+ function onInputValue (val) {
274
+ newPage.value = val
275
+ }
276
+
277
+ function onKeyup (e) {
278
+ isKeyCode(e, 13) === true && updateModel()
279
+ }
279
280
 
280
281
  function getBtn (cfg, page, active) {
281
282
  const data = {
@@ -441,7 +442,9 @@ export default createComponent({
441
442
  placeholder: inputPlaceholder.value,
442
443
  min: minProp.value,
443
444
  max: maxProp.value,
444
- ...inputEvents.value
445
+ 'onUpdate:modelValue': onInputValue,
446
+ onKeyup,
447
+ onBlur: updateModel
445
448
  })
446
449
  : h('div', {
447
450
  class: 'q-pagination__middle row justify-center'
@@ -440,6 +440,12 @@ export default function (state) {
440
440
  )
441
441
  }
442
442
 
443
+ hasLabel.value === true && node.push(
444
+ h('div', {
445
+ class: labelClass.value
446
+ }, hSlot(slots.label, props.label))
447
+ )
448
+
443
449
  if (state.getControl !== void 0) {
444
450
  node.push(state.getControl())
445
451
  }
@@ -459,12 +465,6 @@ export default function (state) {
459
465
  )
460
466
  }
461
467
 
462
- hasLabel.value === true && node.push(
463
- h('div', {
464
- class: labelClass.value
465
- }, hSlot(slots.label, props.label))
466
- )
467
-
468
468
  props.suffix !== void 0 && props.suffix !== null && node.push(
469
469
  h('div', {
470
470
  class: 'q-field__suffix no-pointer-events row items-center'
@@ -10,20 +10,20 @@
10
10
  "type": [ "Boolean", "null" ],
11
11
  "default": "null",
12
12
  "desc": "Does field have validation errors?",
13
- "category": "behavior"
13
+ "category": "validation"
14
14
  },
15
15
 
16
16
  "error-message": {
17
17
  "type": "String",
18
18
  "desc": "Validation error message (gets displayed only if 'error' is set to 'true')",
19
19
  "examples": [ "'Username must have at least 5 characters'" ],
20
- "category": "content"
20
+ "category": "validation"
21
21
  },
22
22
 
23
23
  "no-error-icon": {
24
24
  "type": "Boolean",
25
25
  "desc": "Hide error icon when there is an error",
26
- "category": "content"
26
+ "category": "validation"
27
27
  },
28
28
 
29
29
  "rules": {
@@ -35,13 +35,13 @@
35
35
  "[ 'fulltime' ]",
36
36
  "[ (val, rules) => rules.email(val) || 'Please enter a valid email address' ]"
37
37
  ],
38
- "category": "behavior"
38
+ "category": "validation"
39
39
  },
40
40
 
41
41
  "reactive-rules": {
42
42
  "type": "Boolean",
43
43
  "desc": "By default a change in the rules does not trigger a new validation until the model changes; If set to true then a change in the rules will trigger a validation; Has a performance penalty, so use it only when you really need it",
44
- "category": "behavior"
44
+ "category": "validation"
45
45
  },
46
46
 
47
47
  "lazy-rules": {
@@ -49,7 +49,7 @@
49
49
  "desc": "If set to boolean true then it checks validation status against the 'rules' only after field loses focus for first time; If set to 'ondemand' then it will trigger only when component's validate() method is manually called or when the wrapper QForm submits itself",
50
50
  "default": "false",
51
51
  "values": [ "true", "false", "'ondemand'" ],
52
- "category": "behavior"
52
+ "category": "validation"
53
53
  }
54
54
  },
55
55