ru.coon 2.5.64 → 2.5.65

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/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ # Version 2.5.65, [link](http://gitlab-dbr.sigma-it.local/dbr/ru.coon/-/commit/64478c87b5169b1d5be5b28bae8b82ada2477f32)
2
+ * ## Fixes
3
+ * <span style='color:red'> HT-7918 WindowWrap missing focus</span> ([0bdf38], [link](http://gitlab-dbr.sigma-it.local/dbr/ru.coon/-/commit/0bdf38c03dbd1cac10c9f2d8ea5d0786909d68e1))
4
+
5
+ * update: CHANGELOG.md ([4a4d82], [link](http://gitlab-dbr.sigma-it.local/dbr/ru.coon/-/commit/4a4d820afb7cfa7df56e325ba7435a3ecdfff712))
6
+
1
7
  # Version 2.5.64, [link](http://gitlab-dbr.sigma-it.local/dbr/ru.coon/-/commit/9f48777236abed76cf08cd5cef56e7f9be0dac63)
2
8
  * ## Features
3
9
  * <span style='color:green'>feat: HT-7955: focus CP before save action, set cell editing values in grids</span> ([4c6578], [link](http://gitlab-dbr.sigma-it.local/dbr/ru.coon/-/commit/4c6578c6873cd21c509de304494938276e7367a9))
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "name": "ru.coon"
5
5
  },
6
6
  "description": "",
7
- "version": "2.5.64",
7
+ "version": "2.5.65",
8
8
  "repository": {
9
9
  "type": "git",
10
10
  "url": "git+http://gitlab-dbr.sigma-it.local/dbr/ru.coon"
@@ -115,7 +115,7 @@ Ext.define('Coon.common.panel.WindowWrap', {
115
115
  }];
116
116
  }
117
117
  this.callParent();
118
- this.defaultFocus = this.readOnly ? undefined : (panel.defaultFocus || 'textfield[hidden=false][readOnly=false]');
118
+ this.setFocusTarget(panel);
119
119
  this.content = this.items.getAt(0);
120
120
  this.title = Ext.isEmpty(this.title) ? this.content.title : this.title;
121
121
  if (!Ext.isEmpty(this.content.wrapWindowResizeEvent)) {
@@ -167,6 +167,15 @@ Ext.define('Coon.common.panel.WindowWrap', {
167
167
  }
168
168
  },
169
169
 
170
+ setFocusTarget: function(panel) {
171
+ this.on('render', function() {
172
+ this.focus();
173
+ }, this);
174
+ this.on('focus', function() {
175
+ this.defaultFocus = this.readOnly ? undefined : (panel.defaultFocus || 'textfield[hidden=false][readOnly=false]');
176
+ }, this);
177
+ },
178
+
170
179
  wikiLink: function() {
171
180
  const context = (Ext.isFunction(this.content.getWikiContext) && this.content.getWikiContext()) || this.content.getXType();
172
181
  const panel = Ext.create('Coon.requests.wiki.WikiLinkView');
@@ -0,0 +1,896 @@
1
+ Ext.define('Coon.uielement.component.UiCPVisualEditor', {
2
+ extend: 'Ext.panel.Panel',
3
+ cls: 'UiCPVisualEditor',
4
+ alias: 'widget.UiCPVisualEditor',
5
+ xtype: 'UiCPVisualEditor',
6
+ header: false,
7
+ layout: 'border',
8
+ requires: [
9
+ 'Coon.uielement.component.UiCPVisualEditorConfigWindow'
10
+ ],
11
+ controller: {
12
+ defaultPixelsSize: 200,
13
+ bindingRegister: [],
14
+ plugins: [],
15
+ isTipOpened: false,
16
+ onTreeItemContextMenu: function(view, record, item, index, event, opt) {
17
+ this.onContextClick(event, item, {
18
+ 'cmp': this.getEditorPanel().down('[dataId=' + record.get('dataId') + ']'),
19
+ 'target': Ext.get(item.id).el,
20
+ });
21
+ return false;
22
+ },
23
+ deselectAllCmp: function() {
24
+ this.getEditorPanel().query('[dataId]').map((item) => {
25
+ if (item.el) {
26
+ item.el.dom.classList.remove('hover-item');
27
+ }
28
+ });
29
+ },
30
+ selectCmp: function(id) {
31
+ const cmp = this.getEditorPanel().down('[dataId=' + id + ']');
32
+ if (cmp && cmp.el) {
33
+ cmp.el.dom.classList.add('hover-item');
34
+ }
35
+ },
36
+ onTreeSelectionChange: function(tree, selection) {
37
+ this.deselectAllCmp();
38
+ if (selection.length) {
39
+ this.selectCmp(selection[0].get('dataId'));
40
+ }
41
+ },
42
+ getEditorPanel: function() {
43
+ return this.getView().down('[dataId=editorPanel]');
44
+ },
45
+ onRenderMainPanel: function() {
46
+ this.renderTemplate();
47
+ },
48
+ getFirstContainer: function(formData) {
49
+ return formData.find((item) => {
50
+ if (item.xtype === 'panel' || item.xtype === 'container') {
51
+ return item;
52
+ }
53
+ if (item.items && item.items.length) {
54
+ return this.getFirstContainer(item.items);
55
+ }
56
+ });
57
+ },
58
+ normaliseMainPluginsCfg: function(data) {
59
+ data.map((item) => {
60
+ if (item.cmpParams) {
61
+ if (item.cmpParams.mainPlugins && item.cmpParams.mainPlugins.length) {
62
+ this.plugins = item.cmpParams.mainPlugins;
63
+ delete item.cmpParams['mainPlugins'];
64
+ }
65
+ if (item.items && item.items.length) {
66
+ this.normaliseMainPluginsCfg(item.items);
67
+ }
68
+ }
69
+ });
70
+ },
71
+ renderTemplate: function(data) {
72
+ this.getEditorPanel().removeAll(true);
73
+ const formData = this.getTemplate(data);
74
+ const firstContainer = this.getFirstContainer(formData);
75
+ this.plugins = [];
76
+ this.normaliseMainPluginsCfg(formData);
77
+ if (this.plugins.length) {
78
+ firstContainer.plugins = this.plugins;
79
+ firstContainer.cmpParams.mainPlugins = this.plugins;
80
+ }
81
+ firstContainer['controller'] = {};
82
+ firstContainer['viewModel'] = {};
83
+ this.reloadTreeStore(formData);
84
+ try {
85
+ this.getEditorPanel().add(formData);
86
+ } catch (e) {
87
+ Ext.Msg.alert('Ошибка', e.message);
88
+ }
89
+ },
90
+ reloadTreeStore: function(formData) {
91
+ this.getView().down('[dataId=treeEditorPanel]').setRootNode(this.getNodeCfg(formData)[0]);
92
+ },
93
+ getNodeCfg: function(items) {
94
+ if (!items) {
95
+ return [];
96
+ }
97
+ return items.map((item) => {
98
+ const subItems = item.uiElementCd ? false : this.getNodeCfg(item.items);
99
+ let obj = {};
100
+ if (item.isContainer) {
101
+ obj = {leaf: false, children: []};
102
+ } else {
103
+ obj = {leaf: true};
104
+ }
105
+ const result = Ext.apply({
106
+ 'text': item.cmpParams.xtype,
107
+ 'dataId': item.cmpParams.dataId,
108
+ }, subItems && subItems.length ? {children: subItems, expanded: true} : obj);
109
+ return result;
110
+ });
111
+ },
112
+ getTemplate: function(data) {
113
+ if (!data) {
114
+ data = [this.getDefaultData()];
115
+ }
116
+ return data.map((item) => {
117
+ return this.getTemplateCmp(item);
118
+ });
119
+ },
120
+ getDefaultsByLayoutType: function(layout) {
121
+ switch (layout) {
122
+ case 'vbox':
123
+ return {width: '100%', flex: 1};
124
+ case 'hbox':
125
+ return {height: '100%', flex: 1};
126
+ }
127
+ },
128
+ modifyObject: function(obj) {
129
+ const newObject = {};
130
+ newObject.cmpParams = obj;
131
+ delete newObject.cmpParams['uiElementCd'];
132
+ // delete newObject.cmpParams['plugins'];
133
+ if (obj.xtype === 'ReportPanel') {
134
+ delete newObject.cmpParams['items'];
135
+ }
136
+ if (!obj.xtype) {
137
+ newObject.cmpParams.xtype = 'panel';
138
+ }
139
+
140
+ return newObject;
141
+ },
142
+ getTemplateCmp: function(cfg) {
143
+ const modifiedObject = typeof cfg.cmpParams !== 'undefined' ? cfg : this.modifyObject(cfg);
144
+ if (typeof modifiedObject.cmpParams.items !== 'undefined' && modifiedObject.cmpParams.items.length) {
145
+ modifiedObject.items = modifiedObject.cmpParams.items;
146
+ delete modifiedObject.cmpParams['items'];
147
+ }
148
+ if (!modifiedObject.cmpParams.dataId) {
149
+ modifiedObject.cmpParams.dataId = Ext.id() + '-interface-node';
150
+ }
151
+ const layout = typeof modifiedObject.cmpParams.layout === 'undefined' ? 'fit' :
152
+ modifiedObject.cmpParams.layout === 'object' ? modifiedObject.cmpParams.layout.type : modifiedObject.cmpParams.layout;
153
+ const newCmp = Ext.apply({
154
+ 'defaults': this.getDefaultsByLayoutType(layout),
155
+ 'cmpParams': modifiedObject.cmpParams,
156
+ }, modifiedObject.cmpParams);
157
+ if (modifiedObject.items && modifiedObject.items.length) {
158
+ newCmp.items = this.getTemplate(modifiedObject.items);
159
+ }
160
+ if (!newCmp.items || newCmp.items.length === 0) {
161
+ newCmp.cls = 'borders-default';
162
+ newCmp.listeners = {'render': this.onGetTemplateCmp.bind(this)};
163
+ }
164
+ return newCmp;
165
+ },
166
+ getCurrentPanelIndex: function(panel) {
167
+ let panelIndex = 0;
168
+ panel.up().items.items.map((item, index) => {
169
+ if (item.id === panel.id) {
170
+ panelIndex = index;
171
+ }
172
+ });
173
+ return panelIndex;
174
+ },
175
+ addCmp: function(cmp, side, inParent, xtype) {
176
+ if (inParent && cmp.up().xtype === cmp.xtype) {
177
+ cmp = cmp.up();
178
+ }
179
+ const parent = cmp.up();
180
+ if (!parent) {
181
+ return false;
182
+ }
183
+ const parentLayout = parent.layout.type || false;
184
+ const index = this.getCurrentPanelIndex(cmp);
185
+ let container = {};
186
+ let newIndex = index;
187
+ const needLayout = side === 'left' || side === 'right' ? 'hbox' : 'vbox';
188
+ if (side === 'down' || side === 'right') {
189
+ newIndex = Number(index) + 1;
190
+ }
191
+ if (parentLayout === needLayout) {
192
+ parent.insert(newIndex, this.getTemplateCmp(this.getDefaultCmp(xtype)));
193
+ } else {
194
+ container = {
195
+ xtype: xtype,
196
+ cmpParams: {
197
+ xtype: xtype,
198
+ layout: needLayout,
199
+ flex: cmp.flex || 1,
200
+ },
201
+ layout: needLayout,
202
+ flex: cmp.flex || 1,
203
+ items: [],
204
+ };
205
+ const currentTemplate = this.getTemplate(this.getData([cmp])).pop();
206
+ const defaultTemplate = this.getTemplateCmp(this.getDefaultCmp(xtype));
207
+ if (side === 'down' || side === 'right') {
208
+ container.items = [currentTemplate, defaultTemplate];
209
+ } else {
210
+ container.items = [defaultTemplate, currentTemplate];
211
+ }
212
+ parent.remove(cmp, true);
213
+ parent.insert(index, [container]);
214
+ }
215
+ this.renderTemplate(this.getData(this.getEditorPanel().items.items));
216
+ },
217
+ getData: function(items) {
218
+ if (!items) {
219
+ return [];
220
+ }
221
+ return items.map((item) => {
222
+ const subItems = !item.cmpParams ||
223
+ item.xtypesMap.grid ||
224
+ item.cmpParams.xtype === 'ReportPanel' ||
225
+ (!item.items ?
226
+ false :
227
+ this.getData(item.items.items)
228
+ );
229
+ const result = Ext.apply({
230
+ 'cmpParams': item.cmpParams,
231
+ }, subItems ? {items: subItems} : {});
232
+ return result;
233
+ });
234
+ },
235
+
236
+ onDeleteCmpClick: function(elem) {
237
+ const me = this;
238
+ Ext.Msg.show({
239
+ title: 'Внимание',
240
+ message: 'Вы действительно хотите удалить элемент рабочего стола?',
241
+ buttons: Ext.Msg.YESNO,
242
+ icon: Ext.Msg.QUESTION,
243
+ fn: function(btn) {
244
+ if (btn === 'yes') {
245
+ const branch = me.getDeletedBranch(elem);
246
+ const xtype = branch.xtype;
247
+ const parent = branch.up();
248
+ branch.destroy();
249
+ if (parent.xtype === xtype && parent.items.items.length === 1) {
250
+ parent.cmpParams = parent.items.items[0].cmpParams;
251
+ parent.cmpParams.items = me.getData(parent.items.items[0].items.items);
252
+ parent.removeAll(true);
253
+ }
254
+ me.reloadView();
255
+ }
256
+ },
257
+ });
258
+ },
259
+ getDeletedBranch: function(panel) {
260
+ if (panel.up().items.items.length > 1 || panel.xtype !== panel.up().xtype || panel.up().dataId === 'editorPanel') {
261
+ return panel;
262
+ }
263
+ return this.getDeletedBranch(panel.up());
264
+ },
265
+ clearBindRegister: function() {
266
+ this.bindingRegister.map((bind) => {
267
+ bind.destroy();
268
+ });
269
+ },
270
+ reloadView: function() {
271
+ this.clearBindRegister();
272
+ this.renderTemplate(this.getData(this.getEditorPanel().items.items));
273
+ },
274
+ onContextClick: function(event, dom, opt) {
275
+ const cmp = opt.cmp;
276
+ const target = !opt.target ? cmp : opt.target;
277
+ const contextMenu = new Ext.menu.Menu({
278
+ closeAction: 'destroy',
279
+ items: this.getMenuCfgByXtype(cmp.cmpParams.xtype, cmp),
280
+ listeners: {
281
+ hide: function() {
282
+ const me = this;
283
+ Ext.defer(() => me.destroy(), 2000);
284
+ },
285
+ },
286
+ });
287
+ contextMenu.showAt(target.getX(), target.getY());
288
+ event.preventDefault();
289
+ return false;
290
+ },
291
+ onGetTemplateCmp: function(elem) {
292
+ const cmp = Ext.get(elem.id);
293
+ cmp.on('mouseover', this.enableBorders.bind(this, cmp, true));
294
+ cmp.on('mouseout', this.enableBorders.bind(this, cmp, false));
295
+ cmp.on('contextmenu', this.onContextClick, this, {'cmp': elem});
296
+ /* elem.el.dom.addEventListener('mouseover', this.enableBorders.bind(this, true), this);
297
+ elem.el.dom.addEventListener('mouseout', this.enableBorders.bind(this, false), this);*/
298
+ },
299
+ enableBorders: function(elem, flag, event) {
300
+ if (flag) {
301
+ elem.dom.classList.add('hover-item');
302
+ } else {
303
+ elem.dom.classList.remove('hover-item');
304
+ }
305
+ // }
306
+ },
307
+ onClickButtonAddPanel: function(panel, event) {
308
+ this.addCmp(panel, event.target.getAttribute('data-side'), event.target.getAttribute('data-in-parent') === 'true', 'container');
309
+ },
310
+ renderMenu: function(panel, xtype, event) {
311
+ const me = this;
312
+ if (!me.isTipOpened) {
313
+ me.isTipOpened = true;
314
+ const tip = Ext.create('Ext.tip.Tip', {
315
+ autoShow: false,
316
+ target: event.target,
317
+ closeAction: 'destroy',
318
+ closable: true,
319
+ layout: 'fit',
320
+ cls: 'menu-tip',
321
+ listeners: {
322
+ 'beforeclose': function() {
323
+ me.isTipOpened = false;
324
+ },
325
+ },
326
+ items: [
327
+ {
328
+ xtype: 'treelist',
329
+ store: {
330
+ root: me.getMenuCfgByXtype(xtype),
331
+ },
332
+ listeners: {
333
+ 'itemclick': me.menuItemClick.bind(me, panel),
334
+ },
335
+ }
336
+ ],
337
+ });
338
+ tip.show();
339
+ // tip.setXY([event.clientX, event.clientY]);
340
+ }
341
+ },
342
+ getIndex: function(panel) {
343
+ let index = 0;
344
+ panel.up().items.keys.find((item, number) => {
345
+ if (panel.id === item) {
346
+ index = number;
347
+ return item;
348
+ }
349
+ });
350
+ return index;
351
+ },
352
+ getMenuCfgByXtype: function(xtype, panel) {
353
+ const me = this;
354
+ let buttons = [];
355
+ if (panel.isContainer) {
356
+ buttons = buttons.concat([{
357
+ iconCls: 'x-fa fa-file-invoice',
358
+ text: 'Добавить элемент',
359
+ handler: () => me.onAddCmpClick(panel),
360
+ },
361
+ {
362
+ iconCls: 'x-fa fa-file-invoice',
363
+ text: 'Импортировать существующую настраиваемую панель',
364
+ handler: () => me.onAddExistingPanelCmpClick(panel),
365
+ },
366
+ {iconCls: 'x-fa fa-copy', text: 'Копировать содержимое'},
367
+ {iconCls: 'x-fa fa-paste', text: 'Вставить содержимое'},
368
+ {iconCls: 'x-fa fa-pastafarianism', text: 'Заменить содержимое'}]
369
+ );
370
+ const firstContainer = this.getFirstContainer(this.getEditorPanel().items.items);
371
+ if (firstContainer.dataId !== panel.dataId) {
372
+ buttons = buttons.concat([
373
+ {
374
+ iconCls: 'x-fa fa-file-invoice',
375
+ text: 'Прикрепить отчет',
376
+ handler: () => me.onAddReportCmpClick(panel),
377
+ }
378
+ ]
379
+ );
380
+ }
381
+ }
382
+ if (panel.successUserEditingOptions && panel.successUserEditingOptions.length) {
383
+ buttons = buttons.concat([
384
+ {iconCls: 'x-fa fa-cog', text: 'Настройки', handler: () => me.onSettingsCmpClick(panel)}
385
+ ]);
386
+ }
387
+ if (panel.up().dataId !== 'editorPanel') {
388
+ buttons = buttons.concat([{
389
+ iconCls: 'x-fa fa-remove',
390
+ text: 'Удалить',
391
+ handler: () => me.onDeleteCmpClick(panel),
392
+ }]);
393
+ }
394
+ buttons = buttons.concat([{
395
+ iconCls: 'x-fa fa-save',
396
+ text: 'Сохранить',
397
+ handler: () => me.onSaveCmpClick(panel),
398
+ }]);
399
+
400
+ if (panel.up().layout.type !== 'border' && panel.up().isContainer && panel.up().items.length > 1) {
401
+ const curIndex = this.getIndex(panel);
402
+ if (curIndex === 0 || curIndex === panel.up().items.length - 1) {
403
+ if (curIndex === 0) {
404
+ buttons = buttons.concat([{
405
+ iconCls: 'x-fa fa-chevron-circle-down',
406
+ text: 'Переместить вниз',
407
+ handler: () => me.onMoveCmpClick(panel, curIndex + 1),
408
+ }]);
409
+ }
410
+ if (curIndex === panel.up().items.length - 1) {
411
+ buttons = buttons.concat([{
412
+ iconCls: 'x-fa fa-chevron-circle-up',
413
+ text: 'Переместить вверх',
414
+ handler: () => me.onMoveCmpClick(panel, curIndex - 1),
415
+ }]);
416
+ }
417
+ } else {
418
+ buttons = buttons.concat([{
419
+ iconCls: 'x-fa fa-chevron-circle-up',
420
+ text: 'Переместить вверх',
421
+ handler: () => me.onMoveCmpClick(panel, curIndex - 1),
422
+ }, {
423
+ iconCls: 'x-fa fa-chevron-circle-down',
424
+ text: 'Переместить вниз',
425
+ handler: () => me.onMoveCmpClick(panel, curIndex + 1),
426
+ }]);
427
+ }
428
+ }
429
+
430
+ switch (xtype) {
431
+ case 'container':
432
+ buttons = [
433
+ {
434
+ iconCls: 'x-fa fa-angle-left',
435
+ text: 'Добавить влево',
436
+ handler: () => me.addCmp(panel, 'left', false, xtype),
437
+ },
438
+ {
439
+ iconCls: 'x-fa fa-angle-right',
440
+ text: 'Добавить вправо',
441
+ handler: () => me.addCmp(panel, 'right', false, xtype),
442
+ },
443
+ {
444
+ iconCls: 'x-fa fa-angle-up',
445
+ text: 'Добавить панель вверх',
446
+ handler: () => me.addCmp(panel, 'up', false, xtype),
447
+ },
448
+ {
449
+ iconCls: 'x-fa fa-angle-down',
450
+ text: 'Добавить вниз',
451
+ handler: () => me.addCmp(panel, 'down', false, xtype),
452
+ },
453
+ {
454
+ iconCls: 'x-fa fa-angle-double-left',
455
+ text: 'Добавить в родителя влево',
456
+ handler: () => me.addCmp(panel, 'left', true, xtype),
457
+ },
458
+ {
459
+ iconCls: 'x-fa fa-angle-double-right',
460
+ text: 'Добавить в родителя вправо',
461
+ handler: () => me.addCmp(panel, 'right', true, xtype),
462
+ },
463
+ {
464
+ iconCls: 'x-fa fa-angle-double-up',
465
+ text: 'Добавить в родителя вверх',
466
+ handler: () => me.addCmp(panel, 'up', true, xtype),
467
+ },
468
+ {
469
+ iconCls: 'x-fa fa-angle-double-down',
470
+ text: 'Добавить в родителя вниз',
471
+ handler: () => me.addCmp(panel, 'down', true, xtype),
472
+ }
473
+ ].concat(buttons);
474
+ break;
475
+ }
476
+ return buttons;
477
+ },
478
+ menuItemClick: function(panel, list, opt) {
479
+ switch (opt.node.data.action) {
480
+ case 'add':
481
+ this.addCmp(panel, opt.node.data.side, opt.node.data.inParent, 'container');
482
+ break;
483
+ case 'addCmp':
484
+ this.onAddCmpClick(panel);
485
+ break;
486
+ case 'remove':
487
+ this.onDeleteCmpClick(panel);
488
+ break;
489
+ case 'save':
490
+ this.onSaveCmpClick(panel);
491
+ break;
492
+ }
493
+ list.up().close();
494
+ },
495
+ onMoveCmpClick: function(panel, needIndex) {
496
+ const parent = panel.up();
497
+ parent.remove(panel, false);
498
+ parent.insert(needIndex, panel);
499
+ this.reloadView();
500
+ },
501
+ onSaveCmpClick: function() {
502
+ JSON.stringify(this.getData(this.getEditorPanel().items.items));
503
+ },
504
+ enablePanelControls: function(div, flag) {
505
+ div.style.display = flag ? 'unset' : 'none';
506
+ },
507
+ onAddCmpClick: function(panel) {
508
+ const me = this;
509
+ let value = 'container';
510
+ let data = [
511
+ {'id': 'container', 'name': 'Контенер'},
512
+ {'id': 'panel', 'name': 'Панель'},
513
+ {'id': 'tabpanel', 'name': 'Таб панель'},
514
+ {'id': 'fieldset', 'name': 'fieldset'},
515
+ {'id': 'textfield', 'name': 'Текстовое поле'},
516
+ {'id': 'numberfield', 'name': 'Числовое поле'},
517
+ {'id': 'datefield', 'name': 'Дата'}
518
+ ];
519
+ if (panel.xtype === 'tabpanel') {
520
+ data = [{'id': 'panel', 'name': 'Панель'}];
521
+ value = 'panel';
522
+ }
523
+ Ext.create('Ext.window.Window', {
524
+ closable: true,
525
+ parentPanel: panel,
526
+ closeAction: 'destroy',
527
+ width: 400,
528
+ title: 'Добавлние элемента',
529
+ height: 170,
530
+ modal: true,
531
+ maximazible: false,
532
+ minimazible: false,
533
+ items: [
534
+ {
535
+ margin: '10px 5px',
536
+ fieldLabel: 'Тип элемента',
537
+ flex: 1,
538
+ width: '100%',
539
+ xtype: 'combo',
540
+ queryMode: 'local',
541
+ value: value,
542
+ displayField: 'name',
543
+ valueField: 'id',
544
+ store: {
545
+ fields: ['id', 'name'],
546
+ data: data,
547
+ },
548
+ }
549
+ ],
550
+ buttons: [
551
+ {
552
+ text: 'Применить',
553
+ handler: me.insertCmp.bind(me, panel),
554
+ },
555
+ {
556
+ text: 'Отмена',
557
+ handler: function() {
558
+ this.up('window').close();
559
+ },
560
+ }
561
+ ],
562
+ }).show();
563
+ },
564
+ insertCmp: function(panel, btn) {
565
+ const cmpXtype = btn.up('window').down('combo').getValue();
566
+ if (!panel.items.length) {
567
+ switch (cmpXtype) {
568
+ case 'textfield':
569
+ case 'numberfield':
570
+ case 'datefield':
571
+ panel.cmpParams.layout = 'anchor';
572
+ break;
573
+ case 'panel':
574
+ case 'tabpanel':
575
+ case 'fieldset':
576
+ case 'container':
577
+ panel.cmpParams.layout = 'fit';
578
+ break;
579
+ }
580
+ }
581
+ panel.add(this.getCfgCmpByXtype(cmpXtype));
582
+ this.reloadView();
583
+ btn.up('window').close();
584
+ },
585
+ getCfgCmpByXtype: function(xtype) {
586
+ switch (xtype) {
587
+ case 'panel':
588
+ return {
589
+ xtype: 'panel',
590
+ layout: 'fit',
591
+ cmpParams: {
592
+ xtype: 'panel',
593
+ layout: 'fit',
594
+ title: 'Новая панель',
595
+ },
596
+ title: 'Новая панель',
597
+ };
598
+ break;
599
+ case 'tabpanel':
600
+ return {
601
+ xtype: 'tabpanel',
602
+ layout: 'fit',
603
+ cmpParams: {
604
+ xtype: 'tabpanel',
605
+ layout: 'fit',
606
+ title: 'Новая панель',
607
+ },
608
+ title: 'Новая панель',
609
+ };
610
+ break;
611
+ case 'container':
612
+ return {
613
+ xtype: 'container',
614
+ cmpParams: {
615
+ xtype: 'container',
616
+ layout: 'fit',
617
+ },
618
+ layout: 'fit',
619
+ };
620
+ break;
621
+ case 'fieldset':
622
+ return {
623
+ xtype: 'fieldset',
624
+ cmpParams: {
625
+ xtype: 'fieldset',
626
+ layout: 'fit',
627
+ title: 'Филдсет',
628
+ },
629
+ };
630
+ break;
631
+ case 'textfield':
632
+ return {
633
+ xtype: 'textfield',
634
+ cmpParams: {
635
+ xtype: 'textfield',
636
+ anchor: '100%',
637
+ fieldLabel: 'Текствое поле',
638
+ },
639
+ };
640
+ break;
641
+ case 'numberfield':
642
+ return {
643
+ xtype: 'numberfield',
644
+ cmpParams: {
645
+ anchor: '100%',
646
+ xtype: 'numberfield',
647
+ fieldLabel: 'Числовое поле',
648
+ },
649
+ };
650
+ break;
651
+ case 'datefield':
652
+ return {
653
+ xtype: 'datefield',
654
+ cmpParams: {
655
+ anchor: '100%',
656
+ xtype: 'datefield',
657
+ fieldLabel: 'Дата поле',
658
+ },
659
+ };
660
+ break;
661
+ }
662
+ },
663
+
664
+ getDefaultData: function() {
665
+ return {
666
+ 'cmpParams': {'xtype': 'container', 'layout': 'fit', 'flex': 1, 'dataId': Ext.id() + '-interface-node'},
667
+
668
+ };
669
+ },
670
+ getDefaultCmp: function(xtype) {
671
+ return {
672
+ 'cmpParams': {
673
+ 'layout': 'fit',
674
+ 'flex': 1,
675
+ 'xtype': xtype || 'container',
676
+ },
677
+ };
678
+ },
679
+ onSettingsCmpClick(panel) {
680
+ const window = Ext.create('Coon.uielement.component.UiCPVisualEditorConfigWindow', {
681
+ 'parentPanel': panel,
682
+ 'parentController': this,
683
+ });
684
+ window.show();
685
+ },
686
+ getValueJson: function(str) {
687
+ try {
688
+ return JSON5.parse(str);
689
+ } catch (e) {
690
+ return str;
691
+ }
692
+ },
693
+ valueIsValidJson: function(str) {
694
+ try {
695
+ return JSON5.parse(str);
696
+ } catch (e) {
697
+ return false;
698
+ }
699
+ },
700
+ onAddReportCmpClick: function(panel) {
701
+ const me = this;
702
+ Ext.create('Ext.window.Window', {
703
+ height: '80%',
704
+ width: 700,
705
+ layout: 'fit',
706
+ closeAction: 'destroy',
707
+ modal: true,
708
+ resizable: false,
709
+ minimazible: false,
710
+ maximazible: false,
711
+
712
+ items: [
713
+ {
714
+ xtype: 'grid',
715
+ store: {
716
+ type: 'json',
717
+ pageSize: 0,
718
+ },
719
+ listeners: {
720
+ itemdblclick: function(element, record) {
721
+ const reportCfg = me.getDefaultCmp('ReportPanel');
722
+ reportCfg.cmpParams.reportId = record.get('CM_REPORT_CD');
723
+ panel.cmpParams = reportCfg.cmpParams;
724
+ me.reloadView();
725
+ element.up('window').close();
726
+ },
727
+ render: function(grid) {
728
+ Promise.all([
729
+ Ext.Ajax.request({
730
+ url: 'ReportFormData/get',
731
+ method: 'POST',
732
+ params: {
733
+ reportId: 'REPORTS',
734
+ parameterList: '[]',
735
+ },
736
+ })
737
+ ]).then(function(valArray) {
738
+ const panels = Ext.decode(valArray[0].responseText).list;
739
+ const data = panels.map((item) => {
740
+ return {
741
+ 'CM_REPORT_CD': item.CM_REPORT_CD,
742
+ 'DESCR': item.DESCR,
743
+ };
744
+ });
745
+ grid.getStore().loadData(data);
746
+ });
747
+ },
748
+ },
749
+ plugins: [
750
+ {ptype: 'gridfilterbar', clicksToEdit: 2}
751
+ ],
752
+ columns: [
753
+ {
754
+ dataIndex: 'CM_REPORT_CD', text: 'Наименование', flex: 1, filter: {type: 'string'},
755
+ },
756
+ {dataIndex: 'DESCR', text: 'Описание', flex: 2, filter: {type: 'string'}}
757
+
758
+ ],
759
+ }
760
+ ],
761
+ buttons: [{
762
+ text: 'Закрыть',
763
+ handler: (elem) => elem.up('window').close(),
764
+ }],
765
+ }).show();
766
+ },
767
+ getDataFromTemplateObj: function(template) {
768
+
769
+ },
770
+ onAddExistingPanelCmpClick: function(panel) {
771
+ const me = this;
772
+ Ext.create('Ext.window.Window', {
773
+ height: '80%',
774
+ width: 700,
775
+ layout: 'fit',
776
+ closeAction: 'destroy',
777
+ modal: true,
778
+ resizable: false,
779
+ minimazible: false,
780
+ maximazible: false,
781
+
782
+ items: [
783
+ {
784
+ xtype: 'grid',
785
+ store: {
786
+ type: 'json',
787
+ pageSize: 0,
788
+ },
789
+ listeners: {
790
+ itemdblclick: function(element, record) {
791
+ const command = Ext.create('command.GetUIElementCommand');
792
+ command.on('complete', function(UIElementBean) {
793
+ const value = me.valueIsValidJson(UIElementBean.propertyData);
794
+ if (!value) {
795
+ Ext.Msg.alert('Ошибка', 'Не корректный JSON объект');
796
+ return false;
797
+ }
798
+ try {
799
+ const check = Ext.create('Ext.panel.Panel', value);
800
+ check.destroy();
801
+ } catch (e) {
802
+ element.up('window').close();
803
+ Ext.Msg.alert('Ошибка', e.message);
804
+ return false;
805
+ }
806
+ panel.removeAll(true);
807
+ if (value && value.plugins && value.plugins.length) {
808
+ panel.cmpParams.mainPlugins = value.plugins;
809
+ delete value['plugins'];
810
+ }
811
+ const content = me.getTemplate([value]);
812
+ panel.add(content);
813
+ me.reloadView();
814
+ element.up('window').close();
815
+ /*
816
+ */
817
+ }, this);
818
+ command.execute(record.get('CM_REPORT_CD'));
819
+ },
820
+ render: function(grid) {
821
+ Promise.all([
822
+ Ext.Ajax.request({
823
+ url: 'ReportFormData/get',
824
+ method: 'POST',
825
+ params: {
826
+ reportId: 'UI_CUSTOM_PANELS_LIST',
827
+ parameterList: '[]',
828
+ },
829
+ })
830
+ ]).then(function(valArray) {
831
+ const panels = Ext.decode(valArray[0].responseText).list;
832
+ const data = panels.map((item) => {
833
+ return {
834
+ 'CM_REPORT_CD': item.UI_ELEMENT_CD,
835
+ 'DESCR': item.DESCR,
836
+ };
837
+ });
838
+ grid.getStore().loadData(data);
839
+ });
840
+ },
841
+ },
842
+ plugins: [
843
+ {ptype: 'gridfilterbar', clicksToEdit: 2}
844
+ ],
845
+ columns: [
846
+ {
847
+ dataIndex: 'CM_REPORT_CD', text: 'Наименование', flex: 1, filter: {type: 'string'},
848
+ },
849
+ {dataIndex: 'DESCR', text: 'Описание', flex: 2, filter: {type: 'string'}}
850
+
851
+ ],
852
+ }
853
+ ],
854
+ buttons: [{
855
+ text: 'Закрыть',
856
+ handler: (elem) => elem.up('window').close(),
857
+ }],
858
+ }).show();
859
+ },
860
+ },
861
+ items: [
862
+ {
863
+ xtype: 'panel',
864
+ region: 'center',
865
+ flex: 4,
866
+ layout: 'fit',
867
+ header: false,
868
+ dataId: 'editorPanel',
869
+ split: true,
870
+ },
871
+ {
872
+ xtype: 'treepanel',
873
+ store: {
874
+ type: 'tree',
875
+ rootVisible: false,
876
+ root: {
877
+ expanded: true,
878
+ children: [],
879
+ },
880
+ },
881
+ title: 'Структура',
882
+ cls: 'tree-container',
883
+ collapsible: true,
884
+ region: 'east',
885
+ flex: 1,
886
+ dataId: 'treeEditorPanel',
887
+ listeners: {
888
+ 'selectionchange': 'onTreeSelectionChange',
889
+ 'itemcontextmenu': 'onTreeItemContextMenu',
890
+ },
891
+ }
892
+ ],
893
+ listeners: {
894
+ render: 'onRenderMainPanel',
895
+ },
896
+ });
@@ -0,0 +1,108 @@
1
+ .UiCPVisualEditor {
2
+ .x-grid-cell-inner .x-btn {
3
+ padding: 0;
4
+ }
5
+
6
+ .widget-box {
7
+ border: 2px solid #e0e0e0;
8
+ margin: 10px 20px;
9
+ padding: 7px;
10
+ border-radius: 10px;
11
+ }
12
+
13
+ /*-------------*/
14
+ .borders {
15
+ margin: 0 3px 15px 3px !important;
16
+ box-shadow: 0 1px 6px 0 rgba(86, 112, 163, 0.2);
17
+ }
18
+
19
+ .borders > .x-panel-bodyWrap > .x-panel-body {
20
+ border: 1px solid #e0e0e0 !important;
21
+ border-radius: 0 0 5px 5px;
22
+ margin-top: -1px;
23
+ }
24
+
25
+ .no-header-panel .x-panel-bodyWrap > .x-panel-body {
26
+ border: 1px solid #e0e0e0 !important;
27
+ border-radius: 5px;
28
+ margin-top: 0;
29
+ }
30
+
31
+ .borders .x-panel-header {
32
+ border-radius: 5px 5px 0 0;
33
+ height: auto;
34
+ }
35
+
36
+ .draggable-element {
37
+ width: 100px;
38
+ height: 100px;
39
+ background-color: #e0e0e0;
40
+ }
41
+
42
+
43
+ .btn i {
44
+ color: #FFF;
45
+ font-style: normal;
46
+ }
47
+
48
+
49
+ .icon {
50
+ font-size: 18px;
51
+ display: block;
52
+ text-align: center;
53
+ margin-top: 6px;
54
+ }
55
+
56
+
57
+ .btn {
58
+ &:hover {
59
+ background-color: rgba(61, 103, 128, 1) !important;
60
+ }
61
+
62
+ width: 30px;
63
+ height: 30px;
64
+ background-color: rgba(61, 103, 128, 0.7);
65
+ border-radius: 18px;
66
+ cursor: pointer;
67
+ z-index: 999;
68
+ }
69
+
70
+ .center-btn {
71
+ position: absolute;
72
+ left: 50%;
73
+ top: 50%;
74
+ margin: -12px 0 0 -11px;
75
+ }
76
+
77
+ .right-top-btn {
78
+ position: absolute;
79
+ right: 0;
80
+ top: 0;
81
+ margin: 1px 0 0 0;
82
+ }
83
+
84
+ .hidden-btn {
85
+ display: none !important;
86
+ }
87
+
88
+ .borders-default {
89
+ border: 1px solid black;
90
+ }
91
+
92
+ .hover-item {
93
+ border: 1px solid red;
94
+ }
95
+
96
+ .tree-container .x-panel-body{
97
+ background-color: #f0f0f0;
98
+ }
99
+ }
100
+
101
+ .menu-tip .x-tool-close {
102
+ background-color: #111111 !important;
103
+ }
104
+
105
+ .svg-icon-tool {
106
+ background-color: white !important;
107
+ }
108
+
@@ -0,0 +1,303 @@
1
+ Ext.define('Coon.uielement.component.UiCPVisualEditorConfigWindow', {
2
+ extend: 'Ext.window.Window',
3
+ cls: 'UiCPVisualEditorConfigWindow',
4
+ alias: 'widget.UiCPVisualEditorConfigWindow',
5
+ xtype: 'UiCPVisualEditorConfigWindow',
6
+ title: 'Настройки компонента',
7
+ width: 500,
8
+ height: '80%',
9
+ layout: 'fit',
10
+ closeAction: 'destroy',
11
+ requires: [
12
+ 'Coon.uielement.component.settings.UiAceEditor'
13
+ ],
14
+ controller: {
15
+ parentCfgLocalState: {},
16
+
17
+ init: function(view) {
18
+ this.initParentCfgLocalState();
19
+ this.loadGrid();
20
+ },
21
+ initParentCfgLocalState: function() {
22
+ const view = this.getView();
23
+ view.parentPanel.successUserEditingOptions.map((option) => {
24
+ const valueObj = this.getOptionValue(option);
25
+ const value = Object.keys(valueObj).length ? valueObj[Object.keys(valueObj)[0]] : null;
26
+ if (value !== null && typeof value === 'object') {
27
+ if (typeof this.parentCfgLocalState[Object.keys(valueObj)[0]] !== 'object') {
28
+ this.parentCfgLocalState[Object.keys(valueObj)[0]] = {};
29
+ }
30
+ Ext.apply(this.parentCfgLocalState[Object.keys(valueObj)[0]], value);
31
+ } else {
32
+ if (value !== '' && value !== null && typeof value !== 'undefined') {
33
+ Ext.apply(this.parentCfgLocalState, valueObj);
34
+ }
35
+ }
36
+ });
37
+ Ext.applyIf(this.parentCfgLocalState, view.parentPanel.cmpParams);
38
+ delete this.parentCfgLocalState['dataId'];
39
+ },
40
+ loadGrid: function() {
41
+ const view = this.getView();
42
+ view.down('grid').getStore().loadData(view.parentPanel.successUserEditingOptions.map((option) => {
43
+ return Ext.apply({
44
+ 'id': option.name,
45
+ 'group': option.group || '',
46
+ 'description': option.description,
47
+ 'type': option.type,
48
+ 'options': this.getOptions(option),
49
+ }, this.getOptionValue(option, true));
50
+ }));
51
+ },
52
+ findDefaultOptionName: function(group) {
53
+ if (!group) {
54
+ return '';
55
+ }
56
+ const defaultOption = this.getView().parentPanel.successUserEditingOptions.find((item) => {
57
+ if (item.group === 'group' && item.defaultOption === true) {
58
+ return item;
59
+ }
60
+ });
61
+ return defaultOption ? defaultOption.name : false;
62
+ },
63
+ getOptionValue: function(option, local) {
64
+ const objCfg = local ? this.parentCfgLocalState : this.getView().parentPanel;
65
+ const returnVariable = local ? 'value' : option.name;
66
+ const returningObj = {};
67
+ let value = null;
68
+ let isGroupOption = false;
69
+ if (typeof option.group !== 'undefined' && option.group) {
70
+ isGroupOption = true;
71
+ if (typeof objCfg[option.group] === 'undefined') {
72
+ return {};
73
+ }
74
+ if (typeof objCfg[option.group][option.name] !== 'undefined') {
75
+ value = objCfg[option.group][option.name];
76
+ } else {
77
+ if (option.name === this.findDefaultOptionName(option.group)) {
78
+ value = objCfg[option.group];
79
+ } else {
80
+ return {};
81
+ }
82
+ }
83
+ } else {
84
+ if (typeof objCfg[option.name] === 'undefined') {
85
+ return {};
86
+ }
87
+ value = objCfg[option.name];
88
+ }
89
+ switch (option.type) {
90
+ case 'int':
91
+ case 'integer':
92
+ returningObj[returnVariable] = Math.round(value) || null;
93
+ break;
94
+ case 'number':
95
+ case 'float':
96
+ returningObj[returnVariable] = Number(value) || null;
97
+ break;
98
+ case 'combo':
99
+ returningObj[returnVariable] = value || null;
100
+ break;
101
+ default:
102
+ returningObj[returnVariable] = value;
103
+ }
104
+ if (isGroupOption && !local) {
105
+ const tmpObj = {};
106
+ tmpObj[option.group] = returningObj;
107
+ return tmpObj;
108
+ }
109
+ return returningObj;
110
+ },
111
+ getOptions: function(option) {
112
+ if (option.type === 'bool') {
113
+ return ['true', 'false'];
114
+ }
115
+ if (option.options && option.options.length) {
116
+ return option.options;
117
+ }
118
+ return [];
119
+ },
120
+ onClose: function() {
121
+ this.getView().close();
122
+ },
123
+ applyGridChanges: function() {
124
+ this.getView().down('grid').getStore().getModifiedRecords().map((record) => {
125
+ const value = record.get('value');
126
+ const key = record.get('id');
127
+ const group = record.get('group');
128
+ if (value === null || value === '' || typeof value === 'undefined') {
129
+ if (group) {
130
+ if (typeof this.parentCfgLocalState[group][key] !== 'undefined') {
131
+ delete this.parentCfgLocalState[group][key];
132
+ }
133
+ } else {
134
+ if (typeof this.parentCfgLocalState[key] !== 'undefined') {
135
+ delete this.parentCfgLocalState[key];
136
+ }
137
+ }
138
+ } else {
139
+ if (group) {
140
+ this.parentCfgLocalState[group][key] = value;
141
+ } else {
142
+ this.parentCfgLocalState[key] = value;
143
+ }
144
+ }
145
+ });
146
+ },
147
+ applyEditorChanges: function() {
148
+ const aceEditor = this.getView().down('UiAceEditor');
149
+ const value = aceEditor.getValue();
150
+ if (aceEditor.hasErrors()) {
151
+ Ext.Msg.alert('Ошибка', 'В редакторе присутствуют ошибки.');
152
+ return false;
153
+ }
154
+ if (!this.valueIsValidJson(value)) {
155
+ Ext.Msg.alert('Ошибка', 'Не корректный JSON объект');
156
+ return false;
157
+ }
158
+ this.parentCfgLocalState = this.getValueJson(value);
159
+ return true;
160
+ },
161
+ getValueJson: function(str) {
162
+ try {
163
+ return JSON5.parse(str);
164
+ } catch (e) {
165
+ return str;
166
+ }
167
+ },
168
+ valueIsValidJson: function(str) {
169
+ try {
170
+ return JSON5.parse(str);
171
+ } catch (e) {
172
+ return false;
173
+ }
174
+ },
175
+ onApply: function() {
176
+ const view = this.getView();
177
+ const tab = this.getView().down('tabpanel').getActiveTab();
178
+ if (tab.xtype === 'UiAceEditor') {
179
+ if (!this.applyEditorChanges()) {
180
+ return false;
181
+ }
182
+ } else {
183
+ this.applyGridChanges();
184
+ }
185
+ view.parentPanel.cmpParams = {'dataId': view.parentPanel.cmpParams['dataId']};
186
+ Ext.apply(view.parentPanel.cmpParams, this.parentCfgLocalState);
187
+ view.parentController.reloadView();
188
+ view.close();
189
+ },
190
+ onBeforeTabChange: function(tabPanel, newCard, oldCard, eOpts) {
191
+ if (newCard.xtype !== 'UiAceEditor') {
192
+ const aceEditor = tabPanel.down('UiAceEditor');
193
+ const value = aceEditor.getValue();
194
+ if (aceEditor.hasErrors()) {
195
+ Ext.Msg.alert('Ошибка', 'В редакторе присутствуют ошибки.');
196
+ return false;
197
+ }
198
+ if (!this.valueIsValidJson(value)) {
199
+ Ext.Msg.alert('Ошибка', 'Не корректный JSON объект');
200
+ return false;
201
+ }
202
+ }
203
+ },
204
+ onTabChange: function(panel, tab) {
205
+ if (tab.xtype === 'UiAceEditor') {
206
+ this.applyGridChanges();
207
+ tab.setValue(JSON.stringify(this.parentCfgLocalState, null, 2));
208
+ } else {
209
+ this.applyEditorChanges();
210
+ this.loadGrid();
211
+ }
212
+ },
213
+ },
214
+ items: [
215
+ {
216
+ xtype: 'tabpanel',
217
+ listeners: {
218
+ 'tabchange': 'onTabChange',
219
+ 'beforetabchange': 'onBeforeTabChange',
220
+ },
221
+ items: [
222
+ {
223
+ xtype: 'grid',
224
+ title: 'Таблица',
225
+ store: {
226
+ fields: ['id', 'description', 'type', 'options', 'value', 'group'],
227
+ groupField: 'group',
228
+ data: [],
229
+ },
230
+ features: [{ftype: 'grouping', groupHeaderTpl: '{name}', collapsible: false}],
231
+ columns: [
232
+ {dataIndex: 'description', text: 'Наименование', flex: 1, filter: {type: 'string'}},
233
+ {
234
+ dataIndex: 'value', text: 'Значение', flex: 1, getEditor: function(record) {
235
+ switch (record.get('type')) {
236
+ case 'bool':
237
+ case 'boolean':
238
+ return Ext.create('Ext.grid.CellEditor', {
239
+ field: Ext.create('Ext.form.field.ComboBox', {
240
+ forceSelection: true,
241
+ store: [[true, 'true'], [false, 'false']],
242
+ }),
243
+ });
244
+ break;
245
+ case 'int':
246
+ case 'integer':
247
+ return Ext.create('Ext.grid.CellEditor', {
248
+ field: Ext.create('Ext.form.field.Number', {
249
+ allowDecimals: false,
250
+ minValue: 0,
251
+ }),
252
+ });
253
+ break;
254
+ case 'number':
255
+ case 'float':
256
+ return Ext.create('Ext.grid.CellEditor', {
257
+ field: Ext.create('Ext.form.field.Number', {
258
+ allowDecimals: true,
259
+ minValue: 0,
260
+ }),
261
+ });
262
+ break;
263
+ case 'text':
264
+ case 'string':
265
+ return Ext.create('Ext.grid.CellEditor', {
266
+ field: Ext.create('Ext.form.field.Text', {}),
267
+ });
268
+ break;
269
+ case 'combo':
270
+ return Ext.create('Ext.grid.CellEditor', {
271
+ field: Ext.create('Ext.form.field.ComboBox', {
272
+ forceSelection: true,
273
+ store: record.get('options').map((option) => {
274
+ return [option, option];
275
+ }),
276
+ }),
277
+ });
278
+ break;
279
+ }
280
+ },
281
+ }
282
+ ],
283
+ plugins: {
284
+ cellediting: {
285
+ clicksToEdit: 2,
286
+ },
287
+ },
288
+ },
289
+ {
290
+ xtype: 'UiAceEditor',
291
+ flex: true,
292
+ scrollable: 'y',
293
+ title: 'PRO',
294
+ }
295
+ ],
296
+ }
297
+
298
+ ],
299
+ buttons: [
300
+ {text: 'Применить', handler: 'onApply'},
301
+ {text: 'Отмена', handler: 'onClose'}
302
+ ],
303
+ });
package/src/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  Ext.define('Coon.version', {
2
2
  singleton: true,
3
- number: '2.5.64',
3
+ number: '2.5.65',
4
4
  });