arrmatura 5.0.4 → 5.2.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 (81) hide show
  1. package/commons/auth/AuthService.ts +111 -0
  2. package/commons/auth/UserService.ts +28 -78
  3. package/commons/auth/index.ts +4 -3
  4. package/commons/auth/user.xml +18 -20
  5. package/commons/components/buttons.xml +6 -4
  6. package/commons/components/layouts.xml +8 -8
  7. package/commons/components/modal.xml +4 -4
  8. package/commons/components/navigation.xml +21 -7
  9. package/commons/components/searchbar.xml +36 -22
  10. package/commons/components/table.xml +25 -5
  11. package/commons/components/toasts.xml +10 -5
  12. package/commons/forms/FormController.ts +48 -34
  13. package/commons/forms/Item.ts +93 -29
  14. package/commons/forms/ItemCollectionController.ts +113 -0
  15. package/commons/forms/ItemController.ts +50 -21
  16. package/commons/forms/NewItemController.ts +46 -0
  17. package/commons/forms/SmartareaField.xml +3 -3
  18. package/commons/forms/SuggestionField.xml +3 -3
  19. package/commons/forms/fields.xml +28 -15
  20. package/commons/forms/form.xml +3 -3
  21. package/commons/forms/index.ts +4 -4
  22. package/commons/index.ts +2 -2
  23. package/commons/services/ApiClientService.ts +32 -0
  24. package/commons/services/GSheetsService.ts +92 -64
  25. package/commons/services/Invoke.ts +24 -8
  26. package/commons/services/JsonpService.ts +1 -1
  27. package/commons/services/MetadataService.ts +50 -0
  28. package/commons/services/NavigationService.ts +20 -1
  29. package/commons/services/Service.ts +22 -28
  30. package/commons/services/Storage.ts +55 -0
  31. package/commons/services/ToastService.ts +16 -4
  32. package/commons/services/index.ts +3 -4
  33. package/core/Arrmatura.ts +4 -9
  34. package/core/CNode.ts +1 -2
  35. package/core/Component.ts +29 -31
  36. package/core/cnodes/conditionals.ts +3 -2
  37. package/core/expression.ts +1 -1
  38. package/core/register.ts +1 -1
  39. package/core/utils.ts +1 -3
  40. package/core-web/attributes.ts +38 -10
  41. package/core-web/elements.ts +22 -4
  42. package/core-web/index.ts +14 -2
  43. package/core-web/reflow.ts +3 -1
  44. package/core-web/support.ts +27 -0
  45. package/docs/index.js +350 -66
  46. package/lib/{arrayGroupBy.ts → array/arrayGroupBy.ts} +1 -1
  47. package/lib/{arraySortBy.ts → array/arraySortBy.ts} +5 -5
  48. package/lib/{arrayToObject.ts → array/arrayToObject.ts} +0 -0
  49. package/lib/array/arrayish.ts +7 -0
  50. package/lib/array/index.ts +4 -0
  51. package/lib/crypto/index.ts +25 -0
  52. package/lib/{dateFormat.ts → date/index.ts} +61 -3
  53. package/lib/func/curry.ts +11 -0
  54. package/lib/{fx.ts → func/fx.ts} +32 -38
  55. package/lib/{noop.ts → func/identity.ts} +1 -3
  56. package/lib/{nextId.ts → func/nextId.ts} +0 -0
  57. package/lib/func/noop.ts +6 -0
  58. package/lib/geo/index.js +22 -0
  59. package/lib/index.ts +17 -19
  60. package/lib/{obj.ts → object/index.ts} +8 -3
  61. package/lib/{codus.ts → parsing/codus.ts} +1 -1
  62. package/lib/{predicat.ts → parsing/compiler.ts} +0 -0
  63. package/lib/{scalar.ts → parsing/scalarParse.ts} +0 -0
  64. package/lib/{urls.ts → parsing/urls.ts} +0 -0
  65. package/lib/{xml.ts → parsing/xml.ts} +3 -3
  66. package/lib/{l10n.ts → resources/l10n.ts} +2 -2
  67. package/lib/{resources.ru.ts → resources/resources.ru.ts} +0 -0
  68. package/lib/{resources.ts → resources/resources.ts} +0 -0
  69. package/lib/{str.ts → string/index.ts} +2 -20
  70. package/lib/{createListeners.ts → support/createListeners.ts} +0 -0
  71. package/package.json +7 -6
  72. package/commons/forms/ItemCollection.ts +0 -152
  73. package/commons/forms/MetadataService.ts +0 -45
  74. package/commons/pipes/index.ts +0 -21
  75. package/commons/pipes/showCounts.ts +0 -16
  76. package/commons/services/LocalStorage.ts +0 -46
  77. package/lib/consts.ts +0 -3
  78. package/lib/curry.ts +0 -8
  79. package/lib/dateOf.ts +0 -31
  80. package/lib/dateParseISO8601.ts +0 -27
  81. package/lib/guid.ts +0 -7
@@ -1,13 +1,21 @@
1
- import { arrayGroupBy } from 'arrayGroupBy';
2
- import { getPredicat } from 'predicat';
3
- import { strFormat } from '../../lib';
1
+ import { arrayGroupBy } from '../../lib';
2
+ import { strFormat, getPredicat } from '../../lib';
4
3
  import { Service } from '../services/Service';
5
4
 
5
+ const getFieldsGroups = (fieldProps: Hash[], names?: StringHash): Obj[] => {
6
+ return Object.values(arrayGroupBy(fieldProps, 'group')).map((e) => ({
7
+ name: names?.[e.id] || e.id,
8
+ ...e,
9
+ }));
10
+ };
11
+
6
12
  export class FormController extends Service {
7
13
  data: { [k: string]: unknown } = {};
8
14
  meta: any;
9
15
  error: any;
10
16
  change: any;
17
+ tabs?: StringHash;
18
+ groups?: StringHash;
11
19
 
12
20
  setData(d: Data) {
13
21
  const data = { ...d };
@@ -15,14 +23,14 @@ export class FormController extends Service {
15
23
  }
16
24
 
17
25
  get fieldsGroups(): Obj[] {
18
- return Object.values(arrayGroupBy(this.fieldProps, 'group'));
26
+ return getFieldsGroups(this.fieldProps, this.groups);
19
27
  }
20
28
 
21
29
  get tabsInfo() {
22
30
  const tabs = Object.values(arrayGroupBy(this.fieldProps, ({ tab = 'tab' }) => tab)).map(({ id, items }) => ({
23
31
  id,
24
- name: id,
25
- items: Object.values(arrayGroupBy(items, 'group')),
32
+ name: this.tabs?.[id] || id,
33
+ items: getFieldsGroups(items, this.groups),
26
34
  }));
27
35
  return { enabled: tabs.length > 1, initialTab: tabs?.[0]?.id, tabs };
28
36
  }
@@ -35,39 +43,45 @@ export class FormController extends Service {
35
43
  .map((s) => s.trim().split('='))
36
44
  .map(([id, name = id]) => ({ id, name }));
37
45
  }
46
+
47
+ if (!typeSpec.includes('.')) return this.res('enums.' + typeSpec) || [];
48
+
38
49
  const [key, subid, subKey] = strFormat(typeSpec, data).split('.');
50
+ const enumItems = this.res('enums.' + key) || [];
39
51
  if (subKey) {
40
- return (this.res('enums.' + key) || []).find(({ id }) => id === subid)?.[subKey] || [];
52
+ return enumItems.find(({ id }) => id === subid)?.[subKey] || [];
41
53
  }
42
- return this.res('enums.' + key) || [];
54
+ return enumItems;
43
55
  }
44
56
 
45
57
  get fieldProps() {
46
- return this.meta?.map((field: { [k: string]: string }) => {
47
- const { id, visible, disabled = false, caption, name, type, typeSpec } = field;
48
- const form = this;
49
- const data = this.data;
50
- const value = data[id];
51
- return {
52
- ...field,
53
- error: (form.error && form.error.fields && form.error.fields[id]) || null,
54
- get disabled(): boolean {
55
- return getPredicat(disabled)(data);
56
- },
57
- get visible(): boolean {
58
- return getPredicat(visible || 'true')(data);
59
- },
60
- get options(): Data[] | Data | null {
61
- return form.resolveEnum(typeSpec, data);
62
- },
63
- value: value === undefined ? null : value,
64
- caption: caption || name,
65
- data,
66
- onChange: ({ value, key }: { value: unknown; key?: string }) => {
67
- this.data = { ...this.data, [key || id]: value };
68
- this.change?.(this.data);
69
- },
70
- };
71
- });
58
+ return (
59
+ this.meta?.map?.((field: { [k: string]: string }) => {
60
+ const { id, visible, disabled = false, caption, name, typeSpec } = field;
61
+ const form = this;
62
+ const data = this.data;
63
+ const value = data[id];
64
+ return {
65
+ ...field,
66
+ error: (form.error && form.error.fields && form.error.fields[id]) || null,
67
+ get disabled(): boolean {
68
+ return getPredicat(disabled)(data);
69
+ },
70
+ get visible(): boolean {
71
+ return getPredicat(visible || 'true')(data);
72
+ },
73
+ get options(): Data[] | Data | null {
74
+ return form.resolveEnum(typeSpec, data);
75
+ },
76
+ value: value === undefined ? null : value,
77
+ caption: caption || name,
78
+ data,
79
+ onChange: ({ value, key }: { value: unknown; key?: string }) => {
80
+ this.data = { ...this.data, [key || id]: value };
81
+ this.change?.(this.data);
82
+ },
83
+ };
84
+ }) || []
85
+ );
72
86
  }
73
87
  }
@@ -1,68 +1,132 @@
1
- import { arraySortBy } from 'arraySortBy';
1
+ import { arraySortBy } from '../../lib';
2
2
 
3
- export const analyzeDataByTags = (data: Item[], selection: Hash<boolean>, initials = '') => {
3
+ export const analyzeDataByTags = (
4
+ data: Item[],
5
+ selection: Hash<boolean>,
6
+ initials = '',
7
+ tags: Tag[] = [],
8
+ labelsFields: string
9
+ ) => {
4
10
  const sel = Object.entries(selection)
5
11
  .filter(([_, val]) => val)
6
12
  .map(([key]) => key);
13
+ const level = sel.length;
14
+ if (labelsFields) {
15
+ const lFields = labelsFields.split(',');
16
+ const fields = lFields.slice(0, level);
17
+ const actualData = !level ? data : data.filter((e) => !fields.find((field, index) => e[field] != sel[index]));
18
+ const tagsHash: Hash<Tag> = {};
19
+ if (level) {
20
+ tagsHash['*'] = { id: sel[level - 1], name: sel.join(' ➡ '), count: 0, selected: level > 0 };
21
+ }
7
22
 
8
- if (sel.length || !initials) {
9
- const actualData = data.filter((e) => sel.reduce((r, s) => r && e.$tags.has(s), true));
10
- const tagsHash = actualData.reduce((r, e) => {
11
- e.$tags.forEach((id: string) => {
12
- const tag = r[id] || (r[id] = { id, name: id, count: 0, selected: selection[id] });
23
+ actualData.forEach((e) => {
24
+ const id = String(e[lFields[level]] || '');
25
+ if (!id) return;
26
+ const tag = tagsHash[id] || (tagsHash[id] = { id, name: id, count: 0, selected: selection[id] });
27
+ if (!tag.selected) {
28
+ tag.count++;
29
+ }
30
+ });
31
+
32
+ tags.push(...Object.values(tagsHash));
33
+ // tags.sort((a, b) => (a.selected === b.selected ? (a.id > b.id ? 1 : -1) : !a.selected ? 1 : -1));
34
+ return actualData;
35
+ }
36
+ if (level || !initials) {
37
+ const actualData = data.filter((e) => sel.reduce((r, s) => r && e.getLabels().has(s), true));
38
+ const tagsHash: Hash<Tag> = {};
39
+ sel.forEach((id) => {
40
+ tagsHash[id] = { id, name: id, count: 0, selected: true };
41
+ });
42
+ actualData.forEach((e) => {
43
+ e.getLabels().forEach((id: string) => {
44
+ const tag =
45
+ tagsHash[id] || (tagsHash[id] = { id, name: id, count: 0, selected: selection[id], nonSelectable: true });
13
46
  if (!tag.selected) {
47
+ tag.nonSelectable = false;
14
48
  tag.count++;
15
49
  }
16
50
  });
17
- return r;
18
- }, {});
19
- return { actualData, tags: Object.values(tagsHash) };
51
+ });
52
+
53
+ tags.push(...Object.values(tagsHash));
54
+ tags.sort((a, b) => (a.selected === b.selected ? (a.id > b.id ? 1 : -1) : !a.selected ? 1 : -1));
55
+ return actualData;
20
56
  } else {
21
- const tags = initials.split(',').map((id) => ({ id, name: id, count: 0, selected: false }));
57
+ tags.push(...initials.split(',').map((id) => ({ id, name: id, count: 0, selected: false })));
22
58
  data.forEach((e: Item) => {
23
59
  tags.forEach((tag) => {
24
- if (e.$tags.has(tag.id)) {
60
+ if (e.getLabels().has(tag.id)) {
25
61
  tag.count++;
26
62
  }
27
63
  });
28
64
  });
29
- return { actualData: data, tags };
65
+ return data;
30
66
  }
31
67
  };
32
68
 
33
69
  export const getSuggestions = (data: Item[], kluq: string) => {
34
70
  if (!kluq) return null;
35
71
 
36
- const words = {};
72
+ const words: Hash = {};
37
73
  data.forEach((e) =>
38
- e.$searchData.replace(/\w{3,}/g, (w) => {
74
+ e.$searchData.replace(/[a-z0-9а-яёўі]{3,}/g, (w) => {
39
75
  words[w] = 1;
40
76
  return '';
41
77
  })
42
78
  );
79
+ const lokey = kluq.toLowerCase();
43
80
  return arraySortBy(
44
81
  Object.keys(words)
45
- .filter((e) => e.includes(kluq))
82
+ .filter((e) => e.startsWith(lokey))
46
83
  .map((s) => ({ name: s, id: s })),
47
84
  'name'
48
85
  );
49
86
  };
87
+ export const applyNavInfo = (data: Item[]) => {
88
+ let prev: Item | null = null;
89
+ return !data
90
+ ? null
91
+ : data.map((item: Item, index) => {
92
+ item.$navInfo = { prev, index, total: data.length };
93
+ if (prev?.$navInfo) {
94
+ prev.$navInfo.next = item;
95
+ }
96
+ prev = item;
97
+ return item;
98
+ });
99
+ };
50
100
 
51
- export class Item {
52
- constructor(opts = {}, opts2 = {}) {
53
- Object.assign(this, opts, opts2);
54
- }
55
- get ts() {
56
- return this.$ts || (this.$ts = this.modified_at || this.created_at || -1);
57
- }
58
- set ts(_) {}
59
- get $tags() {
60
- return this.$$tags || (this.$$tags = new Set((this.status + ',' + this.type || '').split(',').filter(Boolean)));
101
+ export class Item implements Delta {
102
+ id?: string;
103
+ $row?: string;
104
+ $: Hash<any> = {};
105
+ $navInfo?: { index: number; total: number; prev?: Item | null; next?: Item };
106
+ [key: string]: unknown;
107
+
108
+ constructor({ $, ...opts }: Delta = {}) {
109
+ Object.assign(this, opts);
61
110
  }
62
- get title() {
63
- return this.$title || (this.$title = this.name || this.subject || this.topic || this.id);
111
+ getLabels(): Set<string> {
112
+ const key = 'labels';
113
+ return (
114
+ this.$[key] ||
115
+ (this.$[key] = new Set(
116
+ String(this[key] || this.labels)
117
+ .split(',')
118
+ .filter(Boolean)
119
+ ))
120
+ );
64
121
  }
65
122
  get $searchData() {
66
- return this.$$searchData || (this.$$searchData = (this.subject + ' ' + this.notes).toLowerCase());
123
+ if (!('searchData' in this.$)) {
124
+ this.$.searchData = String(this.searchData || this.name).toLowerCase();
125
+ }
126
+ return this.$.searchData;
127
+ }
128
+ get $dataset() {
129
+ const { $row, $navInfo, $, ...d } = this;
130
+ return d;
67
131
  }
68
132
  }
@@ -0,0 +1,113 @@
1
+ import { Service } from '../services/Service';
2
+ import { analyzeDataByTags, getSuggestions, applyNavInfo, Item } from './Item';
3
+ import { arraySortBy } from '../../lib';
4
+ import { Storage } from '../services/Storage';
5
+
6
+ export class ItemCollectionController extends Service {
7
+ selection: Hash<boolean> = {};
8
+ shownLimit = 40;
9
+ sortBy = 'title';
10
+ kluqPoshuku = '';
11
+ data?: Item[] | null;
12
+ inputKluqPoshuku = '';
13
+ newEntry: any;
14
+ entry: any;
15
+ initials = '';
16
+ tags: Tag[] = [];
17
+
18
+ local = new Storage('local');
19
+
20
+ get searchHistory(): string[] {
21
+ const str = this.local?.get('searchHistory');
22
+ return str ? str.split(',') : null;
23
+ }
24
+
25
+ get searchSuggestion() {
26
+ if (this.kluqPoshuku === this.inputKluqPoshuku) {
27
+ if (this.kluqPoshuku) return null;
28
+ return this.searchHistory?.map((s: string) => ({ name: s, id: s }));
29
+ }
30
+ return this.data ? getSuggestions(this.data, this.inputKluqPoshuku) : null;
31
+ }
32
+
33
+ set searchHistory(arr) {
34
+ this.local?.set('searchHistory', (arr || []).join(','));
35
+ }
36
+ addHistoryItem(value: string) {
37
+ if (value) {
38
+ this.searchHistory = [value, ...(this.searchHistory || []).filter((s) => s != value)].slice(0, 20);
39
+ }
40
+ }
41
+ setData(data: Hash[]) {
42
+ this.data = !data ? null : data.map((e) => new Item(e));
43
+ }
44
+
45
+ get sortedData() {
46
+ const data = this.data;
47
+ if (!data) return null;
48
+
49
+ const searchedData = !this.kluqPoshuku ? data : data.filter((e) => e.$searchData.startsWith(this.kluqPoshuku));
50
+ this.tags = [];
51
+ const actualData = analyzeDataByTags(searchedData, this.selection, this.initials, this.tags, this.labelsFields);
52
+ return applyNavInfo(arraySortBy(actualData, this.sortBy) as unknown as Item[]);
53
+ }
54
+
55
+ getInfo() {
56
+ const data = this.sortedData;
57
+ if (!data) {
58
+ return {};
59
+ }
60
+ return {
61
+ tags: this.tags,
62
+ data: this.sortedData?.slice(0, this.shownLimit),
63
+ counts: {
64
+ total: data.length,
65
+ actual: data.length,
66
+ hasMore: this.shownLimit < data.length,
67
+ },
68
+ search: {
69
+ kluq: this.kluqPoshuku,
70
+ value: this.inputKluqPoshuku,
71
+ suggestions: this.searchSuggestion,
72
+ input: this.createEmitter('this.inputKluq'),
73
+ enter: this.createEmitter('this.znajdzPoKluqu'),
74
+ },
75
+ };
76
+ }
77
+
78
+ // event handlers:
79
+
80
+ onTag({ id }: Tag, { selection }: this) {
81
+ return {
82
+ selection: !id
83
+ ? {}
84
+ : {
85
+ ...selection,
86
+ [id]: !selection[id],
87
+ },
88
+ };
89
+ }
90
+ onZnajdzPoKluqu({ value }: StringHash) {
91
+ this.addHistoryItem(value);
92
+
93
+ return {
94
+ inputKluqPoshuku: value || '',
95
+ kluqPoshuku: value || '',
96
+ };
97
+ }
98
+ onInputKluq({ value }: Delta) {
99
+ return {
100
+ inputKluqPoshuku: value || '',
101
+ };
102
+ }
103
+ onSortBy({ value }: Delta) {
104
+ return {
105
+ sortBy: value || '-title',
106
+ };
107
+ }
108
+ onShowMore({ size = 50 }, { shownLimit }: this) {
109
+ return {
110
+ shownLimit: shownLimit + size,
111
+ };
112
+ }
113
+ }
@@ -1,21 +1,20 @@
1
1
  import { Service } from '../services/Service';
2
2
  import { Item } from './Item';
3
- import { getPredicat } from 'predicat';
3
+ import { getPredicat } from '../../lib';
4
4
 
5
+ const CHANGES: Hash<Hash> = {};
5
6
  export class ItemController extends Service {
6
7
  all?: Hash<Hash>;
7
- delta?: Hash;
8
8
  itemId: string = '';
9
9
  meta: any;
10
10
  context: any;
11
11
 
12
+ get initialElement() {
13
+ return Array.isArray(this.all) ? this.all.find((e) => e.id == this.itemId) : this.all?.[this.itemId];
14
+ }
12
15
  get initialData() {
13
- const initial = this.all?.[this.itemId];
14
- if (!initial?.id) {
15
- return null;
16
- }
17
- const { $row, ...d } = initial;
18
- return d;
16
+ const e = this.initialElement;
17
+ return !e?.id ? null : e.$dataset;
19
18
  }
20
19
 
21
20
  get actualData() {
@@ -23,10 +22,10 @@ export class ItemController extends Service {
23
22
  if (!initial) {
24
23
  return null;
25
24
  }
26
- const data = { ...this.context, ...initial, ...this.delta };
25
+ const data = { ...this.context, ...initial, ...CHANGES[this.itemId] };
27
26
  this.meta?.map((field: { [k: string]: string }) => {
28
27
  const { id, visible } = field;
29
- const isVisible = getPredicat(visible || 'true')(data);
28
+ const isVisible = !visible || getPredicat(visible)(data);
30
29
  if (!isVisible && data[id]) {
31
30
  data[id] = '';
32
31
  }
@@ -38,25 +37,55 @@ export class ItemController extends Service {
38
37
  return new Item(this.actualData || {});
39
38
  }
40
39
 
41
- upsert(data?: Hash) {
40
+ get itemNavInfo() {
41
+ return { prev: null, next: null, ...this.initialElement?.$navInfo };
42
+ }
43
+
44
+ get itemTitle() {
45
+ return this.initialElement?.title;
46
+ }
47
+
48
+ get touched() {
49
+ return !!CHANGES[this.itemId];
50
+ }
51
+
52
+ upsert(data?: Hash): Hash {
42
53
  throw new Error('upsert not defined.' + data);
43
54
  }
44
55
 
45
- onReset = () => ({ delta: {} });
56
+ async submitData(data: Delta) {
57
+ if (!data) return null;
58
+
59
+ const { error, lastUpdatedItemId, ...rest } = await this.upsert(data);
60
+ console.log(error, rest);
61
+ if (error) {
62
+ const msg = (error as Error)?.message;
63
+ this.toast({ id: msg, mode: 'error', message: 'Error: ' + msg });
64
+ return null;
65
+ }
66
+ delete CHANGES[this.itemId];
67
+ this.toast({ message: 'Saved successfully.', timeout: 5000, link: '#/task?itemId=' + lastUpdatedItemId });
68
+ return {
69
+ counter: NaN,
70
+ };
71
+ }
46
72
 
47
- onChange = (delta: Hash) => ({ delta: { ...this.delta, ...delta } });
73
+ // event handlers:
74
+ onChange = (delta: Hash) => {
75
+ CHANGES[this.itemId] = { ...CHANGES[this.itemId], ...delta };
76
+ return {
77
+ counter: NaN,
78
+ };
79
+ };
48
80
 
49
81
  onSave() {
50
- const data = this.actualData;
51
- if (data) {
52
- this.upsert(data);
53
- }
82
+ return this.submitData(this.actualData);
54
83
  }
55
84
 
56
85
  onDelete() {
57
- const id = this.initialData?.id;
58
- if (id) {
59
- this.upsert({ id, status: 'deleted' });
60
- }
86
+ const { id } = this.initialElement?.id;
87
+ if (!id) return null;
88
+
89
+ return this.submitData({ id, status: 'deleted' });
61
90
  }
62
91
  }
@@ -0,0 +1,46 @@
1
+ import { Service } from '../services/Service';
2
+
3
+ export class NewItemController extends Service {
4
+ data: any;
5
+ info: any;
6
+
7
+ upsert(_data: any) {
8
+ throw new Error('Method not implemented.');
9
+ }
10
+ async submitData(data: Delta) {
11
+ if (!data) return null;
12
+
13
+ const { error, lastUpdatedItemId, ...rest } = await this.upsert(data);
14
+ console.log(error, rest);
15
+ if (error) {
16
+ const msg = (error as Error)?.message;
17
+ this.toast({ id: msg, mode: 'error', message: 'Error: ' + msg });
18
+ return null;
19
+ }
20
+
21
+ this.toast({ message: 'Added successfully. ', timeout: 5000, link: '#/task?itemId=' + lastUpdatedItemId });
22
+ return {
23
+ info: { open: false, data: {} },
24
+ };
25
+ }
26
+ // event handlers:
27
+
28
+ onOpenAddNew() {
29
+ return {
30
+ info: {
31
+ data: this.data,
32
+ open: true,
33
+ },
34
+ };
35
+ }
36
+
37
+ onCancel() {
38
+ return {
39
+ info: { open: false },
40
+ };
41
+ }
42
+
43
+ onSubmit(data: Delta) {
44
+ return this.submitData(data);
45
+ }
46
+ }
@@ -6,14 +6,14 @@
6
6
  <div class="form-input" style="height: auto;min-height:1.5rem;">{value}</div>
7
7
  </ui:then>
8
8
  <ui:else>
9
- <div class="has-icon-right" click="{open|bindArgs:true}">
9
+ <div class="has-icon-right" click="{open|fnBindArgs:true}">
10
10
  <div class="form-input text-{value|then::gray}" style="height: auto;min-height:1.5rem;">{value|or:@placeholder}</div>
11
11
  <i class="form-icon icon icon-edit c-hand"></i>
12
12
  </div>
13
13
  </ui:else>
14
14
  </ui:fragment>
15
15
 
16
- <Modal open="{opened}" mode="sm" ui:if="{opened}" close="{open|bindArgs:false}">
16
+ <Modal open="{opened}" mode="sm" ui:if="{opened}" close="{open|fnBindArgs:false}">
17
17
  <Modal:header>
18
18
  <h6>{caption}</h6>
19
19
  </Modal:header>
@@ -37,7 +37,7 @@
37
37
  </div>
38
38
 
39
39
  <Modal:footer>
40
- <Btn class="float-right" mode="primary" title="OK" action="{open|bindArgs:false}"/>
40
+ <Btn class="float-right" mode="primary" title="OK" action="{open|fnBindArgs:false}"/>
41
41
  </Modal:footer>
42
42
  </Modal>
43
43
  </div>
@@ -1,11 +1,11 @@
1
1
  <component id="SuggestionInput">
2
2
  <div class="form-autocomplete">
3
3
  <div class="has-icon-right">
4
- <input class="form-input" type="text" disabled="{disabled}" placeholder="{placeholder}" focus="{open|bindArgs:true}" blur2="{open|bindArgs:false|nextTick:200}" keypress="{change}" value="{value}" />
4
+ <input class="form-input" type="text" disabled="{disabled}" placeholder="{placeholder}" focus="{open|fnBindArgs:true}" blur2="{open|fnBindArgs:false|fnTick:200}" keypress="{change}" value="{value}" />
5
5
  <i class="form-icon icon icon-{value|then:cross:arrow-down} c-hand" style="margin-right:{options.length|then:1.5:0.25}rem;" click="{reset}" ui:if="disabled|not|and:@value"></i>
6
6
  <ui:fragment ui:if="options|and:@options.length">
7
- <i class="form-icon icon icon-arrow-up c-hand" click="{open|bindArgs:false}" ui:if="opened"></i>
8
- <i class="form-icon icon icon-arrow-down c-hand" click="{open|bindArgs:true}" ui:if="opened|not"></i>
7
+ <i class="form-icon icon icon-arrow-up c-hand" click="{open|fnBindArgs:false}" ui:if="opened"></i>
8
+ <i class="form-icon icon icon-arrow-down c-hand" click="{open|fnBindArgs:true}" ui:if="opened|not"></i>
9
9
  </ui:fragment>
10
10
  </div>
11
11
  <ul class="menu" style="position2: relative; min-width: 180px;max-height:7rem;overflow-y:auto;" ui:if="{options|and:@options.length|and:@opened}">