cloud-web-corejs 1.0.54-dev.685 → 1.0.54-dev.687

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,306 @@
1
+ <template>
2
+ <div class="table-dynamic-field-editor">
3
+ <!-- 后台字段(动态生成):字段定义本身由后台查询下发 -->
4
+ <el-divider class="custom-divider">后台字段(动态生成)</el-divider>
5
+
6
+ <el-form-item label="启用后台字段">
7
+ <el-switch v-model="optionModel.dynamicSchemaEnabled"></el-switch>
8
+ <div class="tip-text">字段由后台查询下发,无需在设计器预先配置</div>
9
+ </el-form-item>
10
+
11
+ <template v-if="optionModel.dynamicSchemaEnabled">
12
+ <el-form-item label="脚本编码">
13
+ <el-input
14
+ v-model="optionModel.dynamicSchemaScriptCode"
15
+ size="mini"
16
+ placeholder="scriptCode 或 formCode/scriptCode"
17
+ ></el-input>
18
+ </el-form-item>
19
+ <el-form-item label="额外参数">
20
+ <a
21
+ href="javascript:void(0);"
22
+ class="a-link link-oneLind"
23
+ @click="editSchemaScriptParam"
24
+ >
25
+ <span>{{ optionModel.dynamicSchemaScriptParam }}</span>
26
+ <i class="el-icon-edit"></i>
27
+ </a>
28
+ <div class="tip-text">
29
+ 格式: return { bizType:
30
+ formModel.type }
31
+ </div>
32
+ </el-form-item>
33
+ <el-form-item label="转换脚本">
34
+ <a
35
+ href="javascript:void(0);"
36
+ class="a-link link-oneLind"
37
+ @click="editSchemaConvert"
38
+ >
39
+ <span>{{ optionModel.dynamicSchemaConvert }}</span>
40
+ <i class="el-icon-edit"></i>
41
+ </a>
42
+ <div class="tip-text">
43
+ 可选。入参 res,返回标准字段定义数组;不填时默认取 res.objx(数组)或
44
+ res.objx.fields / res.objx.columns
45
+ </div>
46
+ </el-form-item>
47
+ <el-form-item label="生成模式">
48
+ <el-radio-group v-model="optionModel.dynamicSchemaMode" size="mini">
49
+ <el-radio-button label="append">追加</el-radio-button>
50
+ <el-radio-button label="replace">替换</el-radio-button>
51
+ <el-radio-button label="anchor">锚点插入</el-radio-button>
52
+ </el-radio-group>
53
+ <div class="tip-text">
54
+ 追加=保留已配字段并在其后生成;替换=清空已配行后全部由后台生成;锚点插入=插到设计期某占位行位置
55
+ </div>
56
+ </el-form-item>
57
+
58
+ <template v-if="optionModel.dynamicSchemaMode === 'anchor'">
59
+ <el-form-item label="占位锚点行">
60
+ <el-select
61
+ v-model="optionModel.dynamicSchemaAnchorRowId"
62
+ size="mini"
63
+ style="width: 100%"
64
+ placeholder="选择设计期的占位行"
65
+ >
66
+ <el-option
67
+ v-for="r in rowOptions"
68
+ :key="r.value"
69
+ :label="r.label"
70
+ :value="r.value"
71
+ ></el-option>
72
+ </el-select>
73
+ <div class="tip-text">建议预留一个空行作为占位锚点</div>
74
+ </el-form-item>
75
+ <el-form-item label="插入位置">
76
+ <el-radio-group
77
+ v-model="optionModel.dynamicSchemaAnchorPosition"
78
+ size="mini"
79
+ >
80
+ <el-radio-button label="replace">替换占位行</el-radio-button>
81
+ <el-radio-button label="before">之前</el-radio-button>
82
+ <el-radio-button label="after">之后</el-radio-button>
83
+ </el-radio-group>
84
+ </el-form-item>
85
+ <el-form-item label="继承行布局">
86
+ <el-switch
87
+ v-model="optionModel.dynamicSchemaInheritLayout"
88
+ ></el-switch>
89
+ <div class="tip-text">
90
+ 开启后生成行沿用占位行的单元格数量/宽度/跨列,否则按"每行列数"平铺
91
+ </div>
92
+ </el-form-item>
93
+ </template>
94
+
95
+ <el-form-item
96
+ label="每行列数"
97
+ v-if="
98
+ optionModel.dynamicSchemaMode !== 'anchor' ||
99
+ !optionModel.dynamicSchemaInheritLayout
100
+ "
101
+ >
102
+ <el-input-number
103
+ v-model="optionModel.dynamicSchemaColumns"
104
+ :min="1"
105
+ :max="12"
106
+ size="mini"
107
+ ></el-input-number>
108
+ </el-form-item>
109
+ </template>
110
+
111
+ <div class="tip-text scope-tip">
112
+ 字段「显隐/必填/只读/禁用/取值」等动态规则请到「表单设置 -
113
+ 动态字段规则」统一配置
114
+ </div>
115
+
116
+ <el-dialog
117
+ title="额外参数"
118
+ :visible.sync="scriptParamDialogVisible"
119
+ v-if="scriptParamDialogVisible"
120
+ :show-close="true"
121
+ custom-class="dialog-style list-dialog"
122
+ v-dialog-drag
123
+ :close-on-click-modal="false"
124
+ :close-on-press-escape="false"
125
+ :destroy-on-close="true"
126
+ :append-to-body="true"
127
+ :modal-append-to-body="true"
128
+ >
129
+ <div class="cont">
130
+ <code-editor
131
+ :mode="'javascript'"
132
+ :readonly="false"
133
+ v-model="editingScriptParam"
134
+ ref="schemaScriptParamEditor"
135
+ ></code-editor>
136
+ </div>
137
+ <div slot="footer" class="dialog-footer">
138
+ <el-button
139
+ @click="scriptParamDialogVisible = false"
140
+ class="button-sty"
141
+ icon="el-icon-close"
142
+ >
143
+ {{ i18nt("designer.hint.cancel") }}
144
+ </el-button>
145
+ <el-button
146
+ type="primary"
147
+ @click="saveSchemaScriptParam"
148
+ class="button-sty"
149
+ icon="el-icon-check"
150
+ >
151
+ {{ i18nt("designer.hint.confirm") }}
152
+ </el-button>
153
+ </div>
154
+ </el-dialog>
155
+
156
+ <el-dialog
157
+ title="转换脚本"
158
+ :visible.sync="convertDialogVisible"
159
+ v-if="convertDialogVisible"
160
+ :show-close="true"
161
+ custom-class="dialog-style list-dialog"
162
+ v-dialog-drag
163
+ :close-on-click-modal="false"
164
+ :close-on-press-escape="false"
165
+ :destroy-on-close="true"
166
+ :append-to-body="true"
167
+ :modal-append-to-body="true"
168
+ >
169
+ <div class="cont">
170
+ <code-editor
171
+ :mode="'javascript'"
172
+ :readonly="false"
173
+ v-model="editingConvert"
174
+ ref="schemaConvertEditor"
175
+ ></code-editor>
176
+ </div>
177
+ <div slot="footer" class="dialog-footer">
178
+ <el-button
179
+ @click="convertDialogVisible = false"
180
+ class="button-sty"
181
+ icon="el-icon-close"
182
+ >
183
+ {{ i18nt("designer.hint.cancel") }}
184
+ </el-button>
185
+ <el-button
186
+ type="primary"
187
+ @click="saveSchemaConvert"
188
+ class="button-sty"
189
+ icon="el-icon-check"
190
+ >
191
+ {{ i18nt("designer.hint.confirm") }}
192
+ </el-button>
193
+ </div>
194
+ </el-dialog>
195
+ </div>
196
+ </template>
197
+
198
+ <script>
199
+ import i18n from "../../../../../../components/xform/utils/i18n";
200
+
201
+ export default {
202
+ name: "table-dynamicField-editor",
203
+ mixins: [i18n],
204
+ props: {
205
+ designer: Object,
206
+ selectedWidget: Object,
207
+ optionModel: Object,
208
+ },
209
+ data() {
210
+ return {
211
+ scriptParamDialogVisible: false,
212
+ convertDialogVisible: false,
213
+ editingScriptParam: "",
214
+ editingConvert: "",
215
+ };
216
+ },
217
+ computed: {
218
+ rowOptions() {
219
+ const rows = (this.selectedWidget && this.selectedWidget.rows) || [];
220
+ return rows.map((row, idx) => {
221
+ const fields = [];
222
+ (row.cols || []).forEach((cell) => {
223
+ this.collectFields(cell.widgetList || [], fields);
224
+ });
225
+ const names = fields
226
+ .map((w) => w.options.label || w.options.name)
227
+ .filter((n) => !!n);
228
+ const preview = names.length ? names.join("、") : "空行";
229
+ return { label: "第" + (idx + 1) + "行:" + preview, value: row.id };
230
+ });
231
+ },
232
+ },
233
+ methods: {
234
+ editSchemaScriptParam() {
235
+ this.editingScriptParam = this.optionModel.dynamicSchemaScriptParam || "";
236
+ this.scriptParamDialogVisible = true;
237
+ },
238
+ saveSchemaScriptParam() {
239
+ if (!this.validateEditor("schemaScriptParamEditor")) return;
240
+ this.optionModel.dynamicSchemaScriptParam = this.editingScriptParam;
241
+ this.scriptParamDialogVisible = false;
242
+ },
243
+ editSchemaConvert() {
244
+ this.editingConvert = this.optionModel.dynamicSchemaConvert || "";
245
+ this.convertDialogVisible = true;
246
+ },
247
+ saveSchemaConvert() {
248
+ if (!this.validateEditor("schemaConvertEditor")) return;
249
+ this.optionModel.dynamicSchemaConvert = this.editingConvert;
250
+ this.convertDialogVisible = false;
251
+ },
252
+ validateEditor(refName) {
253
+ const editor = this.$refs[refName];
254
+ if (!editor) return true;
255
+ const codeHints = editor.getEditorAnnotations();
256
+ let syntaxErrorFlag = false;
257
+ if (codeHints && codeHints.length > 0) {
258
+ codeHints.forEach((chItem) => {
259
+ if (chItem.type === "error") {
260
+ syntaxErrorFlag = true;
261
+ }
262
+ });
263
+ if (syntaxErrorFlag) {
264
+ this.$message.error(
265
+ this.i18nt("designer.setting.syntaxCheckWarning")
266
+ );
267
+ return false;
268
+ }
269
+ }
270
+ return true;
271
+ },
272
+ collectFields(list, out) {
273
+ (list || []).forEach((w) => {
274
+ if (!w) return;
275
+ if (w.category === "container") {
276
+ if (Array.isArray(w.rows)) {
277
+ w.rows.forEach((row) =>
278
+ this.collectFields((row && row.cols) || [], out)
279
+ );
280
+ }
281
+ ["cols", "tabs", "widgetList", "panes", "buttonWidgetList"].forEach(
282
+ (k) => {
283
+ if (Array.isArray(w[k])) this.collectFields(w[k], out);
284
+ }
285
+ );
286
+ } else if (w.formItemFlag) {
287
+ out.push(w);
288
+ }
289
+ });
290
+ },
291
+ },
292
+ };
293
+ </script>
294
+
295
+ <style lang="scss" scoped>
296
+ .tip-text {
297
+ font-size: 12px;
298
+ color: #909399;
299
+ line-height: 1.4;
300
+ margin-top: 2px;
301
+ }
302
+
303
+ .scope-tip {
304
+ margin-top: 10px;
305
+ }
306
+ </style>
@@ -107,6 +107,7 @@ const COMMON_PROPERTIES = {
107
107
  detailPaneContainer: "detail-pane-editor",
108
108
  vabSearchField: "vabSearchField-editor",
109
109
  fullWidth: "table-fullWidth-editor",
110
+ dynamicSchemaEnabled: "table-dynamicField-editor",
110
111
  dataTable: "data-table-editor",
111
112
  accessUrl: "accessUrl-editor",
112
113
  formulaEnabled: "formulaEnabled-editor",
@@ -31,6 +31,24 @@ export const containers = [
31
31
  customClass: "",
32
32
  styleTableClass: "",
33
33
  fullWidth: false,
34
+ // 后台字段定义模式:字段本身由后台查询下发(适用于字段不固定、无法在设计器预配的场景)
35
+ dynamicSchemaEnabled: false,
36
+ // 后台脚本编码(支持 "formCode/scriptCode"),返回标准字段定义数组
37
+ dynamicSchemaScriptCode: null,
38
+ // 额外请求参数(JSON 字符串)
39
+ dynamicSchemaScriptParam: null,
40
+ // 转换脚本:将后台响应转成标准字段定义数组(可选,入参 res)
41
+ dynamicSchemaConvert: null,
42
+ // 自动布局每行列数
43
+ dynamicSchemaColumns: 4,
44
+ // 生成模式:append=追加到已配行之后,replace=替换全部行,anchor=按设计期占位行定位插入
45
+ dynamicSchemaMode: "append",
46
+ // anchor 模式:占位锚点行的 id(设计期某一行)
47
+ dynamicSchemaAnchorRowId: null,
48
+ // anchor 模式:插入位置 replace=替换占位行 / before=占位行之前 / after=占位行之后
49
+ dynamicSchemaAnchorPosition: "replace",
50
+ // anchor 模式:是否继承占位行的列布局(单元格数量/宽度/跨列),否则按 dynamicSchemaColumns 平铺
51
+ dynamicSchemaInheritLayout: true,
34
52
  ...defaultWfConfig,
35
53
  },
36
54
  },
@@ -0,0 +1,285 @@
1
+ /**
2
+ * 动态字段规则引擎(纯逻辑,无 Vue 上下文)。
3
+ *
4
+ * 供「表单级动态规则(form-setting)」与「容器级动态字段(container-item)」共用:
5
+ * - 目标收集:字段 + 命名容器,建立 目标key -> { widget, refKey, isContainer } 映射与设计基线
6
+ * - 规则计算:本地条件/逻辑求值,输出每个目标的最终状态
7
+ * - 状态落地:通过 getWidgetRef 应用到运行时组件,无 ref 时回退改 schema
8
+ */
9
+ import {
10
+ traverseFieldWidgets,
11
+ traverseContainerWidgets,
12
+ traverseFieldWidgetsOfContainer,
13
+ } from "../../../../components/xform/utils/util";
14
+
15
+ // 布局内格容器,不作为可控目标
16
+ const EXCLUDED_CONTAINER_TYPES = ["grid-col", "table-cell", "h5-table-cell"];
17
+
18
+ export function getModelKey(w) {
19
+ return (w.options.keyNameEnabled && w.options.keyName) || w.options.name;
20
+ }
21
+
22
+ function addFieldTo(map, baseline, w) {
23
+ if (!w || !w.options) return;
24
+ const key = getModelKey(w);
25
+ if (!key) return;
26
+ map[key] = { widget: w, refKey: w.options.name, isContainer: false };
27
+ baseline[key] = {
28
+ visible: !w.options.hidden,
29
+ required: !!w.options.required,
30
+ readonly: !!w.options.readonly,
31
+ disabled: !!w.options.disabled,
32
+ };
33
+ }
34
+
35
+ function addContainerTo(map, baseline, w) {
36
+ if (!w || !w.options || !w.options.name) return;
37
+ if (EXCLUDED_CONTAINER_TYPES.indexOf(w.type) > -1) return;
38
+ const key = w.options.name;
39
+ if (map[key]) return;
40
+ map[key] = { widget: w, refKey: key, isContainer: true };
41
+ baseline[key] = { visible: !w.options.hidden };
42
+ }
43
+
44
+ // 整个表单范围:字段 + 命名容器(跳过弹窗/抽屉内部)
45
+ export function buildFormTargetMap(widgetList) {
46
+ const map = {};
47
+ const baseline = {};
48
+ traverseFieldWidgets(widgetList || [], (w) => addFieldTo(map, baseline, w));
49
+ traverseContainerWidgets(
50
+ widgetList || [],
51
+ (w) => addContainerTo(map, baseline, w),
52
+ true
53
+ );
54
+ return { map, baseline };
55
+ }
56
+
57
+ // 单个容器范围:容器内字段 + 命名子容器
58
+ export function buildContainerTargetMap(container) {
59
+ const map = {};
60
+ const baseline = {};
61
+ traverseFieldWidgetsOfContainer(container, (w) => addFieldTo(map, baseline, w));
62
+ collectNamedContainersInContainer(container).forEach((w) =>
63
+ addContainerTo(map, baseline, w)
64
+ );
65
+ return { map, baseline };
66
+ }
67
+
68
+ // 递归收集指定容器内「命名的子容器」
69
+ export function collectNamedContainersInContainer(root) {
70
+ const out = [];
71
+ const walk = (w, isRoot) => {
72
+ if (!w || w.category !== "container") return;
73
+ if (
74
+ !isRoot
75
+ && w.options
76
+ && w.options.name
77
+ && EXCLUDED_CONTAINER_TYPES.indexOf(w.type) === -1
78
+ ) {
79
+ out.push(w);
80
+ }
81
+ if (Array.isArray(w.rows)) {
82
+ w.rows.forEach((row) => {
83
+ (row.cols || []).forEach((cell) => walk(cell, false));
84
+ });
85
+ }
86
+ ["cols", "tabs", "widgetList", "panes", "buttonWidgetList"].forEach((k) => {
87
+ if (Array.isArray(w[k])) w[k].forEach((c) => walk(c, false));
88
+ });
89
+ };
90
+ walk(root, true);
91
+ return out;
92
+ }
93
+
94
+ /* ------------------- 层级下拉选项(供设计器) ------------------- */
95
+ // 构建带层级的目标候选(字段 + 容器),按表单树 DFS 顺序输出,附带 depth。
96
+ // 布局内格(grid-col/table-cell 等)不单独成节点,仅作为透明层向下展开。
97
+ function makeTreeBuilder() {
98
+ const nodes = [];
99
+ const visitList = (list, depth) => {
100
+ (list || []).forEach((w) => visit(w, depth));
101
+ };
102
+ const visitChildren = (w, depth) => {
103
+ if (Array.isArray(w.rows)) {
104
+ w.rows.forEach((row) => visitList((row && row.cols) || [], depth));
105
+ }
106
+ ["cols", "tabs", "widgetList", "panes", "buttonWidgetList"].forEach((k) => {
107
+ if (Array.isArray(w[k])) visitList(w[k], depth);
108
+ });
109
+ };
110
+ const visit = (w, depth) => {
111
+ if (!w) return;
112
+ if (w.category === "container") {
113
+ // 布局内格:透明展开,深度不变
114
+ if (EXCLUDED_CONTAINER_TYPES.indexOf(w.type) > -1) {
115
+ visitChildren(w, depth);
116
+ return;
117
+ }
118
+ const name = w.options && w.options.name;
119
+ nodes.push({
120
+ value: name || "__c_" + w.id,
121
+ baseLabel: (w.options && (w.options.label || name)) || w.type,
122
+ depth,
123
+ isContainer: true,
124
+ hasName: !!name,
125
+ type: w.type,
126
+ });
127
+ visitChildren(w, depth + 1);
128
+ } else if (w.formItemFlag) {
129
+ const key = getModelKey(w);
130
+ if (!key) return;
131
+ nodes.push({
132
+ value: key,
133
+ baseLabel: (w.options.label || key) + " (" + key + ")",
134
+ depth,
135
+ isContainer: false,
136
+ hasName: true,
137
+ type: w.type,
138
+ });
139
+ }
140
+ };
141
+ return { nodes, visitList, visitChildren };
142
+ }
143
+
144
+ // 整个表单范围的层级候选
145
+ export function buildWidgetTreeOptions(rootList) {
146
+ const b = makeTreeBuilder();
147
+ b.visitList(rootList || [], 0);
148
+ return b.nodes;
149
+ }
150
+
151
+ // 单个容器范围的层级候选(不含容器自身,从其子级开始)
152
+ export function buildContainerTreeOptions(container) {
153
+ const b = makeTreeBuilder();
154
+ if (container) b.visitChildren(container, 0);
155
+ return b.nodes;
156
+ }
157
+
158
+ /* ------------------- 规则计算 ------------------- */
159
+ export function computeLocalStates(rules, baseline, formModel) {
160
+ const list = rules || [];
161
+ const states = {};
162
+ const ensure = (key) => {
163
+ if (!states[key]) {
164
+ const base = baseline[key] || { visible: true };
165
+ states[key] = Object.assign({}, base);
166
+ }
167
+ return states[key];
168
+ };
169
+ // 先把所有规则涉及的目标置为基线,未命中时即还原
170
+ list.forEach((rule) => {
171
+ (rule.targets || []).forEach((t) => t.field && ensure(t.field));
172
+ });
173
+ list.forEach((rule) => {
174
+ if (!evalRule(rule, formModel)) return;
175
+ (rule.targets || []).forEach((t) => {
176
+ if (!t.field) return;
177
+ const s = ensure(t.field);
178
+ if (t.visible !== undefined && t.visible !== null) s.visible = !!t.visible;
179
+ if (t.required !== undefined && t.required !== null) {
180
+ s.required = !!t.required;
181
+ }
182
+ if (t.readonly !== undefined && t.readonly !== null) {
183
+ s.readonly = !!t.readonly;
184
+ }
185
+ if (t.disabled !== undefined && t.disabled !== null) {
186
+ s.disabled = !!t.disabled;
187
+ }
188
+ });
189
+ });
190
+ return states;
191
+ }
192
+
193
+ export function evalRule(rule, model) {
194
+ const conds = (rule && rule.conditions) || [];
195
+ if (!conds.length) return true;
196
+ if (rule.logic === "or") {
197
+ return conds.some((c) => evalCondition(c, model));
198
+ }
199
+ return conds.every((c) => evalCondition(c, model));
200
+ }
201
+
202
+ export function evalCondition(cond, model) {
203
+ if (!cond || !cond.field) return false;
204
+ const actual = model ? model[cond.field] : undefined;
205
+ const expected = cond.value;
206
+ const isEmpty = (v) =>
207
+ v === undefined
208
+ || v === null
209
+ || v === ""
210
+ || (Array.isArray(v) && v.length === 0);
211
+ const toList = (v) =>
212
+ String(v == null ? "" : v)
213
+ .split(",")
214
+ .map((s) => s.trim())
215
+ .filter((s) => s !== "");
216
+ switch (cond.operator) {
217
+ case "eq":
218
+ return String(actual) === String(expected);
219
+ case "ne":
220
+ return String(actual) !== String(expected);
221
+ case "gt":
222
+ return Number(actual) > Number(expected);
223
+ case "lt":
224
+ return Number(actual) < Number(expected);
225
+ case "ge":
226
+ return Number(actual) >= Number(expected);
227
+ case "le":
228
+ return Number(actual) <= Number(expected);
229
+ case "in":
230
+ return toList(expected).includes(String(actual));
231
+ case "nin":
232
+ return !toList(expected).includes(String(actual));
233
+ case "includes":
234
+ return Array.isArray(actual)
235
+ ? actual.map(String).includes(String(expected))
236
+ : String(actual == null ? "" : actual).indexOf(String(expected)) > -1;
237
+ case "empty":
238
+ return isEmpty(actual);
239
+ case "notEmpty":
240
+ return !isEmpty(actual);
241
+ default:
242
+ return false;
243
+ }
244
+ }
245
+
246
+ /* ------------------- 状态落地 ------------------- */
247
+ // entry: { widget, refKey, isContainer };getWidgetRef: (name) => 运行时组件ref
248
+ export function applyTargetState(entry, state, getWidgetRef) {
249
+ if (!entry || !state) return;
250
+ const widget = entry.widget;
251
+ const isContainer = entry.isContainer;
252
+ const ref = getWidgetRef ? getWidgetRef(entry.refKey) : null;
253
+ const hasVisible = state.visible !== undefined && state.visible !== null;
254
+ if (ref) {
255
+ if (hasVisible && ref.setHidden) ref.setHidden(!state.visible);
256
+ if (isContainer) return;
257
+ if (state.required !== undefined && state.required !== null && ref.setRequired) {
258
+ ref.setRequired(!!state.required);
259
+ }
260
+ if (state.readonly !== undefined && state.readonly !== null && ref.setReadonly) {
261
+ ref.setReadonly(!!state.readonly);
262
+ }
263
+ if (state.disabled !== undefined && state.disabled !== null && ref.setDisabled) {
264
+ ref.setDisabled(!!state.disabled);
265
+ }
266
+ if (state.options !== undefined && state.options !== null && ref.setOptions) {
267
+ ref.setOptions(state.options);
268
+ }
269
+ if (state.value !== undefined && ref.setValue) {
270
+ ref.setValue(state.value);
271
+ }
272
+ } else {
273
+ if (hasVisible) widget.options.hidden = !state.visible;
274
+ if (isContainer) return;
275
+ if (state.required !== undefined && state.required !== null) {
276
+ widget.options.required = !!state.required;
277
+ }
278
+ if (state.readonly !== undefined && state.readonly !== null) {
279
+ widget.options.readonly = !!state.readonly;
280
+ }
281
+ if (state.disabled !== undefined && state.disabled !== null) {
282
+ widget.options.disabled = !!state.disabled;
283
+ }
284
+ }
285
+ }