@michalrakus/x-react-web-lib 1.17.0 → 1.19.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 (43) hide show
  1. package/lib/components/XAutoComplete.d.ts +9 -9
  2. package/lib/components/XAutoComplete.js +7 -78
  3. package/lib/components/XAutoCompleteBase.d.ts +39 -7
  4. package/lib/components/XAutoCompleteBase.js +351 -64
  5. package/lib/components/XAutoCompleteDT.d.ts +10 -6
  6. package/lib/components/XAutoCompleteDT.js +3 -69
  7. package/lib/components/XCalendar.d.ts +1 -2
  8. package/lib/components/XCalendar.js +79 -10
  9. package/lib/components/XFormBase.js +5 -1
  10. package/lib/components/XFormComponent.js +9 -6
  11. package/lib/components/XFormDataTable2.d.ts +15 -1
  12. package/lib/components/XFormDataTable2.js +24 -4
  13. package/lib/components/XFormRowCol/XFormCol.d.ts +1 -0
  14. package/lib/components/XFormRowCol/XFormCol.js +1 -1
  15. package/lib/components/XFormRowCol/XFormInlineRow.d.ts +1 -0
  16. package/lib/components/XFormRowCol/XFormInlineRow.js +1 -1
  17. package/lib/components/XFormRowCol/XFormRow.d.ts +1 -0
  18. package/lib/components/XFormRowCol/XFormRow.js +1 -1
  19. package/lib/components/XFormRowCol/XFormRowCol.d.ts +1 -0
  20. package/lib/components/XFormRowCol/XFormRowCol.js +1 -1
  21. package/lib/components/XInputDate.d.ts +0 -1
  22. package/lib/components/XInputDate.js +4 -18
  23. package/lib/components/XInputDateDT.d.ts +9 -10
  24. package/lib/components/XInputDateDT.js +35 -39
  25. package/lib/components/XInputDecimal.js +1 -1
  26. package/lib/components/XInputTextarea.js +1 -1
  27. package/lib/components/XInputTextareaDT.d.ts +12 -0
  28. package/lib/components/XInputTextareaDT.js +44 -0
  29. package/lib/components/XLazyDataTable.d.ts +4 -2
  30. package/lib/components/XLazyDataTable.js +17 -4
  31. package/lib/components/XSearchBrowseParams.d.ts +2 -2
  32. package/lib/components/XSearchButton.js +2 -2
  33. package/lib/components/XSearchButtonDT.js +2 -2
  34. package/lib/components/XUtils.d.ts +4 -0
  35. package/lib/components/XUtils.js +51 -11
  36. package/lib/components/XUtilsMetadata.js +1 -1
  37. package/lib/serverApi/FindParam.d.ts +12 -2
  38. package/lib/serverApi/FindParam.js +3 -2
  39. package/lib/serverApi/XUtilsCommon.d.ts +5 -0
  40. package/lib/serverApi/XUtilsCommon.js +43 -0
  41. package/lib/serverApi/XUtilsConversions.d.ts +1 -0
  42. package/lib/serverApi/XUtilsConversions.js +63 -5
  43. package/package.json +1 -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,226 @@ 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.computeDisplayValue = _this.computeDisplayValue.bind(_this);
102
154
  _this.formDialogOnSaveOrCancel = _this.formDialogOnSaveOrCancel.bind(_this);
103
155
  _this.formDialogOnHide = _this.formDialogOnHide.bind(_this);
104
156
  _this.searchDialogOnChoose = _this.searchDialogOnChoose.bind(_this);
105
157
  _this.searchDialogOnHide = _this.searchDialogOnHide.bind(_this);
106
158
  return _this;
107
159
  }
160
+ XAutoCompleteBase.prototype.getXSuggestionsLoadType = function () {
161
+ var suggestionsLoadType;
162
+ if (this.props.suggestions) {
163
+ suggestionsLoadType = "suggestions";
164
+ }
165
+ else if (!this.props.suggestionsLoad) {
166
+ suggestionsLoadType = "onSearchStart"; // default
167
+ }
168
+ else {
169
+ suggestionsLoadType = this.props.suggestionsLoad;
170
+ }
171
+ return suggestionsLoadType;
172
+ };
173
+ // helper
174
+ XAutoCompleteBase.prototype.getFields = function () {
175
+ return Array.isArray(this.props.field) ? this.props.field : [this.props.field];
176
+ };
177
+ XAutoCompleteBase.prototype.getFirstField = function () {
178
+ return this.getFields()[0];
179
+ };
108
180
  XAutoCompleteBase.prototype.componentDidMount = function () {
181
+ if (this.getXSuggestionsLoadType() === "eager") {
182
+ this.loadSuggestions();
183
+ }
109
184
  if (this.props.setFocusOnCreate) {
110
185
  this.setFocusToInput();
111
186
  }
112
187
  };
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;
188
+ XAutoCompleteBase.prototype.loadSuggestions = function () {
189
+ return __awaiter(this, void 0, void 0, function () {
190
+ var suggestions;
191
+ return __generator(this, function (_a) {
192
+ switch (_a.label) {
193
+ case 0: return [4 /*yield*/, this.fetchSuggestions()];
194
+ case 1:
195
+ suggestions = _a.sent();
196
+ this.setState({ suggestions: suggestions });
197
+ return [2 /*return*/];
126
198
  }
127
- // bolo:
128
- //return XUtils.normalizeString(fieldValue).startsWith(queryNormalized);
129
- return XUtils_1.XUtils.normalizeString(fieldValue).indexOf(queryNormalized_1) !== -1;
130
199
  });
131
- }
132
- this.setState({ filteredSuggestions: filteredSuggestions });
200
+ });
133
201
  };
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
- }
202
+ XAutoCompleteBase.prototype.fetchSuggestions = function () {
203
+ return __awaiter(this, void 0, void 0, function () {
204
+ return __generator(this, function (_a) {
205
+ if (!this.props.suggestionsQuery) {
206
+ throw "XAutoCompleteBase.loadSuggestions: unexpected error - prop suggestionsQuery is undefined";
143
207
  }
208
+ 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)];
209
+ });
210
+ });
211
+ };
212
+ XAutoCompleteBase.prototype.getSortField = function () {
213
+ var sortField = this.props.suggestionsQuery.sortField;
214
+ if (!sortField) {
215
+ // len pri ne-lazy pouzivame ako default sort prvy displayField
216
+ // pri lazy to spomaluje selecty v pripade ze klauzula LIMIT vyrazne obmedzi vysledny zoznam suggestions
217
+ // pri lazy zosortujeme na frontende v XAutoCompleteBase
218
+ if (this.getXSuggestionsLoadType() !== "lazy") {
219
+ sortField = this.getFirstField();
144
220
  }
221
+ }
222
+ return sortField;
223
+ };
224
+ XAutoCompleteBase.prototype.completeMethod = function (event) {
225
+ return __awaiter(this, void 0, void 0, function () {
226
+ var filteredSuggestions, xSuggestionsLoadType, suggestions, queryNormalized, queryNormalizedList_1, filter, suggestionsRequest, findResult;
227
+ var _this = this;
228
+ return __generator(this, function (_a) {
229
+ switch (_a.label) {
230
+ case 0:
231
+ xSuggestionsLoadType = this.getXSuggestionsLoadType();
232
+ if (!(xSuggestionsLoadType !== "lazy")) return [3 /*break*/, 8];
233
+ suggestions = void 0;
234
+ if (!(xSuggestionsLoadType === "suggestions")) return [3 /*break*/, 1];
235
+ suggestions = this.props.suggestions;
236
+ return [3 /*break*/, 7];
237
+ case 1:
238
+ if (!(xSuggestionsLoadType === "eager")) return [3 /*break*/, 2];
239
+ suggestions = this.state.suggestions;
240
+ return [3 /*break*/, 7];
241
+ case 2:
242
+ if (!(xSuggestionsLoadType === "onSearchStart")) return [3 /*break*/, 6];
243
+ if (!!this.suggestionsLoadedForOSS) return [3 /*break*/, 4];
244
+ return [4 /*yield*/, this.fetchSuggestions()];
245
+ case 3:
246
+ suggestions = _a.sent();
247
+ // ulozime si
248
+ this.setState({ suggestions: suggestions });
249
+ this.suggestionsLoadedForOSS = true; // ak user dalej typuje, nechceme znova nacitavat suggestions
250
+ return [3 /*break*/, 5];
251
+ case 4:
252
+ // uz mame nacitane
253
+ suggestions = this.state.suggestions;
254
+ _a.label = 5;
255
+ case 5: return [3 /*break*/, 7];
256
+ case 6: throw 'Unexpected error - unknown xSuggestionsLoadType';
257
+ case 7:
258
+ if (!event.query.trim().length) {
259
+ // input je prazdny - volanie sem nastane ak user otvori dropdown cez dropdown button
260
+ filteredSuggestions = __spreadArray([], __read(suggestions), false);
261
+ }
262
+ else {
263
+ queryNormalized = XUtils_1.XUtils.normalizeString(event.query);
264
+ if (this.props.splitQueryValue) {
265
+ queryNormalizedList_1 = queryNormalized.split(' ').filter(function (value) { return value !== ''; }); // nechceme pripadne prazdne retazce ''
266
+ }
267
+ else {
268
+ queryNormalizedList_1 = [queryNormalized]; // nesplitujeme
269
+ }
270
+ filteredSuggestions = suggestions.filter(function (suggestion) {
271
+ var e_1, _a;
272
+ var fieldValue = _this.computeDisplayValue(suggestion);
273
+ // specialna null polozka (prazdny objekt) - test dame az za test fieldValue na undefined - koli performance
274
+ if (fieldValue === undefined && Object.keys(suggestion).length === 0) {
275
+ return false;
276
+ }
277
+ var fieldValueNormalized = XUtils_1.XUtils.normalizeString(fieldValue);
278
+ // all partial query values must match
279
+ var match = true;
280
+ try {
281
+ for (var queryNormalizedList_2 = __values(queryNormalizedList_1), queryNormalizedList_2_1 = queryNormalizedList_2.next(); !queryNormalizedList_2_1.done; queryNormalizedList_2_1 = queryNormalizedList_2.next()) {
282
+ var queryItemNormalized = queryNormalizedList_2_1.value;
283
+ // look for substring
284
+ if (fieldValueNormalized.indexOf(queryItemNormalized) === -1) {
285
+ match = false;
286
+ break;
287
+ }
288
+ }
289
+ }
290
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
291
+ finally {
292
+ try {
293
+ if (queryNormalizedList_2_1 && !queryNormalizedList_2_1.done && (_a = queryNormalizedList_2.return)) _a.call(queryNormalizedList_2);
294
+ }
295
+ finally { if (e_1) throw e_1.error; }
296
+ }
297
+ return match;
298
+ });
299
+ }
300
+ return [3 /*break*/, 10];
301
+ case 8:
302
+ // ************* lazy ***************
303
+ // na backendev SELECT-e pouzijeme klauzulu LIMIT <maxRows + 1>
304
+ // ak najdeme menej ako <maxRows + 1> zaznamov tak vieme ze sme nasli vsetky
305
+ // ak najdeme presne <maxRows + 1> zaznamov, tak na konci zobrazime uzivatelovi specialnu polozku "..."
306
+ // ktora ho upozorni ze existuju aj dalsie zaznamy splnujuce podmienku
307
+ // pikoska - ak je query je velmi siroke (select by bez LIMIT <maxRows + 1> vratil mnoho zaznamov),
308
+ // tak je takyto select velmi lacny (niekolko ms) - staci totiz najst prvych napr. 20 zaznamov splnujucich podmienku, t.j. netreba robit full-table scan
309
+ // to ale plati len v pripade ze nepouzijeme ORDER BY - pri pouziti ORDER BY urobi full-table scan (vyfiltruje) a nasledne zosortuje
310
+ // toto sa da obist specialnym selectom:
311
+ // select t.* from (select t0.* from table t0 order by t0.<attr1>) t where <full-text-condition> limit 20
312
+ // (najprv zosortuje a az potom filtruje prvych 20 zaznamov - predpoklad je ze nad t0.<attr1> mame index aby rychlo sortoval)
313
+ // tento specialny select mozme v buducnosti dorobit (na backende) ak chceme podporovat (rychle) sortovanie v DB pre autocomplete
314
+ if (!this.props.suggestionsQuery) {
315
+ throw "XAutoCompleteBase.loadSuggestions: unexpected error - prop suggestionsQuery is undefined";
316
+ }
317
+ filter = XUtils_1.XUtils.evalFilter(this.props.suggestionsQuery.filter);
318
+ suggestionsRequest = {
319
+ maxRows: this.props.lazyLoadMaxRows + 1,
320
+ fullTextSearch: { fields: this.getFields(), value: event.query.trim(), splitValue: this.props.splitQueryValue, matchMode: "contains" },
321
+ entity: this.props.suggestionsQuery.entity,
322
+ filterItems: XUtils_1.XUtils.createCustomFilterItems(filter),
323
+ multiSortMeta: XUtils_1.XUtils.createMultiSortMeta(this.getSortField()),
324
+ fields: this.props.suggestionsQuery.fields
325
+ };
326
+ return [4 /*yield*/, XUtils_1.XUtils.fetchOne('x-lazy-auto-complete-suggestions', suggestionsRequest)];
327
+ case 9:
328
+ findResult = _a.sent();
329
+ filteredSuggestions = findResult.rowList;
330
+ // ak sme nesortovali v DB (co je draha operacia) tak zosortujeme teraz
331
+ // (computeDisplayValue sa vola duplicitne ale pre tych cca 20 zaznamov je to ok)
332
+ if (this.props.suggestionsQuery.sortField === undefined) {
333
+ filteredSuggestions = XUtils_1.XUtils.arraySort(filteredSuggestions, this.computeDisplayValue);
334
+ }
335
+ // ak mame o 1 zaznam viac ako je lazyLoadMaxRows, zmenime posledny zaznam na ...
336
+ if (filteredSuggestions.length > this.props.lazyLoadMaxRows) {
337
+ filteredSuggestions[filteredSuggestions.length - 1] = XAutoCompleteBase.valueMoreSuggestions; // zatial priamo string
338
+ }
339
+ _a.label = 10;
340
+ case 10:
341
+ this.setState({ filteredSuggestions: filteredSuggestions });
342
+ return [2 /*return*/];
343
+ }
344
+ });
345
+ });
346
+ };
347
+ XAutoCompleteBase.prototype.onChange = function (e) {
348
+ if (typeof e.value === 'string' && !XAutoCompleteBase.isMoreSuggestions(e.value)) {
145
349
  this.setState({ inputChanged: true, inputValueState: e.value });
350
+ this.wasOnChangeCalled = false; // reset na default hodnotu
146
351
  }
147
352
  };
148
353
  XAutoCompleteBase.prototype.onSelect = function (e) {
149
- this.setObjectValue(e.value, XUtils_1.OperationType.None);
354
+ // nevolame this.setObjectValue ak uz bol zavolany z onBlur
355
+ if (!this.wasOnChangeCalled) {
356
+ // nedovolime vybrat specialny zaznam ...
357
+ if (!XAutoCompleteBase.isMoreSuggestions(e.value)) {
358
+ this.setObjectValue(e.value, XUtils_1.OperationType.None);
359
+ }
360
+ }
150
361
  };
151
362
  XAutoCompleteBase.prototype.onBlur = function (e) {
152
363
  // optimalizacia - testujeme len ak inputChanged === true
@@ -159,6 +370,11 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
159
370
  var filteredSuggestions = this.state.filteredSuggestions;
160
371
  if (filteredSuggestions && filteredSuggestions.length === 1) {
161
372
  this.setObjectValue(filteredSuggestions[0], XUtils_1.OperationType.None);
373
+ // ak bol tento this.setObjectValue vyvolany klikom do suggestions dropdown-u,
374
+ // tak bude este nasledne zavolany onSelect a tam chceme zamedzit volaniu this.setObjectValue,
375
+ // preto nastavujeme tento priznak
376
+ // priznak vratime naspet na false ak uzivatel zacne cokolvek robit s autocomplete (zacne don typovat alebo klikne na dropdown)
377
+ this.wasOnChangeCalled = true;
162
378
  }
163
379
  else {
164
380
  // tu by sme mohli skusit vyratat vysledok pre filteredSuggestions este raz, mozno este vypocet filteredSuggestions nedobehol
@@ -190,8 +406,9 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
190
406
  }
191
407
  }
192
408
  }
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;
409
+ // odchadzame z inputu, zresetujeme priznak - ak zacne user pracovat s autocomplete-om, nacitaju sa suggestions z DB (ak mame suggestionsLoad = onSearchStart)
410
+ // suggestions chceme nacitat, lebo user moze zmenit iny atribut ktory ovplyvnuje filter autocomplete-u -> chceme novy zoznam suggestions
411
+ this.suggestionsLoadedForOSS = false;
195
412
  };
196
413
  XAutoCompleteBase.prototype.createErrorMessage = function () {
197
414
  return "Value \"".concat(this.state.inputValueState, "\" was not found among valid values.");
@@ -231,6 +448,14 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
231
448
  if (object !== null) {
232
449
  // ak bol save, treba tento novy object pouzit
233
450
  this.setObjectValue(object, objectChange);
451
+ // ak pouzivame zoznam this.state.suggestions, tak ho rereadneme
452
+ // poznamka: ak pouzivame this.props.suggestions z parenta, tak si musi zoznam rereadnut parent!
453
+ if (objectChange !== XUtils_1.OperationType.None) {
454
+ // zmenil sa zaznam dobrovolnika v DB
455
+ // zatial len refreshneme z DB
456
+ // ak by bol reqest pomaly, mozme pri inserte (nove id) / update (existujuce id) upravit zoznam a usetrime tym request do DB
457
+ this.loadSuggestions();
458
+ }
234
459
  // treba upravit this.state.filteredSuggestions? setli sme novy objekt, panel so suggestions by mal byt zavrety - TODO - overit
235
460
  }
236
461
  else {
@@ -270,7 +495,7 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
270
495
  _this.formDialogInitValuesForInsert = {};
271
496
  // ak mame nevalidnu hodnotu, tak ju predplnime (snaha o user friendly)
272
497
  if (_this.state.inputChanged) {
273
- _this.formDialogInitValuesForInsert[_this.props.field] = _this.state.inputValueState;
498
+ _this.formDialogInitValuesForInsert[_this.getFirstField()] = _this.state.inputValueState;
274
499
  }
275
500
  _this.setState({ formDialogOpened: true });
276
501
  }
@@ -287,13 +512,7 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
287
512
  alert('Please select some row.');
288
513
  }
289
514
  else {
290
- // otvorime dialog na update
291
- if (_this.props.idField === undefined) {
292
- throw "XAutoCompleteBase: property valueForm is defined but property idField is also needed for form editation.";
293
- }
294
- _this.formDialogObjectId = _this.props.value[_this.props.idField];
295
- _this.formDialogInitValuesForInsert = undefined;
296
- _this.setState({ formDialogOpened: true });
515
+ _this.onEditAssocValue();
297
516
  }
298
517
  }
299
518
  }
@@ -335,39 +554,87 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
335
554
  });
336
555
  };
337
556
  XAutoCompleteBase.prototype.onOpenDropdown = function (e) {
338
- var _this = this;
339
- if (this.props.onSearchStart) {
340
- this.props.onSearchStart(function () { return _this.openDropdown(e); });
341
- }
342
- else {
343
- // otvori dropdown (search je metoda popisana v API, volanie sme skopcili zo zdrojakov primereact)
344
- //this.autoCompleteRef.current.search(e, '', 'dropdown');
345
- this.openDropdown(e);
346
- }
557
+ this.openDropdown(e);
558
+ this.suggestionsLoadedForOSS = false; // user mohol vyplnit nieco co meni filter a ide znova pracovat s autocomplete, nacitame suggestions znova (suggestionsLoad = onSearchStart)
559
+ this.wasOnChangeCalled = false; // reset na default hodnotu
347
560
  };
348
561
  XAutoCompleteBase.prototype.openDropdown = function (e) {
349
562
  // otvori dropdown (search je metoda popisana v API, volanie sme skopcili zo zdrojakov primereact)
350
563
  this.autoCompleteRef.current.search(e, '', 'dropdown');
351
564
  };
565
+ XAutoCompleteBase.prototype.onEditAssocValue = function () {
566
+ // otvorime dialog na update
567
+ if (this.props.idField === undefined) {
568
+ throw "XAutoCompleteBase: property valueForm is defined but property idField is also needed for form editation.";
569
+ }
570
+ this.formDialogObjectId = this.props.value[this.props.idField];
571
+ this.formDialogInitValuesForInsert = undefined;
572
+ this.setState({ formDialogOpened: true });
573
+ };
352
574
  // vracia objekt (ak inputChanged === false) alebo string (ak inputChanged === true)
353
575
  XAutoCompleteBase.prototype.computeInputValue = function () {
354
576
  var inputValue;
355
577
  if (!this.state.inputChanged) {
356
578
  // poznamka: ak object === null tak treba do inputu zapisovat prazdny retazec, ak by sme pouzili null, neprejavila by sa zmena v modeli na null
357
579
  var object = this.props.value;
358
- inputValue = (object !== null) ? object : ""; // TODO - je "" ok?
580
+ inputValue = (object !== null) ? this.computeDisplayValue(object) : ""; // TODO - je "" ok?
359
581
  }
360
582
  else {
361
583
  inputValue = this.state.inputValueState;
362
584
  }
363
585
  return inputValue;
364
586
  };
587
+ XAutoCompleteBase.prototype.itemTemplate = function (suggestion, index) {
588
+ return this.computeDisplayValue(suggestion);
589
+ };
590
+ XAutoCompleteBase.prototype.computeDisplayValue = function (suggestion) {
591
+ var e_2, _a;
592
+ var displayValue = "";
593
+ if (XAutoCompleteBase.isMoreSuggestions(suggestion)) {
594
+ displayValue = suggestion;
595
+ }
596
+ else {
597
+ try {
598
+ for (var _b = __values(this.getFields()), _c = _b.next(); !_c.done; _c = _b.next()) {
599
+ var field = _c.value;
600
+ // TODO - konverzie na spravny typ/string
601
+ var _d = __read(XUtilsCommon_1.XUtilsCommon.getPrefixAndField(field), 2), prefix = _d[0], fieldOnly = _d[1];
602
+ var value = XUtilsCommon_1.XUtilsCommon.getValueByPath(suggestion, fieldOnly);
603
+ if (value !== null && value !== undefined) {
604
+ var valueStr = value.toString(); // TODO - spravnu konverziu
605
+ if (valueStr !== "") {
606
+ if (displayValue !== "") {
607
+ displayValue += " ";
608
+ }
609
+ if (prefix) {
610
+ displayValue += prefix;
611
+ }
612
+ displayValue += valueStr;
613
+ }
614
+ }
615
+ }
616
+ }
617
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
618
+ finally {
619
+ try {
620
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
621
+ }
622
+ finally { if (e_2) throw e_2.error; }
623
+ }
624
+ }
625
+ return displayValue;
626
+ };
627
+ // vrati true ak sa jedna o specialny typ XAutoCompleteBase.valueMoreSuggestions
628
+ XAutoCompleteBase.isMoreSuggestions = function (suggestion) {
629
+ return typeof suggestion === "string" && suggestion === XAutoCompleteBase.valueMoreSuggestions;
630
+ };
365
631
  // takto cez metodku, mozno sa metodka vola len ked sa otvori dialog a usetrime nieco...
366
632
  XAutoCompleteBase.prototype.createSearchBrowseParams = function () {
633
+ var _a;
367
634
  return {
368
635
  onChoose: this.searchDialogOnChoose,
369
- displayFieldFilter: (this.state.inputChanged ? { field: this.props.field, constraint: { value: this.state.inputValueState, matchMode: "startsWith" } } : undefined),
370
- customFilterFunction: this.props.customFilterFunction
636
+ displayFieldFilter: (this.state.inputChanged ? { field: this.getFirstField(), constraint: { value: this.state.inputValueState, matchMode: "contains" } } : undefined),
637
+ customFilter: (_a = this.props.suggestionsQuery) === null || _a === void 0 ? void 0 : _a.filter
371
638
  };
372
639
  };
373
640
  XAutoCompleteBase.prototype.render = function () {
@@ -375,21 +642,34 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
375
642
  var _a;
376
643
  var readOnly = (_a = this.props.readOnly) !== null && _a !== void 0 ? _a : false;
377
644
  var dropdownButton;
378
- if ((this.props.searchBrowse && !readOnly) || this.props.valueForm) {
379
- // mame searchBrowse alebo CRUD operacie, potrebujeme SplitButton
380
- var splitButtonItems = [];
381
- if (this.props.valueForm) {
382
- this.createInsertUpdateItems(splitButtonItems);
645
+ if (!readOnly) {
646
+ if (this.props.searchBrowse || this.props.valueForm) {
647
+ // mame searchBrowse alebo CRUD operacie, potrebujeme SplitButton
648
+ var splitButtonItems = [];
649
+ if (this.props.valueForm) {
650
+ this.createInsertUpdateItems(splitButtonItems);
651
+ }
652
+ if (this.props.searchBrowse && !readOnly) {
653
+ this.createSearchItem(splitButtonItems);
654
+ }
655
+ this.createDropdownItem(splitButtonItems);
656
+ dropdownButton = react_1.default.createElement(splitbutton_1.SplitButton, { model: splitButtonItems, className: 'x-splitbutton-only-dropdown' + XUtils_1.XUtils.mobileCssSuffix(), menuClassName: 'x-splitbutton-only-dropdown-menu' + XUtils_1.XUtils.mobileCssSuffix(), disabled: readOnly });
383
657
  }
384
- if (this.props.searchBrowse && !readOnly) {
385
- this.createSearchItem(splitButtonItems);
658
+ else {
659
+ // mame len 1 operaciu - dame jednoduchy button
660
+ dropdownButton = react_1.default.createElement(button_1.Button, { icon: "pi pi-chevron-down", onClick: function (e) { return _this.onOpenDropdown(e); }, className: 'x-dropdownbutton' + XUtils_1.XUtils.mobileCssSuffix() });
386
661
  }
387
- this.createDropdownItem(splitButtonItems);
388
- dropdownButton = react_1.default.createElement(splitbutton_1.SplitButton, { model: splitButtonItems, className: 'x-splitbutton-only-dropdown' + XUtils_1.XUtils.mobileCssSuffix(), menuClassName: 'x-splitbutton-only-dropdown-menu' + XUtils_1.XUtils.mobileCssSuffix(), disabled: readOnly });
389
662
  }
390
663
  else {
391
- // mame len 1 operaciu - dame jednoduchy button
392
- dropdownButton = react_1.default.createElement(button_1.Button, { icon: "pi pi-chevron-down", onClick: function (e) { return _this.onOpenDropdown(e); }, className: 'x-dropdownbutton' + XUtils_1.XUtils.mobileCssSuffix(), disabled: readOnly });
664
+ // readOnly
665
+ // ak mame valueForm a mame asociovany objekt, umoznime editovat asociovany objekt
666
+ if (this.props.valueForm && this.props.value !== null) {
667
+ dropdownButton = react_1.default.createElement(button_1.Button, { icon: "pi pi-pencil", onClick: function (e) { return _this.onEditAssocValue(); }, className: 'x-dropdownbutton' + XUtils_1.XUtils.mobileCssSuffix() });
668
+ }
669
+ else {
670
+ // dame disablovany button (z estetickych dovodov, zachovame sirku)
671
+ dropdownButton = react_1.default.createElement(button_1.Button, { icon: "pi pi-chevron-down", className: 'x-dropdownbutton' + XUtils_1.XUtils.mobileCssSuffix(), disabled: true });
672
+ }
393
673
  }
394
674
  // vypocitame inputValue
395
675
  var inputValue = this.computeInputValue();
@@ -405,9 +685,9 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
405
685
  // <DobrovolnikForm id={this.formDialogObjectId} object={this.formDialogInitValuesForInsert} onSaveOrCancel={this.formDialogOnSaveOrCancel}/>
406
686
  // formgroup-inline lepi SplitButton na autocomplete a zarovna jeho vysku
407
687
  return (react_1.default.createElement("div", { className: "x-auto-complete-base", style: { width: this.props.width } },
408
- 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))),
688
+ 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))),
409
689
  dropdownButton,
410
- this.props.valueForm != undefined && !readOnly ?
690
+ this.props.valueForm != undefined ?
411
691
  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, {
412
692
  id: this.formDialogObjectId, initValues: this.formDialogInitValuesForInsert, onSaveOrCancel: this.formDialogOnSaveOrCancel
413
693
  } /*, this.props.valueForm.children*/))
@@ -416,6 +696,13 @@ var XAutoCompleteBase = /** @class */ (function (_super) {
416
696
  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*/))
417
697
  : undefined));
418
698
  };
699
+ XAutoCompleteBase.valueMoreSuggestions = "...";
700
+ XAutoCompleteBase.defaultProps = {
701
+ lazyLoadMaxRows: 10,
702
+ splitQueryValue: true,
703
+ minLength: 1,
704
+ scrollHeight: '15rem' // primereact has 200px
705
+ };
419
706
  return XAutoCompleteBase;
420
707
  }(react_1.Component));
421
708
  exports.XAutoCompleteBase = XAutoCompleteBase;
@@ -3,24 +3,28 @@ 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
11
  displayField: string;
10
12
  searchBrowse?: JSX.Element;
11
13
  assocForm?: JSX.Element;
12
- filter?: XTableFieldFilterProp;
13
14
  suggestions?: any[];
15
+ suggestionsLoad?: XSuggestionsLoadProp;
16
+ lazyLoadMaxRows?: number;
17
+ splitQueryValue?: boolean;
18
+ minLength?: number;
19
+ filter?: XTableFieldFilterProp;
20
+ sortField?: string | DataTableSortMeta[];
21
+ fields?: string[];
22
+ scrollHeight?: string;
14
23
  }
15
24
  export declare class XAutoCompleteDT extends XFormComponentDT<XAutoCompleteDTProps> {
16
25
  protected xAssoc: XAssoc;
17
26
  protected errorInBase: string | undefined;
18
- state: {
19
- suggestions: any[];
20
- };
21
27
  constructor(props: XAutoCompleteDTProps);
22
- componentDidMount(): void;
23
- readAndSetSuggestions(): Promise<void>;
24
28
  getField(): string;
25
29
  isNotNull(): boolean;
26
30
  getValue(): any | null;