@michalrakus/x-react-web-lib 1.18.0 → 1.20.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.
Files changed (57) hide show
  1. package/XEditor.d.ts +3 -0
  2. package/XEditor.js +5 -0
  3. package/XEditorBase.d.ts +3 -0
  4. package/XEditorBase.js +5 -0
  5. package/XExportRowsDialog.d.ts +1 -1
  6. package/XExportRowsDialog.js +1 -1
  7. package/XHtmlRenderer.d.ts +3 -0
  8. package/XHtmlRenderer.js +5 -0
  9. package/XLazyDataTable.d.ts +1 -1
  10. package/XLazyDataTable.js +1 -1
  11. package/XMultilineRenderer.d.ts +3 -0
  12. package/XMultilineRenderer.js +5 -0
  13. package/gulpfile.js +7 -2
  14. package/lib/administration/XBrowseMetaBrowse.d.ts +1 -1
  15. package/lib/administration/XBrowseMetaBrowse.js +1 -1
  16. package/lib/administration/XUserBrowse.d.ts +1 -1
  17. package/lib/administration/XUserBrowse.js +1 -1
  18. package/lib/components/XAutoComplete.d.ts +11 -9
  19. package/lib/components/XAutoComplete.js +7 -78
  20. package/lib/components/XAutoCompleteBase.d.ts +42 -7
  21. package/lib/components/XAutoCompleteBase.js +342 -45
  22. package/lib/components/XAutoCompleteDT.d.ts +14 -8
  23. package/lib/components/XAutoCompleteDT.js +3 -69
  24. package/lib/components/XEditBrowse.js +1 -1
  25. package/lib/components/XEditor.d.ts +15 -0
  26. package/lib/components/XEditor.js +64 -0
  27. package/lib/components/XEditorBase.d.ts +9 -0
  28. package/lib/components/XEditorBase.js +91 -0
  29. package/lib/components/XFormBase.d.ts +1 -0
  30. package/lib/components/XFormBase.js +19 -4
  31. package/lib/components/XFormDataTable2.js +1 -1
  32. package/lib/components/XInputTextareaBase.js +3 -4
  33. package/lib/components/{XExportRowsDialog.d.ts → XLazyDataTable/XExportRowsDialog.d.ts} +1 -1
  34. package/lib/components/{XExportRowsDialog.js → XLazyDataTable/XExportRowsDialog.js} +5 -5
  35. package/lib/components/XLazyDataTable/XHtmlRenderer.d.ts +7 -0
  36. package/lib/components/XLazyDataTable/XHtmlRenderer.js +78 -0
  37. package/lib/components/{XLazyDataTable.d.ts → XLazyDataTable/XLazyDataTable.d.ts} +20 -8
  38. package/lib/components/{XLazyDataTable.js → XLazyDataTable/XLazyDataTable.js} +62 -36
  39. package/lib/components/XLazyDataTable/XMultilineRenderer.d.ts +8 -0
  40. package/lib/components/XLazyDataTable/XMultilineRenderer.js +80 -0
  41. package/lib/components/XLazyDataTable/XMultilineSwitch.d.ts +7 -0
  42. package/lib/components/XLazyDataTable/XMultilineSwitch.js +20 -0
  43. package/lib/components/XSearchBrowseParams.d.ts +2 -2
  44. package/lib/components/XSearchButton.js +2 -2
  45. package/lib/components/XSearchButtonDT.js +2 -2
  46. package/lib/components/XUtils.d.ts +4 -0
  47. package/lib/components/XUtils.js +51 -11
  48. package/lib/components/XUtilsMetadata.d.ts +1 -1
  49. package/lib/serverApi/FindParam.d.ts +12 -2
  50. package/lib/serverApi/FindParam.js +3 -2
  51. package/lib/serverApi/XUtilsCommon.d.ts +2 -0
  52. package/lib/serverApi/XUtilsCommon.js +37 -1
  53. package/lib/serverApi/XUtilsMetadataCommon.d.ts +1 -0
  54. package/lib/serverApi/XUtilsMetadataCommon.js +16 -0
  55. package/lib/serverApi/x-lib-api.d.ts +6 -0
  56. package/lib/serverApi/x-lib-api.js +3 -0
  57. package/package.json +2 -1
@@ -48,6 +48,42 @@ var __importStar = (this && this.__importStar) || function (mod) {
48
48
  __setModuleDefault(result, mod);
49
49
  return result;
50
50
  };
51
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
52
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
53
+ return new (P || (P = Promise))(function (resolve, reject) {
54
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
55
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
56
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
57
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
58
+ });
59
+ };
60
+ var __generator = (this && this.__generator) || function (thisArg, body) {
61
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
62
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
63
+ function verb(n) { return function (v) { return step([n, v]); }; }
64
+ function step(op) {
65
+ if (f) throw new TypeError("Generator is already executing.");
66
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
67
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
68
+ if (y = 0, t) op = [op[0] & 2, t.value];
69
+ switch (op[0]) {
70
+ case 0: case 1: t = op; break;
71
+ case 4: _.label++; return { value: op[1], done: false };
72
+ case 5: _.label++; y = op[1]; op = [0]; continue;
73
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
74
+ default:
75
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
76
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
77
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
78
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
79
+ if (t[2]) _.ops.pop();
80
+ _.trys.pop(); continue;
81
+ }
82
+ op = body.call(thisArg, _);
83
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
84
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
85
+ }
86
+ };
51
87
  var __read = (this && this.__read) || function (o, n) {
52
88
  var m = typeof Symbol === "function" && o[Symbol.iterator];
53
89
  if (!m) return o;
@@ -73,6 +109,17 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
73
109
  }
74
110
  return to.concat(ar || Array.prototype.slice.call(from));
75
111
  };
112
+ var __values = (this && this.__values) || function(o) {
113
+ var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
114
+ if (m) return m.call(o);
115
+ if (o && typeof o.length === "number") return {
116
+ next: function () {
117
+ if (o && i >= o.length) o = void 0;
118
+ return { value: o && o[i++], done: !o };
119
+ }
120
+ };
121
+ throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
122
+ };
76
123
  Object.defineProperty(exports, "__esModule", { value: true });
77
124
  exports.XAutoCompleteBase = void 0;
78
125
  var react_1 = __importStar(require("react"));
@@ -81,6 +128,7 @@ var splitbutton_1 = require("primereact/splitbutton");
81
128
  var dialog_1 = require("primereact/dialog");
82
129
  var XUtils_1 = require("./XUtils");
83
130
  var button_1 = require("primereact/button");
131
+ var XUtilsCommon_1 = require("../serverApi/XUtilsCommon");
84
132
  var XAutoCompleteBase = /** @class */ (function (_super) {
85
133
  __extends(XAutoCompleteBase, _super);
86
134
  function XAutoCompleteBase(props) {
@@ -90,63 +138,228 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
90
138
  inputChanged: false,
91
139
  inputValueState: undefined,
92
140
  notValid: false,
141
+ suggestions: undefined,
93
142
  filteredSuggestions: undefined,
94
143
  formDialogOpened: false,
95
144
  searchDialogOpened: false
96
145
  };
97
- _this.wasSearchStartCalled = false;
146
+ _this.suggestionsLoadedForOSS = false;
147
+ _this.wasOnChangeCalled = false;
98
148
  _this.completeMethod = _this.completeMethod.bind(_this);
99
149
  _this.onChange = _this.onChange.bind(_this);
100
150
  _this.onSelect = _this.onSelect.bind(_this);
101
151
  _this.onBlur = _this.onBlur.bind(_this);
152
+ _this.itemTemplate = _this.itemTemplate.bind(_this);
153
+ _this.itemTemplateString = _this.itemTemplateString.bind(_this);
154
+ _this.computeDefaultDisplayValue = _this.computeDefaultDisplayValue.bind(_this);
102
155
  _this.formDialogOnSaveOrCancel = _this.formDialogOnSaveOrCancel.bind(_this);
103
156
  _this.formDialogOnHide = _this.formDialogOnHide.bind(_this);
104
157
  _this.searchDialogOnChoose = _this.searchDialogOnChoose.bind(_this);
105
158
  _this.searchDialogOnHide = _this.searchDialogOnHide.bind(_this);
106
159
  return _this;
107
160
  }
161
+ XAutoCompleteBase.prototype.getXSuggestionsLoadType = function () {
162
+ var suggestionsLoadType;
163
+ if (this.props.suggestions) {
164
+ suggestionsLoadType = "suggestions";
165
+ }
166
+ else if (!this.props.suggestionsLoad) {
167
+ suggestionsLoadType = "onSearchStart"; // default
168
+ }
169
+ else {
170
+ suggestionsLoadType = this.props.suggestionsLoad;
171
+ }
172
+ return suggestionsLoadType;
173
+ };
174
+ // helper
175
+ XAutoCompleteBase.prototype.getFields = function () {
176
+ return Array.isArray(this.props.field) ? this.props.field : [this.props.field];
177
+ };
178
+ XAutoCompleteBase.prototype.getFirstField = function () {
179
+ return this.getFields()[0];
180
+ };
108
181
  XAutoCompleteBase.prototype.componentDidMount = function () {
182
+ if (this.getXSuggestionsLoadType() === "eager") {
183
+ this.loadSuggestions();
184
+ }
109
185
  if (this.props.setFocusOnCreate) {
110
186
  this.setFocusToInput();
111
187
  }
112
188
  };
113
- XAutoCompleteBase.prototype.completeMethod = function (event) {
114
- var _this = this;
115
- var filteredSuggestions;
116
- if (!event.query.trim().length) {
117
- filteredSuggestions = __spreadArray([], __read(this.props.suggestions), false);
118
- }
119
- else {
120
- var queryNormalized_1 = XUtils_1.XUtils.normalizeString(event.query);
121
- filteredSuggestions = this.props.suggestions.filter(function (suggestion) {
122
- var fieldValue = suggestion[_this.props.field];
123
- // specialna null polozka (prazdny objekt) - test dame az za test fieldValue na undefined - koli performance
124
- if (fieldValue === undefined && Object.keys(suggestion).length === 0) {
125
- return false;
189
+ XAutoCompleteBase.prototype.loadSuggestions = function () {
190
+ return __awaiter(this, void 0, void 0, function () {
191
+ var suggestions;
192
+ return __generator(this, function (_a) {
193
+ switch (_a.label) {
194
+ case 0: return [4 /*yield*/, this.fetchSuggestions()];
195
+ case 1:
196
+ suggestions = _a.sent();
197
+ this.setState({ suggestions: suggestions });
198
+ return [2 /*return*/];
126
199
  }
127
- // bolo:
128
- //return XUtils.normalizeString(fieldValue).startsWith(queryNormalized);
129
- return XUtils_1.XUtils.normalizeString(fieldValue).indexOf(queryNormalized_1) !== -1;
130
200
  });
131
- }
132
- this.setState({ filteredSuggestions: filteredSuggestions });
201
+ });
133
202
  };
134
- XAutoCompleteBase.prototype.onChange = function (e) {
135
- if (typeof e.value === 'string') {
136
- // ak user zacne typovat znaky, nacitame suggestions, ak sme lazy (onSearchStart !== undefined)
137
- if (this.props.onSearchStart) {
138
- if (e.value !== '') { // ak user vymaze cely input, este nechceme nacitat suggestions, az ked zapise nejaky znak
139
- if (!this.wasSearchStartCalled) {
140
- this.props.onSearchStart();
141
- this.wasSearchStartCalled = true; // ak user dalej typuje, nechceme znova nacitavat suggestions
142
- }
203
+ XAutoCompleteBase.prototype.fetchSuggestions = function () {
204
+ return __awaiter(this, void 0, void 0, function () {
205
+ return __generator(this, function (_a) {
206
+ if (!this.props.suggestionsQuery) {
207
+ throw "XAutoCompleteBase.loadSuggestions: unexpected error - prop suggestionsQuery is undefined";
143
208
  }
209
+ return [2 /*return*/, XUtils_1.XUtils.fetchRows(this.props.suggestionsQuery.entity, XUtils_1.XUtils.evalFilter(this.props.suggestionsQuery.filter), this.getSortField(), this.props.suggestionsQuery.fields)];
210
+ });
211
+ });
212
+ };
213
+ XAutoCompleteBase.prototype.getSortField = function () {
214
+ var sortField = this.props.suggestionsQuery.sortField;
215
+ if (!sortField) {
216
+ // len pri ne-lazy pouzivame ako default sort prvy displayField
217
+ // pri lazy to spomaluje selecty v pripade ze klauzula LIMIT vyrazne obmedzi vysledny zoznam suggestions
218
+ // pri lazy zosortujeme na frontende v XAutoCompleteBase
219
+ if (this.getXSuggestionsLoadType() !== "lazy") {
220
+ sortField = this.getFirstField();
144
221
  }
222
+ }
223
+ return sortField;
224
+ };
225
+ XAutoCompleteBase.prototype.completeMethod = function (event) {
226
+ return __awaiter(this, void 0, void 0, function () {
227
+ var filteredSuggestions, xSuggestionsLoadType, suggestions, queryNormalized, queryNormalizedList_1, filter, suggestionsRequest, findResult;
228
+ var _this = this;
229
+ return __generator(this, function (_a) {
230
+ switch (_a.label) {
231
+ case 0:
232
+ xSuggestionsLoadType = this.getXSuggestionsLoadType();
233
+ if (!(xSuggestionsLoadType !== "lazy")) return [3 /*break*/, 8];
234
+ suggestions = void 0;
235
+ if (!(xSuggestionsLoadType === "suggestions")) return [3 /*break*/, 1];
236
+ suggestions = this.props.suggestions;
237
+ return [3 /*break*/, 7];
238
+ case 1:
239
+ if (!(xSuggestionsLoadType === "eager")) return [3 /*break*/, 2];
240
+ suggestions = this.state.suggestions;
241
+ return [3 /*break*/, 7];
242
+ case 2:
243
+ if (!(xSuggestionsLoadType === "onSearchStart")) return [3 /*break*/, 6];
244
+ if (!!this.suggestionsLoadedForOSS) return [3 /*break*/, 4];
245
+ return [4 /*yield*/, this.fetchSuggestions()];
246
+ case 3:
247
+ suggestions = _a.sent();
248
+ // ulozime si
249
+ this.setState({ suggestions: suggestions });
250
+ this.suggestionsLoadedForOSS = true; // ak user dalej typuje, nechceme znova nacitavat suggestions
251
+ return [3 /*break*/, 5];
252
+ case 4:
253
+ // uz mame nacitane
254
+ suggestions = this.state.suggestions;
255
+ _a.label = 5;
256
+ case 5: return [3 /*break*/, 7];
257
+ case 6: throw 'Unexpected error - unknown xSuggestionsLoadType';
258
+ case 7:
259
+ if (!event.query.trim().length) {
260
+ // input je prazdny - volanie sem nastane ak user otvori dropdown cez dropdown button
261
+ filteredSuggestions = __spreadArray([], __read(suggestions), false);
262
+ }
263
+ else {
264
+ queryNormalized = XUtils_1.XUtils.normalizeString(event.query);
265
+ if (this.props.splitQueryValue) {
266
+ queryNormalizedList_1 = queryNormalized.split(' ').filter(function (value) { return value !== ''; }); // nechceme pripadne prazdne retazce ''
267
+ }
268
+ else {
269
+ queryNormalizedList_1 = [queryNormalized]; // nesplitujeme
270
+ }
271
+ filteredSuggestions = suggestions.filter(function (suggestion) {
272
+ var e_1, _a;
273
+ var fieldValue = _this.itemTemplateString(suggestion);
274
+ // specialna null polozka (prazdny objekt) - test dame az za test fieldValue na undefined - koli performance
275
+ if (fieldValue === undefined && Object.keys(suggestion).length === 0) {
276
+ return false;
277
+ }
278
+ var fieldValueNormalized = XUtils_1.XUtils.normalizeString(fieldValue);
279
+ // all partial query values must match
280
+ var match = true;
281
+ try {
282
+ for (var queryNormalizedList_2 = __values(queryNormalizedList_1), queryNormalizedList_2_1 = queryNormalizedList_2.next(); !queryNormalizedList_2_1.done; queryNormalizedList_2_1 = queryNormalizedList_2.next()) {
283
+ var queryItemNormalized = queryNormalizedList_2_1.value;
284
+ // look for substring
285
+ if (fieldValueNormalized.indexOf(queryItemNormalized) === -1) {
286
+ match = false;
287
+ break;
288
+ }
289
+ }
290
+ }
291
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
292
+ finally {
293
+ try {
294
+ if (queryNormalizedList_2_1 && !queryNormalizedList_2_1.done && (_a = queryNormalizedList_2.return)) _a.call(queryNormalizedList_2);
295
+ }
296
+ finally { if (e_1) throw e_1.error; }
297
+ }
298
+ return match;
299
+ });
300
+ }
301
+ return [3 /*break*/, 10];
302
+ case 8:
303
+ // ************* lazy ***************
304
+ // na backendev SELECT-e pouzijeme klauzulu LIMIT <maxRows + 1>
305
+ // ak najdeme menej ako <maxRows + 1> zaznamov tak vieme ze sme nasli vsetky
306
+ // ak najdeme presne <maxRows + 1> zaznamov, tak na konci zobrazime uzivatelovi specialnu polozku "..."
307
+ // ktora ho upozorni ze existuju aj dalsie zaznamy splnujuce podmienku
308
+ // pikoska - ak je query je velmi siroke (select by bez LIMIT <maxRows + 1> vratil mnoho zaznamov),
309
+ // tak je takyto select velmi lacny (niekolko ms) - staci totiz najst prvych napr. 20 zaznamov splnujucich podmienku, t.j. netreba robit full-table scan
310
+ // to ale plati len v pripade ze nepouzijeme ORDER BY - pri pouziti ORDER BY urobi full-table scan (vyfiltruje) a nasledne zosortuje
311
+ // toto sa da obist specialnym selectom:
312
+ // select t.* from (select t0.* from table t0 order by t0.<attr1>) t where <full-text-condition> limit 20
313
+ // (najprv zosortuje a az potom filtruje prvych 20 zaznamov - predpoklad je ze nad t0.<attr1> mame index aby rychlo sortoval)
314
+ // tento specialny select mozme v buducnosti dorobit (na backende) ak chceme podporovat (rychle) sortovanie v DB pre autocomplete
315
+ if (!this.props.suggestionsQuery) {
316
+ throw "XAutoCompleteBase.loadSuggestions: unexpected error - prop suggestionsQuery is undefined";
317
+ }
318
+ filter = XUtils_1.XUtils.evalFilter(this.props.suggestionsQuery.filter);
319
+ suggestionsRequest = {
320
+ maxRows: this.props.lazyLoadMaxRows + 1,
321
+ fullTextSearch: { fields: this.getFields(), value: event.query.trim(), splitValue: this.props.splitQueryValue, matchMode: "contains" },
322
+ entity: this.props.suggestionsQuery.entity,
323
+ filterItems: XUtils_1.XUtils.createCustomFilterItems(filter),
324
+ multiSortMeta: XUtils_1.XUtils.createMultiSortMeta(this.getSortField()),
325
+ fields: this.props.suggestionsQuery.fields
326
+ };
327
+ return [4 /*yield*/, XUtils_1.XUtils.fetchOne('x-lazy-auto-complete-suggestions', suggestionsRequest)];
328
+ case 9:
329
+ findResult = _a.sent();
330
+ filteredSuggestions = findResult.rowList;
331
+ // ak sme nesortovali v DB (co je draha operacia) tak zosortujeme teraz
332
+ // (itemTemplateString sa vola duplicitne ale pre tych cca 20 zaznamov je to ok)
333
+ if (this.props.suggestionsQuery.sortField === undefined) {
334
+ filteredSuggestions = XUtils_1.XUtils.arraySort(filteredSuggestions, this.itemTemplateString);
335
+ }
336
+ // ak mame o 1 zaznam viac ako je lazyLoadMaxRows, zmenime posledny zaznam na ...
337
+ // TODO - lepsie by bolo posledny zaznam vyhodit a popisok ... zobrazit do footer-a (odpadnu problemy z pripadnou selekciou pseudozaznamu ...)
338
+ if (filteredSuggestions.length > this.props.lazyLoadMaxRows) {
339
+ filteredSuggestions[filteredSuggestions.length - 1] = XAutoCompleteBase.valueMoreSuggestions; // zatial priamo string
340
+ }
341
+ _a.label = 10;
342
+ case 10:
343
+ this.setState({ filteredSuggestions: filteredSuggestions });
344
+ return [2 /*return*/];
345
+ }
346
+ });
347
+ });
348
+ };
349
+ XAutoCompleteBase.prototype.onChange = function (e) {
350
+ if (typeof e.value === 'string' && !XAutoCompleteBase.isMoreSuggestions(e.value)) {
145
351
  this.setState({ inputChanged: true, inputValueState: e.value });
352
+ this.wasOnChangeCalled = false; // reset na default hodnotu
146
353
  }
147
354
  };
148
355
  XAutoCompleteBase.prototype.onSelect = function (e) {
149
- this.setObjectValue(e.value, XUtils_1.OperationType.None);
356
+ // nevolame this.setObjectValue ak uz bol zavolany z onBlur
357
+ if (!this.wasOnChangeCalled) {
358
+ // nedovolime vybrat specialny zaznam ...
359
+ if (!XAutoCompleteBase.isMoreSuggestions(e.value)) {
360
+ this.setObjectValue(e.value, XUtils_1.OperationType.None);
361
+ }
362
+ }
150
363
  };
151
364
  XAutoCompleteBase.prototype.onBlur = function (e) {
152
365
  // optimalizacia - testujeme len ak inputChanged === true
@@ -159,6 +372,11 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
159
372
  var filteredSuggestions = this.state.filteredSuggestions;
160
373
  if (filteredSuggestions && filteredSuggestions.length === 1) {
161
374
  this.setObjectValue(filteredSuggestions[0], XUtils_1.OperationType.None);
375
+ // ak bol tento this.setObjectValue vyvolany klikom do suggestions dropdown-u,
376
+ // tak bude este nasledne zavolany onSelect a tam chceme zamedzit volaniu this.setObjectValue,
377
+ // preto nastavujeme tento priznak
378
+ // priznak vratime naspet na false ak uzivatel zacne cokolvek robit s autocomplete (zacne don typovat alebo klikne na dropdown)
379
+ this.wasOnChangeCalled = true;
162
380
  }
163
381
  else {
164
382
  // tu by sme mohli skusit vyratat vysledok pre filteredSuggestions este raz, mozno este vypocet filteredSuggestions nedobehol
@@ -190,8 +408,9 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
190
408
  }
191
409
  }
192
410
  }
193
- // odchadzame z inputu, zresetujeme priznak - ak zacne user pracovat s autocomplete-om, nacitaju sa suggestions z DB (ak mame lazy)
194
- this.wasSearchStartCalled = false;
411
+ // odchadzame z inputu, zresetujeme priznak - ak zacne user pracovat s autocomplete-om, nacitaju sa suggestions z DB (ak mame suggestionsLoad = onSearchStart)
412
+ // suggestions chceme nacitat, lebo user moze zmenit iny atribut ktory ovplyvnuje filter autocomplete-u -> chceme novy zoznam suggestions
413
+ this.suggestionsLoadedForOSS = false;
195
414
  };
196
415
  XAutoCompleteBase.prototype.createErrorMessage = function () {
197
416
  return "Value \"".concat(this.state.inputValueState, "\" was not found among valid values.");
@@ -231,6 +450,14 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
231
450
  if (object !== null) {
232
451
  // ak bol save, treba tento novy object pouzit
233
452
  this.setObjectValue(object, objectChange);
453
+ // ak pouzivame zoznam this.state.suggestions, tak ho rereadneme
454
+ // poznamka: ak pouzivame this.props.suggestions z parenta, tak si musi zoznam rereadnut parent!
455
+ if (objectChange !== XUtils_1.OperationType.None) {
456
+ // zmenil sa zaznam dobrovolnika v DB
457
+ // zatial len refreshneme z DB
458
+ // ak by bol reqest pomaly, mozme pri inserte (nove id) / update (existujuce id) upravit zoznam a usetrime tym request do DB
459
+ this.loadSuggestions();
460
+ }
234
461
  // treba upravit this.state.filteredSuggestions? setli sme novy objekt, panel so suggestions by mal byt zavrety - TODO - overit
235
462
  }
236
463
  else {
@@ -270,7 +497,7 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
270
497
  _this.formDialogInitValuesForInsert = {};
271
498
  // ak mame nevalidnu hodnotu, tak ju predplnime (snaha o user friendly)
272
499
  if (_this.state.inputChanged) {
273
- _this.formDialogInitValuesForInsert[_this.props.field] = _this.state.inputValueState;
500
+ _this.formDialogInitValuesForInsert[_this.getFirstField()] = _this.state.inputValueState;
274
501
  }
275
502
  _this.setState({ formDialogOpened: true });
276
503
  }
@@ -329,15 +556,9 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
329
556
  });
330
557
  };
331
558
  XAutoCompleteBase.prototype.onOpenDropdown = function (e) {
332
- var _this = this;
333
- if (this.props.onSearchStart) {
334
- this.props.onSearchStart(function () { return _this.openDropdown(e); });
335
- }
336
- else {
337
- // otvori dropdown (search je metoda popisana v API, volanie sme skopcili zo zdrojakov primereact)
338
- //this.autoCompleteRef.current.search(e, '', 'dropdown');
339
- this.openDropdown(e);
340
- }
559
+ this.openDropdown(e);
560
+ this.suggestionsLoadedForOSS = false; // user mohol vyplnit nieco co meni filter a ide znova pracovat s autocomplete, nacitame suggestions znova (suggestionsLoad = onSearchStart)
561
+ this.wasOnChangeCalled = false; // reset na default hodnotu
341
562
  };
342
563
  XAutoCompleteBase.prototype.openDropdown = function (e) {
343
564
  // otvori dropdown (search je metoda popisana v API, volanie sme skopcili zo zdrojakov primereact)
@@ -358,19 +579,88 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
358
579
  if (!this.state.inputChanged) {
359
580
  // poznamka: ak object === null tak treba do inputu zapisovat prazdny retazec, ak by sme pouzili null, neprejavila by sa zmena v modeli na null
360
581
  var object = this.props.value;
361
- inputValue = (object !== null) ? object : ""; // TODO - je "" ok?
582
+ inputValue = (object !== null) ? this.computeItemTemplate(object, -1, true) : ""; // TODO - je "" ok?
362
583
  }
363
584
  else {
364
585
  inputValue = this.state.inputValueState;
365
586
  }
366
587
  return inputValue;
367
588
  };
589
+ XAutoCompleteBase.prototype.itemTemplate = function (suggestion, index) {
590
+ return this.computeItemTemplate(suggestion, index, false);
591
+ };
592
+ // pouziva sa na vytvorenie hodnoty do inputu (vyselectovany zaznam) a tiez na pripadne sortovanie a filtrovanie na frontende (ak nepouzivame lazy nacitavanie)
593
+ XAutoCompleteBase.prototype.itemTemplateString = function (suggestion) {
594
+ var itemValue = this.computeItemTemplate(suggestion, -1, true);
595
+ if (typeof itemValue !== "string") {
596
+ throw "XAutoCompleteBase: function of the property itemTemplate created non-string value for suggestion. Please create string value if parameter createStringValue = true.";
597
+ }
598
+ return itemValue;
599
+ };
600
+ XAutoCompleteBase.prototype.computeItemTemplate = function (suggestion, index, createStringValue) {
601
+ var itemTemplate;
602
+ // osetrenie specialnej polozky ... dame sem, nech sa to nemusi inde riesit
603
+ if (XAutoCompleteBase.isMoreSuggestions(suggestion)) {
604
+ itemTemplate = suggestion;
605
+ }
606
+ else {
607
+ if (this.props.itemTemplate) {
608
+ itemTemplate = this.props.itemTemplate(suggestion, index, createStringValue, this.computeDefaultDisplayValue);
609
+ }
610
+ else {
611
+ itemTemplate = this.computeDefaultDisplayValue(suggestion);
612
+ }
613
+ }
614
+ return itemTemplate;
615
+ };
616
+ XAutoCompleteBase.prototype.computeDefaultDisplayValue = function (suggestion) {
617
+ var e_2, _a;
618
+ var displayValue = "";
619
+ if (XAutoCompleteBase.isMoreSuggestions(suggestion)) {
620
+ displayValue = suggestion;
621
+ }
622
+ else {
623
+ try {
624
+ for (var _b = __values(this.getFields()), _c = _b.next(); !_c.done; _c = _b.next()) {
625
+ var field = _c.value;
626
+ // TODO - konverzie na spravny typ/string
627
+ var _d = __read(XUtilsCommon_1.XUtilsCommon.getPrefixAndField(field), 2), prefix = _d[0], fieldOnly = _d[1];
628
+ var value = XUtilsCommon_1.XUtilsCommon.getValueByPath(suggestion, fieldOnly);
629
+ if (value !== null && value !== undefined) {
630
+ var valueStr = value.toString(); // TODO - spravnu konverziu
631
+ if (valueStr !== "") {
632
+ if (displayValue !== "") {
633
+ displayValue += " ";
634
+ }
635
+ if (prefix) {
636
+ displayValue += prefix;
637
+ }
638
+ displayValue += valueStr;
639
+ }
640
+ }
641
+ }
642
+ }
643
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
644
+ finally {
645
+ try {
646
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
647
+ }
648
+ finally { if (e_2) throw e_2.error; }
649
+ }
650
+ }
651
+ return displayValue;
652
+ };
653
+ // vrati true ak sa jedna o specialny typ XAutoCompleteBase.valueMoreSuggestions
654
+ XAutoCompleteBase.isMoreSuggestions = function (suggestion) {
655
+ return typeof suggestion === "string" && suggestion === XAutoCompleteBase.valueMoreSuggestions;
656
+ };
368
657
  // takto cez metodku, mozno sa metodka vola len ked sa otvori dialog a usetrime nieco...
369
658
  XAutoCompleteBase.prototype.createSearchBrowseParams = function () {
659
+ var _a;
370
660
  return {
371
661
  onChoose: this.searchDialogOnChoose,
372
- displayFieldFilter: (this.state.inputChanged ? { field: this.props.field, constraint: { value: this.state.inputValueState, matchMode: "startsWith" } } : undefined),
373
- customFilterFunction: this.props.customFilterFunction
662
+ displayFieldFilter: (this.state.inputChanged ? { field: this.getFirstField(), constraint: { value: this.state.inputValueState, matchMode: "contains" } } : undefined),
663
+ customFilter: (_a = this.props.suggestionsQuery) === null || _a === void 0 ? void 0 : _a.filter
374
664
  };
375
665
  };
376
666
  XAutoCompleteBase.prototype.render = function () {
@@ -421,7 +711,7 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
421
711
  // <DobrovolnikForm id={this.formDialogObjectId} object={this.formDialogInitValuesForInsert} onSaveOrCancel={this.formDialogOnSaveOrCancel}/>
422
712
  // formgroup-inline lepi SplitButton na autocomplete a zarovna jeho vysku
423
713
  return (react_1.default.createElement("div", { className: "x-auto-complete-base", style: { width: this.props.width } },
424
- react_1.default.createElement(autocomplete_1.AutoComplete, __assign({ value: inputValue, suggestions: this.state.filteredSuggestions, completeMethod: this.completeMethod, field: this.props.field, onChange: this.onChange, onSelect: this.onSelect, onBlur: this.onBlur, maxLength: this.props.maxLength, ref: this.autoCompleteRef, readOnly: readOnly, disabled: readOnly }, XUtils_1.XUtils.createErrorProps(error))),
714
+ react_1.default.createElement(autocomplete_1.AutoComplete, __assign({ value: inputValue, suggestions: this.state.filteredSuggestions, completeMethod: this.completeMethod, itemTemplate: this.itemTemplate, onChange: this.onChange, onSelect: this.onSelect, onBlur: this.onBlur, minLength: this.props.minLength, scrollHeight: this.props.scrollHeight, ref: this.autoCompleteRef, readOnly: readOnly, disabled: readOnly }, XUtils_1.XUtils.createErrorProps(error), { inputClassName: this.props.inputClassName })),
425
715
  dropdownButton,
426
716
  this.props.valueForm != undefined ?
427
717
  react_1.default.createElement(dialog_1.Dialog, { visible: this.state.formDialogOpened, onHide: this.formDialogOnHide, header: this.formDialogObjectId ? 'Modification' : 'New row' }, react_1.default.cloneElement(this.props.valueForm, {
@@ -432,6 +722,13 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
432
722
  react_1.default.createElement(dialog_1.Dialog, { visible: this.state.searchDialogOpened, onHide: this.searchDialogOnHide }, react_1.default.cloneElement(this.props.searchBrowse, { searchBrowseParams: this.createSearchBrowseParams() } /*, props.searchBrowse.children*/))
433
723
  : undefined));
434
724
  };
725
+ XAutoCompleteBase.valueMoreSuggestions = "...";
726
+ XAutoCompleteBase.defaultProps = {
727
+ lazyLoadMaxRows: 10,
728
+ splitQueryValue: true,
729
+ minLength: 1,
730
+ scrollHeight: '15rem' // primereact has 200px
731
+ };
435
732
  return XAutoCompleteBase;
436
733
  }(react_1.Component));
437
734
  exports.XAutoCompleteBase = XAutoCompleteBase;
@@ -1,26 +1,32 @@
1
- /// <reference types="react" />
1
+ import React from "react";
2
2
  import { XFormComponentDT, XFormComponentDTProps } from "./XFormComponentDT";
3
3
  import { XAssoc } from "../serverApi/XEntityMetadata";
4
4
  import { OperationType } from "./XUtils";
5
5
  import { XError } from "./XErrors";
6
+ import { XSuggestionsLoadProp } from "./XAutoCompleteBase";
6
7
  import { XTableFieldFilterProp } from "./XFormDataTable2";
8
+ import { DataTableSortMeta } from "primereact/datatable";
7
9
  export interface XAutoCompleteDTProps extends XFormComponentDTProps {
8
10
  assocField: string;
9
- displayField: string;
11
+ displayField: string | string[];
12
+ itemTemplate?: (suggestion: any, index: number, createStringValue: boolean, defaultValue: (suggestion: any) => string) => React.ReactNode;
10
13
  searchBrowse?: JSX.Element;
11
14
  assocForm?: JSX.Element;
12
- filter?: XTableFieldFilterProp;
13
15
  suggestions?: any[];
16
+ suggestionsLoad?: XSuggestionsLoadProp;
17
+ lazyLoadMaxRows?: number;
18
+ splitQueryValue?: boolean;
19
+ minLength?: number;
20
+ filter?: XTableFieldFilterProp;
21
+ sortField?: string | DataTableSortMeta[];
22
+ fields?: string[];
23
+ scrollHeight?: string;
24
+ inputClassName?: string;
14
25
  }
15
26
  export declare class XAutoCompleteDT extends XFormComponentDT<XAutoCompleteDTProps> {
16
27
  protected xAssoc: XAssoc;
17
28
  protected errorInBase: string | undefined;
18
- state: {
19
- suggestions: any[];
20
- };
21
29
  constructor(props: XAutoCompleteDTProps);
22
- componentDidMount(): void;
23
- readAndSetSuggestions(): Promise<void>;
24
30
  getField(): string;
25
31
  isNotNull(): boolean;
26
32
  getValue(): any | null;