ru.coon 2.6.22 → 2.7.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/CHANGELOG.md +43 -0
- package/package.json +1 -1
- package/src/Function.js +37 -28
- package/src/common/field/ForeignField.js +1 -1
- package/src/common/panel/WindowWrap.js +9 -0
- package/src/report/component/ReportPanel.js +42 -1
- package/src/report/component/reportpanel/NorthPanel.js +3 -0
- package/src/report/component/reportpanel/ReportGrid.scss +4 -0
- package/src/report/component/settings/property/ReportPropertiesPanel.js +0 -1
- package/src/report/component/settings/property/ReportPropertyDictionary.js +11 -0
- package/src/report/plugin/configPanel/AddFilterConditionPluginConfigPanel.js +195 -0
- package/src/report/plugin/configPanel/AddFilterConditionPluginConfigPanel.scss +53 -0
- package/src/report/plugin/grid/AddFilterConditionPlugin.js +178 -0
- package/src/report/plugin/grid/GridContextMenu.js +50 -12
- package/src/uielement/component/UiCustomController.js +4 -0
- package/src/uielement/component/formchips/Chip.js +35 -5
- package/src/uielement/component/formchips/FilterConditionToolbar.js +59 -21
- package/src/uielement/component/formchips/FilterConditionToolbar.scss +29 -8
- package/src/uielement/component/formchips/FilterConditionToolbarController.js +235 -72
- package/src/version.js +1 -1
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
Ext.define('Coon.report.plugin.grid.AddFilterConditionPlugin', {
|
|
2
|
+
extend: 'Ext.AbstractPlugin',
|
|
3
|
+
alias: 'plugin.AddFilterConditionPlugin',
|
|
4
|
+
uses: [],
|
|
5
|
+
requires: [
|
|
6
|
+
'Ext.grid.Panel'
|
|
7
|
+
],
|
|
8
|
+
configurePanelWizard: 'AddFilterConditionPluginConfigPanel',
|
|
9
|
+
|
|
10
|
+
filters: new Map(),
|
|
11
|
+
|
|
12
|
+
init: function(grid) {
|
|
13
|
+
this.grid = grid;
|
|
14
|
+
grid.on('added', function(grid) {
|
|
15
|
+
const contextMenu = grid.contextMenu;
|
|
16
|
+
contextMenu.add(new Ext.menu.Item({
|
|
17
|
+
iconCls: 'svg-icon svg-icon-filter-alt',
|
|
18
|
+
text: 'фильтр по значению',
|
|
19
|
+
itemId: 'filterByCellValue',
|
|
20
|
+
handler: this.addFilter.bind(this),
|
|
21
|
+
}));
|
|
22
|
+
contextMenu.add(new Ext.menu.Item({
|
|
23
|
+
text: 'Отменить фильтр для столбца',
|
|
24
|
+
hidden: true,
|
|
25
|
+
itemId: 'cancelCurrentColumnFilter',
|
|
26
|
+
handler: this.clearCurrentColumnFilter.bind(this),
|
|
27
|
+
}));
|
|
28
|
+
contextMenu.add(new Ext.menu.Item({
|
|
29
|
+
text: 'Отменить все',
|
|
30
|
+
itemId: 'cancelAllFilters',
|
|
31
|
+
handler: this.clearAllFilters.bind(this),
|
|
32
|
+
}));
|
|
33
|
+
}, this);
|
|
34
|
+
grid.on('load', function() {
|
|
35
|
+
this.clearAllFilters();
|
|
36
|
+
}, this);
|
|
37
|
+
grid.contextMenu.on('requestMenuItems', this.onShowMenu, this);
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
onShowMenu({record, cellIndex}) {
|
|
41
|
+
const cancelAllItem = this.findMenuItem('cancelAllFilters');
|
|
42
|
+
cancelAllItem && cancelAllItem.setDisabled(this.filters.size === 0);
|
|
43
|
+
if (this.filters.size) {
|
|
44
|
+
this.findMenuItem('cancelCurrentColumnFilter').hide();
|
|
45
|
+
}
|
|
46
|
+
this.findMenuItem('filterByCellValue').hide();
|
|
47
|
+
record && this.setMenuText(record, cellIndex);
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
addFilter: function() {
|
|
51
|
+
if (!this.grid) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const key = this.getColumnKey();
|
|
55
|
+
this.filters.set(key, this.columnValue);
|
|
56
|
+
this.doFilter();
|
|
57
|
+
this.changeColumnStyle(this.column);
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
changeColumnStyle(column) {
|
|
61
|
+
if (this.filters.has(column.dataIndex)) {
|
|
62
|
+
column.addCls('filtered-column');
|
|
63
|
+
} else {
|
|
64
|
+
column.removeCls('filtered-column');
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
doFilter() {
|
|
69
|
+
if (this.filters.size) {
|
|
70
|
+
this.grid.getStore().suspendEvents();
|
|
71
|
+
this.grid.getStore().clearFilter();
|
|
72
|
+
this.grid.getStore().resumeEvents();
|
|
73
|
+
this.grid.getStore().filter(
|
|
74
|
+
[...this.filters.entries()].map(function([property, value]) {
|
|
75
|
+
if (Ext.isString(value) || Ext.isNumber(value)) {
|
|
76
|
+
return {property, operator: '=', value};
|
|
77
|
+
} else if (Ext.isDate(value)) {
|
|
78
|
+
return new Ext.util.Filter({
|
|
79
|
+
filterFn: function(rec) {
|
|
80
|
+
return Ext.Date.format(rec.get(property), Coon.format.dateTime) === Ext.Date.format(value, Coon.format.dateTime);
|
|
81
|
+
},
|
|
82
|
+
}, this);
|
|
83
|
+
} else {
|
|
84
|
+
return new Ext.util.Filter({
|
|
85
|
+
filterFn: function(rec) {
|
|
86
|
+
return rec.get(property) === value;
|
|
87
|
+
},
|
|
88
|
+
}, this);
|
|
89
|
+
}
|
|
90
|
+
}, this)
|
|
91
|
+
);
|
|
92
|
+
} else {
|
|
93
|
+
this.grid.getStore().clearFilter();
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
isColumnFiltered() {
|
|
98
|
+
return this.filters.has(this.getColumnKey());
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
showCancelMenuItems: function() {
|
|
102
|
+
const cancelCurrentItem = this.findMenuItem('cancelCurrentColumnFilter');
|
|
103
|
+
cancelCurrentItem && cancelCurrentItem.setHidden(!this.isColumnFiltered());
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
findMenuItem: function(findBy) {
|
|
107
|
+
const contextMenu = this.grid.contextMenu;
|
|
108
|
+
return contextMenu.down(`#${findBy}`);
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
getColumnKey(column) {
|
|
112
|
+
return (column || this.column).initialConfig.dataIndex;
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
clearAllFilters: function() {
|
|
116
|
+
this.filters.clear();
|
|
117
|
+
this.doFilter();
|
|
118
|
+
this.grid.getColumns().forEach((column) => {
|
|
119
|
+
if (column.hasCls('filtered-column')) {
|
|
120
|
+
column.removeCls('filtered-column');
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
clearCurrentColumnFilter: function() {
|
|
126
|
+
this.filters.delete(this.getColumnKey());
|
|
127
|
+
this.doFilter();
|
|
128
|
+
this.changeColumnStyle(this.column);
|
|
129
|
+
},
|
|
130
|
+
|
|
131
|
+
isFilterable: function() {
|
|
132
|
+
if (!this.filterOptions[this.column.dataIndex]) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (Array.isArray(this.columnValue) || Ext.isObject(this.columnValue)) {
|
|
137
|
+
Coon.log.debug('Фильтрация по значению из ячейки невозможна. Сложный тип данных');
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
if (typeof this.columnValue === 'number' && isNaN(this.columnValue)) {
|
|
141
|
+
Coon.log.debug('Фильтрация по значению из ячейки невозможна. Значение NaN');
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
return true;
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
setMenuText(record, cellIndex) {
|
|
148
|
+
const contextMenu = this.grid.contextMenu;
|
|
149
|
+
const columns = this.grid.getColumns();
|
|
150
|
+
const column = columns.length && columns[cellIndex];
|
|
151
|
+
if (!column) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
this.column = column;
|
|
155
|
+
this.columnValue = record.get(column.dataIndex);
|
|
156
|
+
|
|
157
|
+
this.showCancelMenuItems();
|
|
158
|
+
const foundMenuItem = contextMenu.down('#filterByCellValue');
|
|
159
|
+
foundMenuItem.show();
|
|
160
|
+
if (this.filters.size && this.filters.get(this.getColumnKey()) === this.columnValue) {
|
|
161
|
+
foundMenuItem.hide();
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (this.isFilterable()) {
|
|
165
|
+
foundMenuItem.setDisabled(false);
|
|
166
|
+
if (Ext.isDate(this.columnValue)) {
|
|
167
|
+
foundMenuItem.setText(`фильтр по "${Ext.Date.format(this.columnValue, column.format || Coon.format.dateTime)}"`);
|
|
168
|
+
} else if (Ext.isEmpty(this.columnValue)) {
|
|
169
|
+
foundMenuItem.setText(`фильтр по пустому значению`);
|
|
170
|
+
} else {
|
|
171
|
+
foundMenuItem.setText(`фильтр по "${this.columnValue}"`);
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
foundMenuItem.setText(`Нет возможности фильтрации`);
|
|
175
|
+
foundMenuItem.setDisabled(true);
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
});
|
|
@@ -16,16 +16,52 @@ Ext.define('Coon.report.plugin.grid.GridContextMenu', {
|
|
|
16
16
|
}
|
|
17
17
|
this.grid = component;
|
|
18
18
|
this.grid.getView().on({
|
|
19
|
-
cellcontextmenu: {
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
cellcontextmenu: {
|
|
20
|
+
fn: this.cellContextMenuHandler,
|
|
21
|
+
scope: this,
|
|
22
|
+
},
|
|
23
|
+
containercontextmenu: {
|
|
24
|
+
fn: function(view, event) {
|
|
25
|
+
this.showContextMenu({event, view});
|
|
26
|
+
event.preventDefault();
|
|
27
|
+
},
|
|
28
|
+
scope: this,
|
|
29
|
+
},
|
|
22
30
|
});
|
|
23
31
|
|
|
24
32
|
this.grid.contextMenu = Ext.create('Coon.common.tree.BaseContextMenu', {items: this.items});
|
|
33
|
+
this.grid.contextMenu.on('show', this.displacementContextMenu, this);
|
|
34
|
+
this.grid.contextMenu.on('hide', this.restoreCellQtip, this);
|
|
25
35
|
this.grid.getSelectionModel().on('selectionchange', this.updateContext, this);
|
|
26
36
|
this.grid.getStore().on('load', this.updateContext, this);
|
|
27
37
|
},
|
|
28
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Размещение контекстного меню под текстом в ячейке.
|
|
41
|
+
* Удаление qtip (восстанавливается при скрытии контекстного меню)
|
|
42
|
+
*/
|
|
43
|
+
displacementContextMenu: function() {
|
|
44
|
+
const contextMenu = this.grid.contextMenu;
|
|
45
|
+
const cellIndex = contextMenu.cellIndex;
|
|
46
|
+
const columns = this.grid.getColumns();
|
|
47
|
+
const column = columns.length && columns[cellIndex];
|
|
48
|
+
if (!column || !contextMenu.record) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const cell = this.grid.getView().getCell(contextMenu.record, column);
|
|
52
|
+
this.qtipSpan = cell.querySelector('[data-qtip]');
|
|
53
|
+
this.qtipSpan && this.qtipSpan.removeAttribute('data-qtip');
|
|
54
|
+
|
|
55
|
+
contextMenu.alignTo(cell, 'tl-bl');
|
|
56
|
+
|
|
57
|
+
const y = contextMenu.getY();
|
|
58
|
+
contextMenu.setY(y - 7);
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
restoreCellQtip: function() {
|
|
62
|
+
this.qtipSpan && this.qtipSpan.setAttribute('data-qtip', this.columnValue);
|
|
63
|
+
},
|
|
64
|
+
|
|
29
65
|
destroyHandler: function() {
|
|
30
66
|
if (this.grid.contextMenu) {
|
|
31
67
|
this.grid.contextMenu.destroy();
|
|
@@ -33,10 +69,6 @@ Ext.define('Coon.report.plugin.grid.GridContextMenu', {
|
|
|
33
69
|
}
|
|
34
70
|
},
|
|
35
71
|
|
|
36
|
-
containerContextMenuHandler: function(view, e, eOpts) {
|
|
37
|
-
this.showContextMenu(undefined, e);
|
|
38
|
-
},
|
|
39
|
-
|
|
40
72
|
updateContext: function() {
|
|
41
73
|
const grid = this.grid;
|
|
42
74
|
const selected = grid.getSelectionModel().getLastSelected();
|
|
@@ -51,17 +83,20 @@ Ext.define('Coon.report.plugin.grid.GridContextMenu', {
|
|
|
51
83
|
grid.contextMenu.params = params && params.parameterList && Coon.Function.convertProperties(Ext.decode(params.parameterList));
|
|
52
84
|
},
|
|
53
85
|
|
|
54
|
-
cellContextMenuHandler: function(view, td, cellIndex, record, tr, rowIndex,
|
|
86
|
+
cellContextMenuHandler: function(view, td, cellIndex, record, tr, rowIndex, event) {
|
|
55
87
|
this.grid.getSelectionModel().select(rowIndex);
|
|
56
88
|
if (record) {
|
|
57
|
-
this.showContextMenu(record,
|
|
89
|
+
this.showContextMenu({view, td, cellIndex, record, tr, rowIndex, event});
|
|
58
90
|
}
|
|
59
91
|
return false;
|
|
60
92
|
},
|
|
61
93
|
|
|
62
|
-
showContextMenu: function(
|
|
94
|
+
showContextMenu: function({view, td, cellIndex, record, tr, rowIndex, event}) {
|
|
63
95
|
const contextMenu = this.grid.contextMenu;
|
|
64
|
-
|
|
96
|
+
if (record) {
|
|
97
|
+
contextMenu.record = record;
|
|
98
|
+
}
|
|
99
|
+
cellIndex && (contextMenu.cellIndex = cellIndex);
|
|
65
100
|
const store = this.grid.getStore();
|
|
66
101
|
let params;
|
|
67
102
|
if (this.grid instanceof Ext.tree.Panel) {
|
|
@@ -70,7 +105,10 @@ Ext.define('Coon.report.plugin.grid.GridContextMenu', {
|
|
|
70
105
|
params = store.lastOptions && store.lastOptions.params;
|
|
71
106
|
}
|
|
72
107
|
contextMenu.params = params && params.parameterList && Coon.Function.convertProperties(Ext.decode(params.parameterList));
|
|
73
|
-
|
|
108
|
+
contextMenu.fireEvent('requestMenuItems', {view, td, cellIndex, record, tr, rowIndex, event});
|
|
109
|
+
const showMenu = contextMenu.items &&
|
|
110
|
+
contextMenu.items.getRange().find((item) => !item.hidden);
|
|
111
|
+
if (showMenu) {
|
|
74
112
|
contextMenu.show([event.getX(), event.getY()]);
|
|
75
113
|
return this.removeBrowserContextMenu(event);
|
|
76
114
|
}
|
|
@@ -5,6 +5,10 @@ Ext.define('Coon.uielement.component.UiCustomController', {
|
|
|
5
5
|
|
|
6
6
|
init: function(view) {
|
|
7
7
|
const config = view.propertyData || view.initialConfig;
|
|
8
|
+
if (!view || typeof view.on !== 'function') {
|
|
9
|
+
Coon.log.debug(` [Error]UiCustomController.init - view not found or view.on is not a function`);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
8
12
|
view.on('afterrender', function() {
|
|
9
13
|
const {accessDecision, securePoints} = config;
|
|
10
14
|
Coon.log.debug('UiCustomController.accessProps', {accessDecision, securePoints});
|
|
@@ -3,6 +3,8 @@ Ext.define('Coon.uielement.component.formchips.Chip', {
|
|
|
3
3
|
xtype: 'Chip',
|
|
4
4
|
alias: 'widget.Chip',
|
|
5
5
|
defaultListenerScope: true,
|
|
6
|
+
searchRequired: false,
|
|
7
|
+
|
|
6
8
|
config: {
|
|
7
9
|
// Служебный
|
|
8
10
|
service: false,
|
|
@@ -10,6 +12,12 @@ Ext.define('Coon.uielement.component.formchips.Chip', {
|
|
|
10
12
|
unusable: undefined,
|
|
11
13
|
// С кнопкой закрытия
|
|
12
14
|
closable: undefined,
|
|
15
|
+
// Чип критерия для удаленного поиска (если false то для локальной фильтрации в ReportPanel)
|
|
16
|
+
forRemoteSearch: true,
|
|
17
|
+
// Всплывающая подсказка для кнопки закрытия чипа
|
|
18
|
+
deleteChipTooltipMessage: 'Очистить поле формы',
|
|
19
|
+
// Функция колбэка, срабатывающая при закрытии чипа
|
|
20
|
+
removeFilterCallback: undefined,
|
|
13
21
|
},
|
|
14
22
|
tpl: new Ext.XTemplate(
|
|
15
23
|
'<span class="chip-value">{value}</span>',
|
|
@@ -22,15 +30,30 @@ Ext.define('Coon.uielement.component.formchips.Chip', {
|
|
|
22
30
|
},
|
|
23
31
|
|
|
24
32
|
initComponent: function() {
|
|
33
|
+
if (this.forRemoteSearch && this.data) {
|
|
34
|
+
this.originalValue = this.data.value;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
this.configureCls();
|
|
38
|
+
this.callParent();
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
configureCls() {
|
|
42
|
+
const cls = [];
|
|
25
43
|
if (this.getService()) {
|
|
26
|
-
|
|
44
|
+
cls.push('service-chip');
|
|
27
45
|
} else {
|
|
28
|
-
|
|
46
|
+
cls.push(this.getUnusable() ?
|
|
29
47
|
'unusable-chip':
|
|
30
|
-
this.getClosable() ? 'closable-chip' : 'chip';
|
|
48
|
+
this.getClosable() ? 'closable-chip' : 'chip');
|
|
31
49
|
}
|
|
32
50
|
|
|
33
|
-
this.
|
|
51
|
+
if (this.getForRemoteSearch()) {
|
|
52
|
+
cls.push('remote-search-chip');
|
|
53
|
+
} else {
|
|
54
|
+
cls.push('local-search-chip');
|
|
55
|
+
}
|
|
56
|
+
this.cls = cls.join(' ');
|
|
34
57
|
},
|
|
35
58
|
|
|
36
59
|
closeChip: function() {
|
|
@@ -42,6 +65,9 @@ Ext.define('Coon.uielement.component.formchips.Chip', {
|
|
|
42
65
|
chip.fireEvent('delete', field);
|
|
43
66
|
}
|
|
44
67
|
chip.fireEvent('needReloadChips');
|
|
68
|
+
} else if (Ext.isFunction(chip.removeFilterCallback)) {
|
|
69
|
+
chip.removeFilterCallback();
|
|
70
|
+
chip.fireEvent('needReloadChips');
|
|
45
71
|
}
|
|
46
72
|
},
|
|
47
73
|
|
|
@@ -62,6 +88,9 @@ Ext.define('Coon.uielement.component.formchips.Chip', {
|
|
|
62
88
|
if (chip.data.unusable) {
|
|
63
89
|
toolTipText+=`<br>Не использовано при последнем поиске!`;
|
|
64
90
|
}
|
|
91
|
+
if (chip.searchRequired) {
|
|
92
|
+
toolTipText+=`<br>Критерий поиска "${chip.data.label}" изменился. Необходимо выполнить поиск!`;
|
|
93
|
+
}
|
|
65
94
|
tip.update(toolTipText);
|
|
66
95
|
}
|
|
67
96
|
},
|
|
@@ -71,7 +100,7 @@ Ext.define('Coon.uielement.component.formchips.Chip', {
|
|
|
71
100
|
// Тултип для крестика закрытия чипа
|
|
72
101
|
chip.tipClose = Ext.create('Ext.tip.ToolTip', {
|
|
73
102
|
target: chip.el.query('[class=closebtn]')[0],
|
|
74
|
-
html:
|
|
103
|
+
html: this.getDeleteChipTooltipMessage(),
|
|
75
104
|
});
|
|
76
105
|
}
|
|
77
106
|
},
|
|
@@ -84,4 +113,5 @@ Ext.define('Coon.uielement.component.formchips.Chip', {
|
|
|
84
113
|
cmp.tip && cmp.tip.destroy();
|
|
85
114
|
cmp.tipClose && cmp.tipClose.destroy();
|
|
86
115
|
},
|
|
116
|
+
|
|
87
117
|
});
|
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Компонет формы поиска для отображения чипов (типа https://materializecss.com/chips.html) с критериями поиска.
|
|
3
|
-
* Копмонент -
|
|
3
|
+
* Копмонент - тулбар.
|
|
4
|
+
*
|
|
5
|
+
* Поведение.
|
|
6
|
+
* - отображается всегда
|
|
7
|
+
* - включает тул (глаз) для сворачивания формы поиска
|
|
8
|
+
* - при выполнении поиска отображает (перечитывает) чипы с критериями, используемые при поиске.
|
|
9
|
+
* - каждый чип отображает введенное значение критерия (наприпер дату), а при наведении показывает тултип с названием.
|
|
10
|
+
* - чипы не закрываемые
|
|
11
|
+
* - при сворачивании формы поиска в тулбар добавляются кнопки "Поиск" и "Очистить", которые дублируют поведение формы поиска.
|
|
12
|
+
* - каждый чип связан с полем формы и меняет свой вид и содержание тултипа в случае изменения значения в поле поиска.
|
|
13
|
+
*
|
|
14
|
+
* Использование в репорте:
|
|
15
|
+
* Включается свойством репорта - enableChipToolbar.
|
|
16
|
+
*
|
|
17
|
+
* Использование в кастомной панели:
|
|
4
18
|
* Д.быть добавлен в основной контейней кастомной панели, где есть title.
|
|
5
|
-
* В заголовок будет добавлен tool, управляющий
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* 2. Критерии, заполненные на форме поиска, но не использованные при последнем поиске. Отображения бледное.
|
|
10
|
-
* Всегда есть иконка крестика для закрытия чипа.
|
|
11
|
-
* При нажатии "Закрыть" чип будет удален с тулбара, а соответствующий критерий поиска формы будет очищен.
|
|
12
|
-
* Конфигурационный параметр компонента closableFilterCondition в значении true дает чипам типа 1 возможность быть тоже закрываемыми.
|
|
13
|
-
* При закрытии таких чипов компонент формирует событие chipdelete.
|
|
14
|
-
* По этому событию кастомная панель сможет к примеру выполнить новый поиск.
|
|
15
|
-
* Каждый чип отображает введенное значение критерия (наприпер дату), а при наведении показывает тултип с названием
|
|
19
|
+
* В заголовок будет добавлен tool, управляющий сворачиванием формы критериев поиска (Свернуть/Развернуть)
|
|
20
|
+
* (Ссылка на форму поиска по searchFormItemId).
|
|
21
|
+
* Конфигурационный параметр компонента closableFilterCondition пока не используется.
|
|
22
|
+
*
|
|
16
23
|
* критерия поиска (например "Период").
|
|
17
24
|
* Пример использования:
|
|
18
25
|
* @example
|
|
@@ -24,10 +31,12 @@
|
|
|
24
31
|
* {
|
|
25
32
|
* xtype: 'FilterConditionToolbar',
|
|
26
33
|
* reference: 'filterConditionToolbarRef',
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
* dock: 'bottom',
|
|
35
|
+
* listeners: {
|
|
36
|
+
* clear: 'onClearFromChips', // Событие от кнопки "Очистить" из тулбара. Привязать хендлер очистки формы
|
|
37
|
+
* needreload: 'doInitReport', // Событие от кнопки "Поиск" из тулбара. Привязать хендлер выполнения поиска
|
|
38
|
+
* // chipdelete: 'onChipDeleteHandler', // Реакция на закрытие чипа. Например, выполнение нового поиска. НЕ ИСПОЛЬЗУЕТСЯ
|
|
39
|
+
* },
|
|
31
40
|
* },
|
|
32
41
|
* ],
|
|
33
42
|
* ...
|
|
@@ -40,7 +49,7 @@
|
|
|
40
49
|
*}]
|
|
41
50
|
*
|
|
42
51
|
* Обязательно в хендлере выполнения поиска формы нужно добавить формирование события rememberconditions,
|
|
43
|
-
* чтобы тулбар
|
|
52
|
+
* чтобы тулбар ИСПОЛЬЗОВАЛ критерии поиска, использованные для поиска в текущий момент:
|
|
44
53
|
*
|
|
45
54
|
* @example
|
|
46
55
|
* this.lookup('filterConditionToolbarRef').fireEvent('rememberconditions');
|
|
@@ -49,7 +58,7 @@
|
|
|
49
58
|
* 1. Панель, содержащая поля формы поиска, должна иметь itemId searchFormItemId
|
|
50
59
|
*/
|
|
51
60
|
Ext.define('Coon.uielement.component.formchips.FilterConditionToolbar', {
|
|
52
|
-
extend: 'Ext.
|
|
61
|
+
extend: 'Ext.container.Container',
|
|
53
62
|
xtype: 'FilterConditionToolbar',
|
|
54
63
|
alias: 'widget.FilterConditionToolbar',
|
|
55
64
|
cls: 'FilterConditionToolbar',
|
|
@@ -60,10 +69,11 @@ Ext.define('Coon.uielement.component.formchips.FilterConditionToolbar', {
|
|
|
60
69
|
controller: 'filterconditiontoolbarcontroller',
|
|
61
70
|
bodyPadding: 10,
|
|
62
71
|
hidden: true,
|
|
63
|
-
|
|
64
|
-
|
|
72
|
+
layout: {
|
|
73
|
+
type: 'hbox', align: 'stretch',
|
|
74
|
+
},
|
|
65
75
|
listeners: {
|
|
66
|
-
beforerender: '
|
|
76
|
+
beforerender: 'initToolbar',
|
|
67
77
|
boxready: 'fillChipsHandler',
|
|
68
78
|
show: 'fadeInHandler',
|
|
69
79
|
},
|
|
@@ -79,6 +89,34 @@ Ext.define('Coon.uielement.component.formchips.FilterConditionToolbar', {
|
|
|
79
89
|
* Предназначено для вызова из кастомной панели из хендлера
|
|
80
90
|
*/
|
|
81
91
|
|
|
92
|
+
items: [
|
|
93
|
+
{
|
|
94
|
+
xtype: 'toolbar',
|
|
95
|
+
flex: 1,
|
|
96
|
+
overflowHandler: 'menu',
|
|
97
|
+
reference: 'chipsContainer',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
xtype: 'toolbar',
|
|
101
|
+
reference: 'buttonsContainer',
|
|
102
|
+
hidden: true,
|
|
103
|
+
width: 200,
|
|
104
|
+
items: [
|
|
105
|
+
{
|
|
106
|
+
reference: 'searchButton',
|
|
107
|
+
ui: 'orange-button',
|
|
108
|
+
text: 'Поиск',
|
|
109
|
+
handler: 'onSearchButton',
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
reference: 'clearButton',
|
|
113
|
+
ui: 'green-button',
|
|
114
|
+
text: 'Очистить',
|
|
115
|
+
handler: 'onClearButton',
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
}
|
|
119
|
+
],
|
|
82
120
|
config: {
|
|
83
121
|
/**
|
|
84
122
|
* @param {boolean} Если true, то ЧИП, по которому был произведен поиск, можно закрывать. Что приведет к очистке поля, связанного с чипом.
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
.FilterConditionToolbar {
|
|
1
|
+
.x-menu-body .x-box-target, .FilterConditionToolbar {
|
|
2
2
|
|
|
3
3
|
.closable-chip, .unusable-chip, .chip, .service-chip {
|
|
4
4
|
display: inline-block;
|
|
5
5
|
cursor: default;
|
|
6
6
|
padding: 0 15px;
|
|
7
|
-
height:
|
|
8
|
-
line-height:
|
|
9
|
-
border-radius:
|
|
10
|
-
background-color: #f1f1f1;
|
|
7
|
+
height: 26px;
|
|
8
|
+
line-height: 26px;
|
|
9
|
+
border-radius: 13px;
|
|
11
10
|
.chip-value {
|
|
12
11
|
font-size: 13px;
|
|
13
|
-
font-weight: bold;
|
|
14
12
|
}
|
|
15
13
|
.closebtn {
|
|
16
14
|
padding-left: 10px;
|
|
@@ -24,23 +22,46 @@
|
|
|
24
22
|
color: #000;
|
|
25
23
|
}
|
|
26
24
|
}
|
|
25
|
+
.remote-search-chip {
|
|
26
|
+
background-color: #f1f1f1;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.local-search-chip {
|
|
30
|
+
background-color: #dffad3;
|
|
31
|
+
}
|
|
32
|
+
|
|
27
33
|
/* Неиспользованное для поиска поле и сервисное поле */
|
|
28
|
-
.unusable-chip
|
|
34
|
+
.unusable-chip {
|
|
35
|
+
border: 1px solid #ff9800;
|
|
29
36
|
.chip-value {
|
|
30
37
|
font-size: 13px;
|
|
38
|
+
font-style: italic;
|
|
31
39
|
color: gray;
|
|
32
40
|
font-weight: normal;
|
|
33
41
|
}
|
|
34
42
|
}
|
|
35
|
-
|
|
43
|
+
|
|
44
|
+
.service-chip {
|
|
45
|
+
.chip-value {
|
|
46
|
+
font-size: 13px;
|
|
47
|
+
color: gray;
|
|
48
|
+
font-weight: normal;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.chip, .service-chip, .unusable-chip {
|
|
36
53
|
.closebtn {
|
|
37
54
|
display: none;
|
|
38
55
|
}
|
|
39
56
|
}
|
|
57
|
+
|
|
40
58
|
.closable-chip {
|
|
41
59
|
.closebtn {
|
|
42
60
|
display: block;
|
|
43
61
|
}
|
|
44
62
|
}
|
|
45
63
|
|
|
64
|
+
.tool-eye-horus {
|
|
65
|
+
color: #002453;
|
|
66
|
+
}
|
|
46
67
|
}
|