rb-document-form-constructor 0.9.26 → 0.10.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rb-document-form-constructor",
3
- "version": "0.9.26",
3
+ "version": "0.10.0",
4
4
  "description": "",
5
5
  "main": "dist/rb-document-form-constructor.ssr.js",
6
6
  "browser": "dist/rb-document-form-constructor.esm.js",
@@ -20,6 +20,7 @@
20
20
  "build:unpkg": "cross-env kNODE_ENV=production rollup --config build/rollup.config.js --format iife"
21
21
  },
22
22
  "dependencies": {
23
+ "ace-builds": "^1.43.6",
23
24
  "bootstrap": "^4.5.0",
24
25
  "bootstrap-vue": "^2.15.0",
25
26
  "rb-bv-components": "^2.5.63",
@@ -58,4 +59,4 @@
58
59
  "engines": {
59
60
  "node": ">=12"
60
61
  }
61
- }
62
+ }
@@ -4,6 +4,8 @@
4
4
  modal-class="rb-field-rule-form-modal"
5
5
  size="lg"
6
6
  @ok.prevent="onOk"
7
+ @shown="onModalShown"
8
+ @hidden="onModalHidden"
7
9
  ok-title="Сохранить правило"
8
10
  cancel-variant="outline-gray"
9
11
  cancel-title="Отмена">
@@ -112,12 +114,7 @@
112
114
  </b-dropdown-item>
113
115
  </b-dropdown>
114
116
  </b-button-toolbar>
115
- <b-form-textarea v-model="innerRule.script"
116
- :state="state.script"
117
- :invalid-feedback="state.script_feedback"
118
- rows="8"
119
- ref="scriptInput"
120
- ></b-form-textarea>
117
+ <div class="rb-script-editor" ref="scriptEditor"></div>
121
118
  </div>
122
119
  </b-form-group>
123
120
  </b-col>
@@ -138,6 +135,10 @@ import {UtFormConfig} from "../utils/UtFormConfig";
138
135
  import {UtFormConstructor} from "../utils/UtFormConstructor";
139
136
  import DocForm from "./DocForm";
140
137
  import {UtRandom} from "@/utils/UtRandom.js";
138
+ import ace from "ace-builds/src-noconflict/ace";
139
+ import "ace-builds/src-noconflict/mode-javascript";
140
+ import "ace-builds/src-noconflict/theme-textmate";
141
+ import "ace-builds/src-noconflict/ext-language_tools";
141
142
 
142
143
  export default {
143
144
  name: 'FieldRuleFormModal',
@@ -155,6 +156,7 @@ export default {
155
156
  state: this.getDefaultState(),
156
157
  innerFormConfig: null,
157
158
  innerRule: null,
159
+ scriptEditorInstance: null,
158
160
  }
159
161
  },
160
162
  computed: {
@@ -172,16 +174,108 @@ export default {
172
174
  formConfig() {
173
175
  this.copyToInnerFormConfig();
174
176
  },
175
- rule() {
176
- if (this.rule) {
177
- this.innerRule = this.rule;
178
- } else {
179
- this.innerRule = this.getDefaultRule();
177
+ rule: {
178
+ immediate: true,
179
+ handler() {
180
+ if (this.rule) {
181
+ this.innerRule = this.rule;
182
+ } else {
183
+ this.innerRule = this.getDefaultRule();
184
+ }
180
185
  }
181
-
182
186
  }
183
187
  },
184
188
  methods: {
189
+ initScriptEditor() {
190
+ this.scriptEditorInstance = ace.edit(this.$refs.scriptEditor);
191
+ this.scriptEditorInstance.setTheme("ace/theme/textmate");
192
+ this.scriptEditorInstance.session.setMode("ace/mode/javascript");
193
+ this.scriptEditorInstance.session.setUseSoftTabs(true);
194
+ this.scriptEditorInstance.session.setTabSize(2);
195
+ this.scriptEditorInstance.session.setUseWrapMode(true);
196
+ this.scriptEditorInstance.setFontSize(13);
197
+ this.scriptEditorInstance.setShowPrintMargin(false);
198
+ this.scriptEditorInstance.setOption("scrollPastEnd", 0);
199
+ this.scriptEditorInstance.setOptions({
200
+ enableBasicAutocompletion: true,
201
+ enableLiveAutocompletion: true,
202
+ enableSnippets: true,
203
+ });
204
+ this.scriptEditorInstance.setValue(
205
+ this.innerRule && this.innerRule.script ? this.innerRule.script : '',
206
+ -1
207
+ );
208
+ const languageTools = ace.require("ace/ext/language_tools");
209
+ const customCompleter = {
210
+ getCompletions: (editor, session, pos, prefix, callback) => {
211
+ const completions = [
212
+ {
213
+ caption: "doc",
214
+ value: "doc",
215
+ meta: "model",
216
+ score: 1000,
217
+ },
218
+ {
219
+ caption: "value",
220
+ value: "doc['field_name']",
221
+ meta: "current field value",
222
+ score: 1000,
223
+ },
224
+ {
225
+ caption: "form",
226
+ value: "form",
227
+ meta: "form component",
228
+ score: 1000,
229
+ },
230
+ {
231
+ caption: "allFields",
232
+ value: "const allFields = utils.getFields(form.formConfig);",
233
+ meta: "function",
234
+ score: 1000,
235
+ },
236
+ ];
237
+
238
+ callback(null, completions);
239
+ },
240
+ };
241
+ const defaultCompleters = [
242
+ languageTools.textCompleter,
243
+ languageTools.keyWordCompleter,
244
+ languageTools.snippetCompleter,
245
+ ].filter(Boolean);
246
+ this.scriptEditorInstance.completers = [...defaultCompleters, customCompleter];
247
+
248
+ this.scriptEditorInstance.on('change', () => {
249
+ if (this.innerRule) {
250
+ this.innerRule.script = this.scriptEditorInstance.getValue();
251
+ this.validateFields('script');
252
+ }
253
+ });
254
+ },
255
+ syncScriptEditorValue() {
256
+ if (!this.scriptEditorInstance || !this.innerRule) {
257
+ return;
258
+ }
259
+
260
+ const editorValue = this.scriptEditorInstance.getValue();
261
+ const nextValue = this.innerRule.script != null ? this.innerRule.script : '';
262
+ if (editorValue !== nextValue) {
263
+ this.scriptEditorInstance.setValue(nextValue, -1);
264
+ }
265
+ },
266
+ getScriptCaretPosition() {
267
+ if (this.scriptEditorInstance) {
268
+ const session = this.scriptEditorInstance.session;
269
+ const cursor = this.scriptEditorInstance.getCursorPosition();
270
+ if (!session || !cursor) {
271
+ return null;
272
+ }
273
+
274
+ return session.doc.positionToIndex(cursor, 0);
275
+ }
276
+
277
+ return this.$refs.scriptInput ? this.$refs.scriptInput.selectionStart : null;
278
+ },
185
279
  validateFields(fieldName) {
186
280
  let fields = fieldName ? [fieldName] : ['name', 'event', 'script'];
187
281
  fields.forEach(field => {
@@ -241,19 +335,32 @@ export default {
241
335
  this.innerRule = null;
242
336
  },
243
337
  addVariableToScript(varName) {
244
- let caretPosition = this.$refs.scriptInput.selectionStart;
338
+ let caretPosition = this.getScriptCaretPosition();
245
339
  this.insertTextToScript(varName, caretPosition);
246
340
  },
247
341
  addSetVariableToScript(field) {
248
- let caretPosition = this.$refs.scriptInput.selectionStart;
342
+ let caretPosition = this.getScriptCaretPosition();
249
343
  this.insertTextToScript(`doc['${field.name}'] = Значение;`, caretPosition);
250
344
  },
251
345
  addCallInputFunction(field) {
252
- let caretPosition = this.$refs.scriptInput.selectionStart;
346
+ let caretPosition = this.getScriptCaretPosition();
253
347
  this.insertTextToScript(`form.$refs['${field.name}'][0].Название функции();`, caretPosition);
254
348
  },
255
349
  insertTextToScript(text, position) {
256
- position = position != null ? position : this.script.length;
350
+ if (this.scriptEditorInstance) {
351
+ const session = this.scriptEditorInstance.session;
352
+ if (!session) {
353
+ return;
354
+ }
355
+ const offset = position != null ? position : this.scriptEditorInstance.getValue().length;
356
+ const insertPosition = session.doc.indexToPosition(offset, 0);
357
+ session.insert(insertPosition, text);
358
+ this.scriptEditorInstance.focus();
359
+ return;
360
+ }
361
+
362
+ const scriptValue = this.innerRule && this.innerRule.script ? this.innerRule.script : '';
363
+ position = position != null ? position : scriptValue.length;
257
364
  this.innerRule.script = this.innerRule.script != null ? this.innerRule.script : '';
258
365
  let scriptSplit = this.innerRule.script.split('');
259
366
  scriptSplit.splice(position, 0, text);
@@ -264,6 +371,21 @@ export default {
264
371
  if (rule) {
265
372
  Object.assign(this.innerRule, rule);
266
373
  this.innerRule.script = this.innerRule.script.trim();
374
+ this.syncScriptEditorValue();
375
+ }
376
+ },
377
+ onModalShown() {
378
+ this.initScriptEditor();
379
+ this.syncScriptEditorValue();
380
+
381
+ if (this.scriptEditorInstance) {
382
+ this.scriptEditorInstance.focus();
383
+ }
384
+ },
385
+ onModalHidden() {
386
+ if (this.scriptEditorInstance) {
387
+ this.scriptEditorInstance.dispose();
388
+ this.scriptEditorInstance = null;
267
389
  }
268
390
  },
269
391
  onOk() {
@@ -285,3 +407,12 @@ export default {
285
407
  }
286
408
  }
287
409
  </script>
410
+
411
+ <style scoped>
412
+ .rb-script-editor {
413
+ min-height: 220px;
414
+ border: 1px solid #ced4da;
415
+ border-radius: 0.25rem;
416
+ margin-top: 0.5rem;
417
+ }
418
+ </style>