x4js 1.5.5 → 1.5.6
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/lib/changelog.txt +8 -0
- package/lib/cjs/combobox.js +111 -21
- package/lib/cjs/label.js +2 -2
- package/lib/cjs/listview.js +3 -1
- package/lib/cjs/messagebox.js +27 -0
- package/lib/cjs/tools.js +1 -1
- package/lib/cjs/version.js +1 -1
- package/lib/esm/combobox.js +114 -22
- package/lib/esm/label.js +3 -3
- package/lib/esm/listview.js +3 -1
- package/lib/esm/messagebox.js +16 -0
- package/lib/esm/tools.js +1 -1
- package/lib/esm/version.js +1 -1
- package/lib/src/combobox.ts +141 -38
- package/lib/src/label.ts +3 -3
- package/lib/src/listview.ts +5 -2
- package/lib/src/messagebox.ts +21 -0
- package/lib/src/tools.ts +1 -1
- package/lib/src/version.ts +1 -1
- package/lib/types/combobox.d.ts +11 -5
- package/lib/types/listview.d.ts +1 -1
- package/lib/types/messagebox.d.ts +1 -0
- package/lib/types/version.d.ts +1 -1
- package/package.json +1 -1
package/lib/changelog.txt
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
2022/12/08 : 1.5.6 --------------------------------------------------------
|
|
2
|
+
combobox.ts - allow editable
|
|
3
|
+
items can be a function
|
|
4
|
+
populate removed
|
|
5
|
+
|
|
6
|
+
listview.ts - focus bug on popuplistview
|
|
7
|
+
label.ts - bug: display dangerous html elements when multiline = true
|
|
8
|
+
|
|
1
9
|
2022/12/05 : 1.5.1 --------------------------------------------------------
|
|
2
10
|
icon.ts - now accepts direct <svg>..</svg> in argument (var or other)
|
|
3
11
|
|
package/lib/cjs/combobox.js
CHANGED
|
@@ -47,9 +47,36 @@ const tools_1 = require("./tools");
|
|
|
47
47
|
class ComboBox extends layout_1.HLayout {
|
|
48
48
|
constructor(props) {
|
|
49
49
|
super(props);
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
if (!props.editable) {
|
|
51
|
+
this.setDomEvent('keypress', () => this.showPopup());
|
|
52
|
+
}
|
|
53
|
+
this.setDomEvent('click', () => {
|
|
54
|
+
if (this.m_props.editable) {
|
|
55
|
+
this.m_ui_input.focus();
|
|
56
|
+
}
|
|
57
|
+
this.showPopup();
|
|
58
|
+
});
|
|
59
|
+
this.setDomEvent("keydown", e => this._onKey(e));
|
|
52
60
|
this.mapPropEvents(props, 'selectionChange');
|
|
61
|
+
this.m_popvis = false;
|
|
62
|
+
this.m_lockpop = false;
|
|
63
|
+
this.m_lockchg = false;
|
|
64
|
+
}
|
|
65
|
+
_onKey(e) {
|
|
66
|
+
if (this.m_popvis) {
|
|
67
|
+
if (e.key == "ArrowUp" || e.key == "ArrowDown") {
|
|
68
|
+
this.m_lockpop = true;
|
|
69
|
+
this.m_popup.handleKey(e);
|
|
70
|
+
this.m_lockpop = false;
|
|
71
|
+
e.preventDefault();
|
|
72
|
+
e.stopPropagation();
|
|
73
|
+
}
|
|
74
|
+
else if (e.key == "Escape") {
|
|
75
|
+
this._hidePopup();
|
|
76
|
+
e.preventDefault();
|
|
77
|
+
e.stopPropagation();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
53
80
|
}
|
|
54
81
|
set items(items) {
|
|
55
82
|
this.m_props.items = items;
|
|
@@ -61,16 +88,35 @@ class ComboBox extends layout_1.HLayout {
|
|
|
61
88
|
render(props) {
|
|
62
89
|
var _a;
|
|
63
90
|
if (!props.renderer) {
|
|
64
|
-
|
|
91
|
+
const input = new input_1.Input({
|
|
65
92
|
flex: 1,
|
|
66
|
-
readOnly: true,
|
|
93
|
+
readOnly: this.m_props.editable ? false : true,
|
|
67
94
|
tabIndex: 0,
|
|
68
95
|
name: props.name,
|
|
69
96
|
value_hook: {
|
|
70
97
|
get: () => { return this.value; },
|
|
71
98
|
set: (v) => { this.value = v; }
|
|
99
|
+
},
|
|
100
|
+
dom_events: {
|
|
101
|
+
focus: () => {
|
|
102
|
+
if (this.m_props.editable && input.value.length == 0) {
|
|
103
|
+
this.showPopup();
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
input: () => {
|
|
107
|
+
if (this.m_lockchg) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const text = input.value;
|
|
111
|
+
this.m_selection = { id: undefined, text };
|
|
112
|
+
let items = this.showPopup();
|
|
113
|
+
if (items && items.length && items[0].text == text) {
|
|
114
|
+
this.m_selection = { id: items[0].id, text };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
72
117
|
}
|
|
73
118
|
});
|
|
119
|
+
this.m_ui_input = input;
|
|
74
120
|
}
|
|
75
121
|
else {
|
|
76
122
|
this.m_ui_input = new component_1.Component({
|
|
@@ -104,7 +150,9 @@ class ComboBox extends layout_1.HLayout {
|
|
|
104
150
|
cls: 'gadget',
|
|
105
151
|
icon: 'var( --x4-icon-angle-down )',
|
|
106
152
|
tabIndex: false,
|
|
107
|
-
click: () =>
|
|
153
|
+
click: () => {
|
|
154
|
+
this.showPopup(false);
|
|
155
|
+
},
|
|
108
156
|
dom_events: {
|
|
109
157
|
focus: () => { this.dom.focus(); },
|
|
110
158
|
}
|
|
@@ -125,10 +173,18 @@ class ComboBox extends layout_1.HLayout {
|
|
|
125
173
|
/**
|
|
126
174
|
* display the popup
|
|
127
175
|
*/
|
|
128
|
-
showPopup() {
|
|
176
|
+
showPopup(filter_items = true) {
|
|
129
177
|
let props = this.m_props;
|
|
130
178
|
if (props.readOnly || this.hasClass("@disable")) {
|
|
131
|
-
return;
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
let items = props.items;
|
|
182
|
+
if ((0, tools_1.isFunction)(items)) {
|
|
183
|
+
const filter = filter_items ? this.m_ui_input.value : null;
|
|
184
|
+
items = items(filter);
|
|
185
|
+
}
|
|
186
|
+
if (items.length == 0) {
|
|
187
|
+
return null;
|
|
132
188
|
}
|
|
133
189
|
// need creation ?
|
|
134
190
|
if (!this.m_popup) {
|
|
@@ -138,10 +194,15 @@ class ComboBox extends layout_1.HLayout {
|
|
|
138
194
|
// prepare the combo listview
|
|
139
195
|
this.m_popup = new listview_1.PopupListView({
|
|
140
196
|
cls: '@combo-popup',
|
|
141
|
-
items: props.items,
|
|
142
197
|
populate: props.populate,
|
|
143
198
|
renderItem: this.m_props.renderer,
|
|
144
|
-
selectionChange: (e) =>
|
|
199
|
+
selectionChange: (e) => {
|
|
200
|
+
this._selectItem(e);
|
|
201
|
+
if (!this.m_lockpop) {
|
|
202
|
+
this._hidePopup();
|
|
203
|
+
this.focus();
|
|
204
|
+
}
|
|
205
|
+
},
|
|
145
206
|
cancel: (e) => this.signal('cancel', e),
|
|
146
207
|
style: {
|
|
147
208
|
fontFamily,
|
|
@@ -149,14 +210,18 @@ class ComboBox extends layout_1.HLayout {
|
|
|
149
210
|
}
|
|
150
211
|
});
|
|
151
212
|
}
|
|
213
|
+
this.m_popup.items = items;
|
|
152
214
|
let r1 = this.m_ui_button.getBoundingRect(), r2 = this.m_ui_input.getBoundingRect();
|
|
153
215
|
this.m_popup.setStyle({
|
|
154
216
|
minWidth: r1.right - r2.left,
|
|
155
217
|
});
|
|
156
218
|
this.m_popup.displayAt(r2.left, r2.bottom);
|
|
219
|
+
this.m_popvis = true;
|
|
220
|
+
this.startTimer("focus-check", 100, true, () => this._checkFocus());
|
|
157
221
|
if (this.value !== undefined) {
|
|
158
222
|
this.m_popup.selection = this.value;
|
|
159
223
|
}
|
|
224
|
+
return items;
|
|
160
225
|
}
|
|
161
226
|
/** @ignore
|
|
162
227
|
*/
|
|
@@ -165,15 +230,17 @@ class ComboBox extends layout_1.HLayout {
|
|
|
165
230
|
if (!item) {
|
|
166
231
|
return;
|
|
167
232
|
}
|
|
233
|
+
this.m_lockchg = true;
|
|
168
234
|
this._setInput(item, true);
|
|
235
|
+
this.m_lockchg = false;
|
|
169
236
|
this.m_selection = {
|
|
170
237
|
id: item.id,
|
|
171
238
|
text: item.text
|
|
172
239
|
};
|
|
173
240
|
this.emit('selectionChange', (0, x4events_1.EvSelectionChange)(item));
|
|
174
241
|
this.emit('change', (0, x4events_1.EvChange)(item.id));
|
|
175
|
-
this.m_ui_input.focus();
|
|
176
|
-
this.m_popup.hide();
|
|
242
|
+
//this.m_ui_input.focus( );
|
|
243
|
+
//this.m_popup.hide( );
|
|
177
244
|
}
|
|
178
245
|
/**
|
|
179
246
|
*
|
|
@@ -209,7 +276,13 @@ class ComboBox extends layout_1.HLayout {
|
|
|
209
276
|
return this.m_selection ? this.m_selection.id : undefined;
|
|
210
277
|
}
|
|
211
278
|
get valueText() {
|
|
212
|
-
|
|
279
|
+
if (this.m_selection) {
|
|
280
|
+
return this.m_selection.text;
|
|
281
|
+
}
|
|
282
|
+
if (this.m_props.editable) {
|
|
283
|
+
return this.m_ui_input.value;
|
|
284
|
+
}
|
|
285
|
+
return '';
|
|
213
286
|
}
|
|
214
287
|
/**
|
|
215
288
|
*
|
|
@@ -217,7 +290,7 @@ class ComboBox extends layout_1.HLayout {
|
|
|
217
290
|
set value(id) {
|
|
218
291
|
let items = this.m_props.items;
|
|
219
292
|
if ((0, tools_1.isFunction)(items)) {
|
|
220
|
-
items = items();
|
|
293
|
+
items = items(null);
|
|
221
294
|
}
|
|
222
295
|
const found = items.some((v) => {
|
|
223
296
|
if (v.id === id) {
|
|
@@ -234,6 +307,23 @@ class ComboBox extends layout_1.HLayout {
|
|
|
234
307
|
get input() {
|
|
235
308
|
return this.m_ui_input instanceof input_1.Input ? this.m_ui_input : null;
|
|
236
309
|
}
|
|
310
|
+
_checkFocus() {
|
|
311
|
+
const focus = document.activeElement;
|
|
312
|
+
if (this.dom && this.dom.contains(focus) || focus == document.body) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
if (this.m_popup && this.m_popup.dom && this.m_popup.dom.contains(focus)) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
this._hidePopup();
|
|
319
|
+
}
|
|
320
|
+
_hidePopup() {
|
|
321
|
+
if (this.m_popvis) {
|
|
322
|
+
this.m_popup.close();
|
|
323
|
+
this.m_popvis = false;
|
|
324
|
+
this.stopTimer("focus-check");
|
|
325
|
+
}
|
|
326
|
+
}
|
|
237
327
|
static storeProxy(props) {
|
|
238
328
|
let view = props.store instanceof datastore_1.DataStore ? props.store.createView() : props.store;
|
|
239
329
|
return () => {
|
|
@@ -247,13 +337,13 @@ class ComboBox extends layout_1.HLayout {
|
|
|
247
337
|
return result;
|
|
248
338
|
};
|
|
249
339
|
}
|
|
340
|
+
focus() {
|
|
341
|
+
if (this.m_props.editable) {
|
|
342
|
+
this.m_ui_input.focus();
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
super.focus();
|
|
346
|
+
}
|
|
347
|
+
}
|
|
250
348
|
}
|
|
251
349
|
exports.ComboBox = ComboBox;
|
|
252
|
-
/*
|
|
253
|
-
export type CBComboBoxRenderer = ( rec: Record ) => string;
|
|
254
|
-
export interface ComboBoxStore {
|
|
255
|
-
store: DataStore;
|
|
256
|
-
display: string | CBComboBoxRenderer; // if string, the field name to display
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
*/
|
package/lib/cjs/label.js
CHANGED
|
@@ -49,7 +49,7 @@ class Label extends component_1.Component {
|
|
|
49
49
|
var _a;
|
|
50
50
|
let text = this.m_props.text;
|
|
51
51
|
if (this.m_props.multiline && !(text instanceof tools_1.HtmlString)) {
|
|
52
|
-
text = new tools_1.HtmlString(
|
|
52
|
+
text = new tools_1.HtmlString((0, tools_1.escapeHtml)(text, true));
|
|
53
53
|
}
|
|
54
54
|
if (!props.icon) {
|
|
55
55
|
this.setContent(text);
|
|
@@ -74,7 +74,7 @@ class Label extends component_1.Component {
|
|
|
74
74
|
props.text = txt;
|
|
75
75
|
let text = this.m_props.text;
|
|
76
76
|
if (this.m_props.multiline && !(text instanceof tools_1.HtmlString)) {
|
|
77
|
-
text = new tools_1.HtmlString(
|
|
77
|
+
text = new tools_1.HtmlString((0, tools_1.escapeHtml)(text, true));
|
|
78
78
|
}
|
|
79
79
|
if (this.dom) {
|
|
80
80
|
let comp = this;
|
package/lib/cjs/listview.js
CHANGED
|
@@ -64,7 +64,7 @@ class ListView extends layout_1.VLayout {
|
|
|
64
64
|
this._buildItems();
|
|
65
65
|
}
|
|
66
66
|
else if (this.m_props.populate) {
|
|
67
|
-
this.items = this.m_props.populate();
|
|
67
|
+
this.items = this.m_props.populate(null);
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
render(props) {
|
|
@@ -316,6 +316,8 @@ class ListView extends layout_1.VLayout {
|
|
|
316
316
|
}
|
|
317
317
|
/** @ignore */
|
|
318
318
|
_handleClick(e) {
|
|
319
|
+
e.stopImmediatePropagation();
|
|
320
|
+
e.preventDefault();
|
|
319
321
|
let dom = e.target, self = this.dom, list_items = this.m_props.items; // already created by build
|
|
320
322
|
// go up until we find something interesting
|
|
321
323
|
while (dom && dom != self) {
|
package/lib/cjs/messagebox.js
CHANGED
|
@@ -27,6 +27,15 @@
|
|
|
27
27
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
28
28
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
29
29
|
**/
|
|
30
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
31
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
32
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
33
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
34
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
35
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
36
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
37
|
+
});
|
|
38
|
+
};
|
|
30
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
40
|
exports.PromptDialogBox = exports.MessageBox = void 0;
|
|
32
41
|
const dialog_1 = require("./dialog");
|
|
@@ -79,6 +88,24 @@ class MessageBox extends dialog_1.Dialog {
|
|
|
79
88
|
msg.show();
|
|
80
89
|
return msg;
|
|
81
90
|
}
|
|
91
|
+
static showAsync(props) {
|
|
92
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
93
|
+
return new Promise((resolve, reject) => {
|
|
94
|
+
let _props;
|
|
95
|
+
const cb = (btn) => {
|
|
96
|
+
resolve(btn);
|
|
97
|
+
};
|
|
98
|
+
if ((0, tools_1.isString)(props) || (0, tools_1.isHtmlString)(props)) {
|
|
99
|
+
_props = { message: props, click: cb };
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
_props = Object.assign(Object.assign({}, props), { click: cb });
|
|
103
|
+
}
|
|
104
|
+
const msg = new MessageBox(_props);
|
|
105
|
+
msg.show();
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
82
109
|
/**
|
|
83
110
|
* display an alert message
|
|
84
111
|
*/
|
package/lib/cjs/tools.js
CHANGED
|
@@ -273,7 +273,7 @@ exports.sprintf = sprintf;
|
|
|
273
273
|
*/
|
|
274
274
|
function escapeHtml(unsafe, nl_br = false) {
|
|
275
275
|
if (!unsafe || unsafe.length == 0) {
|
|
276
|
-
return
|
|
276
|
+
return "";
|
|
277
277
|
}
|
|
278
278
|
let result = unsafe.replace(/[<>\&\"\']/g, function (c) {
|
|
279
279
|
return '&#' + c.charCodeAt(0) + ';';
|
package/lib/cjs/version.js
CHANGED
package/lib/esm/combobox.js
CHANGED
|
@@ -45,13 +45,42 @@ export class ComboBox extends HLayout {
|
|
|
45
45
|
m_ui_input;
|
|
46
46
|
m_ui_button;
|
|
47
47
|
m_popup;
|
|
48
|
+
m_lockpop;
|
|
49
|
+
m_lockchg;
|
|
50
|
+
m_popvis;
|
|
48
51
|
m_selection;
|
|
49
|
-
m_defer_sel;
|
|
50
52
|
constructor(props) {
|
|
51
53
|
super(props);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
+
if (!props.editable) {
|
|
55
|
+
this.setDomEvent('keypress', () => this.showPopup());
|
|
56
|
+
}
|
|
57
|
+
this.setDomEvent('click', () => {
|
|
58
|
+
if (this.m_props.editable) {
|
|
59
|
+
this.m_ui_input.focus();
|
|
60
|
+
}
|
|
61
|
+
this.showPopup();
|
|
62
|
+
});
|
|
63
|
+
this.setDomEvent("keydown", e => this._onKey(e));
|
|
54
64
|
this.mapPropEvents(props, 'selectionChange');
|
|
65
|
+
this.m_popvis = false;
|
|
66
|
+
this.m_lockpop = false;
|
|
67
|
+
this.m_lockchg = false;
|
|
68
|
+
}
|
|
69
|
+
_onKey(e) {
|
|
70
|
+
if (this.m_popvis) {
|
|
71
|
+
if (e.key == "ArrowUp" || e.key == "ArrowDown") {
|
|
72
|
+
this.m_lockpop = true;
|
|
73
|
+
this.m_popup.handleKey(e);
|
|
74
|
+
this.m_lockpop = false;
|
|
75
|
+
e.preventDefault();
|
|
76
|
+
e.stopPropagation();
|
|
77
|
+
}
|
|
78
|
+
else if (e.key == "Escape") {
|
|
79
|
+
this._hidePopup();
|
|
80
|
+
e.preventDefault();
|
|
81
|
+
e.stopPropagation();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
55
84
|
}
|
|
56
85
|
set items(items) {
|
|
57
86
|
this.m_props.items = items;
|
|
@@ -62,16 +91,35 @@ export class ComboBox extends HLayout {
|
|
|
62
91
|
/** @ignore */
|
|
63
92
|
render(props) {
|
|
64
93
|
if (!props.renderer) {
|
|
65
|
-
|
|
94
|
+
const input = new Input({
|
|
66
95
|
flex: 1,
|
|
67
|
-
readOnly: true,
|
|
96
|
+
readOnly: this.m_props.editable ? false : true,
|
|
68
97
|
tabIndex: 0,
|
|
69
98
|
name: props.name,
|
|
70
99
|
value_hook: {
|
|
71
100
|
get: () => { return this.value; },
|
|
72
101
|
set: (v) => { this.value = v; }
|
|
102
|
+
},
|
|
103
|
+
dom_events: {
|
|
104
|
+
focus: () => {
|
|
105
|
+
if (this.m_props.editable && input.value.length == 0) {
|
|
106
|
+
this.showPopup();
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
input: () => {
|
|
110
|
+
if (this.m_lockchg) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const text = input.value;
|
|
114
|
+
this.m_selection = { id: undefined, text };
|
|
115
|
+
let items = this.showPopup();
|
|
116
|
+
if (items && items.length && items[0].text == text) {
|
|
117
|
+
this.m_selection = { id: items[0].id, text };
|
|
118
|
+
}
|
|
119
|
+
}
|
|
73
120
|
}
|
|
74
121
|
});
|
|
122
|
+
this.m_ui_input = input;
|
|
75
123
|
}
|
|
76
124
|
else {
|
|
77
125
|
this.m_ui_input = new Component({
|
|
@@ -105,7 +153,9 @@ export class ComboBox extends HLayout {
|
|
|
105
153
|
cls: 'gadget',
|
|
106
154
|
icon: 'var( --x4-icon-angle-down )',
|
|
107
155
|
tabIndex: false,
|
|
108
|
-
click: () =>
|
|
156
|
+
click: () => {
|
|
157
|
+
this.showPopup(false);
|
|
158
|
+
},
|
|
109
159
|
dom_events: {
|
|
110
160
|
focus: () => { this.dom.focus(); },
|
|
111
161
|
}
|
|
@@ -126,10 +176,18 @@ export class ComboBox extends HLayout {
|
|
|
126
176
|
/**
|
|
127
177
|
* display the popup
|
|
128
178
|
*/
|
|
129
|
-
showPopup() {
|
|
179
|
+
showPopup(filter_items = true) {
|
|
130
180
|
let props = this.m_props;
|
|
131
181
|
if (props.readOnly || this.hasClass("@disable")) {
|
|
132
|
-
return;
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
let items = props.items;
|
|
185
|
+
if (isFunction(items)) {
|
|
186
|
+
const filter = filter_items ? this.m_ui_input.value : null;
|
|
187
|
+
items = items(filter);
|
|
188
|
+
}
|
|
189
|
+
if (items.length == 0) {
|
|
190
|
+
return null;
|
|
133
191
|
}
|
|
134
192
|
// need creation ?
|
|
135
193
|
if (!this.m_popup) {
|
|
@@ -139,10 +197,15 @@ export class ComboBox extends HLayout {
|
|
|
139
197
|
// prepare the combo listview
|
|
140
198
|
this.m_popup = new PopupListView({
|
|
141
199
|
cls: '@combo-popup',
|
|
142
|
-
items: props.items,
|
|
143
200
|
populate: props.populate,
|
|
144
201
|
renderItem: this.m_props.renderer,
|
|
145
|
-
selectionChange: (e) =>
|
|
202
|
+
selectionChange: (e) => {
|
|
203
|
+
this._selectItem(e);
|
|
204
|
+
if (!this.m_lockpop) {
|
|
205
|
+
this._hidePopup();
|
|
206
|
+
this.focus();
|
|
207
|
+
}
|
|
208
|
+
},
|
|
146
209
|
cancel: (e) => this.signal('cancel', e),
|
|
147
210
|
style: {
|
|
148
211
|
fontFamily,
|
|
@@ -150,14 +213,18 @@ export class ComboBox extends HLayout {
|
|
|
150
213
|
}
|
|
151
214
|
});
|
|
152
215
|
}
|
|
216
|
+
this.m_popup.items = items;
|
|
153
217
|
let r1 = this.m_ui_button.getBoundingRect(), r2 = this.m_ui_input.getBoundingRect();
|
|
154
218
|
this.m_popup.setStyle({
|
|
155
219
|
minWidth: r1.right - r2.left,
|
|
156
220
|
});
|
|
157
221
|
this.m_popup.displayAt(r2.left, r2.bottom);
|
|
222
|
+
this.m_popvis = true;
|
|
223
|
+
this.startTimer("focus-check", 100, true, () => this._checkFocus());
|
|
158
224
|
if (this.value !== undefined) {
|
|
159
225
|
this.m_popup.selection = this.value;
|
|
160
226
|
}
|
|
227
|
+
return items;
|
|
161
228
|
}
|
|
162
229
|
/** @ignore
|
|
163
230
|
*/
|
|
@@ -166,15 +233,17 @@ export class ComboBox extends HLayout {
|
|
|
166
233
|
if (!item) {
|
|
167
234
|
return;
|
|
168
235
|
}
|
|
236
|
+
this.m_lockchg = true;
|
|
169
237
|
this._setInput(item, true);
|
|
238
|
+
this.m_lockchg = false;
|
|
170
239
|
this.m_selection = {
|
|
171
240
|
id: item.id,
|
|
172
241
|
text: item.text
|
|
173
242
|
};
|
|
174
243
|
this.emit('selectionChange', EvSelectionChange(item));
|
|
175
244
|
this.emit('change', EvChange(item.id));
|
|
176
|
-
this.m_ui_input.focus();
|
|
177
|
-
this.m_popup.hide();
|
|
245
|
+
//this.m_ui_input.focus( );
|
|
246
|
+
//this.m_popup.hide( );
|
|
178
247
|
}
|
|
179
248
|
/**
|
|
180
249
|
*
|
|
@@ -210,7 +279,13 @@ export class ComboBox extends HLayout {
|
|
|
210
279
|
return this.m_selection ? this.m_selection.id : undefined;
|
|
211
280
|
}
|
|
212
281
|
get valueText() {
|
|
213
|
-
|
|
282
|
+
if (this.m_selection) {
|
|
283
|
+
return this.m_selection.text;
|
|
284
|
+
}
|
|
285
|
+
if (this.m_props.editable) {
|
|
286
|
+
return this.m_ui_input.value;
|
|
287
|
+
}
|
|
288
|
+
return '';
|
|
214
289
|
}
|
|
215
290
|
/**
|
|
216
291
|
*
|
|
@@ -218,7 +293,7 @@ export class ComboBox extends HLayout {
|
|
|
218
293
|
set value(id) {
|
|
219
294
|
let items = this.m_props.items;
|
|
220
295
|
if (isFunction(items)) {
|
|
221
|
-
items = items();
|
|
296
|
+
items = items(null);
|
|
222
297
|
}
|
|
223
298
|
const found = items.some((v) => {
|
|
224
299
|
if (v.id === id) {
|
|
@@ -235,6 +310,23 @@ export class ComboBox extends HLayout {
|
|
|
235
310
|
get input() {
|
|
236
311
|
return this.m_ui_input instanceof Input ? this.m_ui_input : null;
|
|
237
312
|
}
|
|
313
|
+
_checkFocus() {
|
|
314
|
+
const focus = document.activeElement;
|
|
315
|
+
if (this.dom && this.dom.contains(focus) || focus == document.body) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (this.m_popup && this.m_popup.dom && this.m_popup.dom.contains(focus)) {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
this._hidePopup();
|
|
322
|
+
}
|
|
323
|
+
_hidePopup() {
|
|
324
|
+
if (this.m_popvis) {
|
|
325
|
+
this.m_popup.close();
|
|
326
|
+
this.m_popvis = false;
|
|
327
|
+
this.stopTimer("focus-check");
|
|
328
|
+
}
|
|
329
|
+
}
|
|
238
330
|
static storeProxy(props) {
|
|
239
331
|
let view = props.store instanceof DataStore ? props.store.createView() : props.store;
|
|
240
332
|
return () => {
|
|
@@ -248,12 +340,12 @@ export class ComboBox extends HLayout {
|
|
|
248
340
|
return result;
|
|
249
341
|
};
|
|
250
342
|
}
|
|
343
|
+
focus() {
|
|
344
|
+
if (this.m_props.editable) {
|
|
345
|
+
this.m_ui_input.focus();
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
super.focus();
|
|
349
|
+
}
|
|
350
|
+
}
|
|
251
351
|
}
|
|
252
|
-
/*
|
|
253
|
-
export type CBComboBoxRenderer = ( rec: Record ) => string;
|
|
254
|
-
export interface ComboBoxStore {
|
|
255
|
-
store: DataStore;
|
|
256
|
-
display: string | CBComboBoxRenderer; // if string, the field name to display
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
*/
|
package/lib/esm/label.js
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
28
|
**/
|
|
29
29
|
import { Component } from './component';
|
|
30
|
-
import { HtmlString } from './tools';
|
|
30
|
+
import { escapeHtml, HtmlString } from './tools';
|
|
31
31
|
import { Icon } from './icon';
|
|
32
32
|
/**
|
|
33
33
|
* Standard label
|
|
@@ -45,7 +45,7 @@ export class Label extends Component {
|
|
|
45
45
|
render(props) {
|
|
46
46
|
let text = this.m_props.text;
|
|
47
47
|
if (this.m_props.multiline && !(text instanceof HtmlString)) {
|
|
48
|
-
text = new HtmlString(text
|
|
48
|
+
text = new HtmlString(escapeHtml(text, true));
|
|
49
49
|
}
|
|
50
50
|
if (!props.icon) {
|
|
51
51
|
this.setContent(text);
|
|
@@ -70,7 +70,7 @@ export class Label extends Component {
|
|
|
70
70
|
props.text = txt;
|
|
71
71
|
let text = this.m_props.text;
|
|
72
72
|
if (this.m_props.multiline && !(text instanceof HtmlString)) {
|
|
73
|
-
text = new HtmlString(text
|
|
73
|
+
text = new HtmlString(escapeHtml(text, true));
|
|
74
74
|
}
|
|
75
75
|
if (this.dom) {
|
|
76
76
|
let comp = this;
|
package/lib/esm/listview.js
CHANGED
|
@@ -59,7 +59,7 @@ export class ListView extends VLayout {
|
|
|
59
59
|
this._buildItems();
|
|
60
60
|
}
|
|
61
61
|
else if (this.m_props.populate) {
|
|
62
|
-
this.items = this.m_props.populate();
|
|
62
|
+
this.items = this.m_props.populate(null);
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
render(props) {
|
|
@@ -307,6 +307,8 @@ export class ListView extends VLayout {
|
|
|
307
307
|
}
|
|
308
308
|
/** @ignore */
|
|
309
309
|
_handleClick(e) {
|
|
310
|
+
e.stopImmediatePropagation();
|
|
311
|
+
e.preventDefault();
|
|
310
312
|
let dom = e.target, self = this.dom, list_items = this.m_props.items; // already created by build
|
|
311
313
|
// go up until we find something interesting
|
|
312
314
|
while (dom && dom != self) {
|
package/lib/esm/messagebox.js
CHANGED
|
@@ -76,6 +76,22 @@ export class MessageBox extends Dialog {
|
|
|
76
76
|
msg.show();
|
|
77
77
|
return msg;
|
|
78
78
|
}
|
|
79
|
+
static async showAsync(props) {
|
|
80
|
+
return new Promise((resolve, reject) => {
|
|
81
|
+
let _props;
|
|
82
|
+
const cb = (btn) => {
|
|
83
|
+
resolve(btn);
|
|
84
|
+
};
|
|
85
|
+
if (isString(props) || isHtmlString(props)) {
|
|
86
|
+
_props = { message: props, click: cb };
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
_props = { ...props, click: cb };
|
|
90
|
+
}
|
|
91
|
+
const msg = new MessageBox(_props);
|
|
92
|
+
msg.show();
|
|
93
|
+
});
|
|
94
|
+
}
|
|
79
95
|
/**
|
|
80
96
|
* display an alert message
|
|
81
97
|
*/
|
package/lib/esm/tools.js
CHANGED
|
@@ -269,7 +269,7 @@ export function sprintf(format, ...args) {
|
|
|
269
269
|
*/
|
|
270
270
|
export function escapeHtml(unsafe, nl_br = false) {
|
|
271
271
|
if (!unsafe || unsafe.length == 0) {
|
|
272
|
-
return
|
|
272
|
+
return "";
|
|
273
273
|
}
|
|
274
274
|
let result = unsafe.replace(/[<>\&\"\']/g, function (c) {
|
|
275
275
|
return '&#' + c.charCodeAt(0) + ';';
|
package/lib/esm/version.js
CHANGED
package/lib/src/combobox.ts
CHANGED
|
@@ -38,7 +38,7 @@ import { Input } from './input'
|
|
|
38
38
|
import { Label } from './label'
|
|
39
39
|
import { Button } from './button'
|
|
40
40
|
import { HLayout } from './layout'
|
|
41
|
-
import { PopupListView, ListViewItem,
|
|
41
|
+
import { PopupListView, ListViewItem, EvCancel, PopulateItems } from './listview';
|
|
42
42
|
import { DataStore, DataView, Record } from './datastore'
|
|
43
43
|
import { isFunction, HtmlString } from './tools'
|
|
44
44
|
|
|
@@ -73,12 +73,12 @@ export interface ComboBoxProps extends CProps<ComboBoxEventMap> {
|
|
|
73
73
|
|
|
74
74
|
labelAlign?: 'left' | 'right';
|
|
75
75
|
|
|
76
|
-
items?: ListViewItem[];
|
|
77
|
-
populate?: PopulateItems; // if not specified, fire 'populate' event
|
|
76
|
+
items?: ListViewItem[] | PopulateItems;
|
|
78
77
|
value?: any; // shown value at init
|
|
79
78
|
|
|
80
79
|
renderer?: ComboItemRender;
|
|
81
80
|
selectionChange?: EventCallback<EvSelectionChange>;// shortcut to events: { selectionChange: ... }
|
|
81
|
+
editable?: boolean;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/**
|
|
@@ -87,43 +87,97 @@ export interface ComboBoxProps extends CProps<ComboBoxEventMap> {
|
|
|
87
87
|
|
|
88
88
|
export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
89
89
|
|
|
90
|
-
private m_ui_input: Component;
|
|
90
|
+
private m_ui_input: Input | Component;
|
|
91
91
|
private m_ui_button: Button;
|
|
92
92
|
private m_popup: PopupListView;
|
|
93
|
-
|
|
93
|
+
private m_lockpop: boolean;
|
|
94
|
+
private m_lockchg: boolean;
|
|
95
|
+
private m_popvis: boolean;
|
|
94
96
|
private m_selection: ListViewItem;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
|
|
97
98
|
constructor(props: ComboBoxProps) {
|
|
98
99
|
super(props);
|
|
99
100
|
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
if( !props.editable ) {
|
|
102
|
+
this.setDomEvent( 'keypress', () => this.showPopup() );
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
this.setDomEvent( 'click', () => {
|
|
106
|
+
if( this.m_props.editable ) {
|
|
107
|
+
this.m_ui_input.focus( );
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
this.showPopup();
|
|
111
|
+
} );
|
|
102
112
|
|
|
113
|
+
this.setDomEvent("keydown", e => this._onKey(e));
|
|
103
114
|
this.mapPropEvents(props, 'selectionChange' );
|
|
115
|
+
|
|
116
|
+
this.m_popvis = false;
|
|
117
|
+
this.m_lockpop = false;
|
|
118
|
+
this.m_lockchg = false;
|
|
104
119
|
}
|
|
105
120
|
|
|
121
|
+
_onKey(e) {
|
|
122
|
+
if (this.m_popvis) {
|
|
123
|
+
if (e.key == "ArrowUp" || e.key == "ArrowDown") {
|
|
124
|
+
this.m_lockpop = true;
|
|
125
|
+
this.m_popup.handleKey(e);
|
|
126
|
+
this.m_lockpop = false;
|
|
127
|
+
e.preventDefault();
|
|
128
|
+
e.stopPropagation();
|
|
129
|
+
}
|
|
130
|
+
else if (e.key == "Escape") {
|
|
131
|
+
this._hidePopup();
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
e.stopPropagation();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
106
138
|
set items( items: ListViewItem[] ) {
|
|
107
139
|
this.m_props.items = items;
|
|
108
140
|
if( this.m_popup ) {
|
|
109
141
|
this.m_popup.items = items;
|
|
110
142
|
}
|
|
111
143
|
}
|
|
112
|
-
|
|
144
|
+
|
|
113
145
|
/** @ignore */
|
|
114
146
|
render( props: ComboBoxProps ) {
|
|
115
147
|
|
|
116
148
|
if( !props.renderer ) {
|
|
117
|
-
|
|
149
|
+
|
|
150
|
+
const input = new Input( {
|
|
118
151
|
flex : 1,
|
|
119
|
-
readOnly : true,
|
|
152
|
+
readOnly : this.m_props.editable ? false : true,
|
|
120
153
|
tabIndex : 0,
|
|
121
154
|
name: props.name,
|
|
122
155
|
value_hook: {
|
|
123
156
|
get: (): string => { return this.value; },
|
|
124
157
|
set: (v: string) => { this.value = v; }
|
|
158
|
+
},
|
|
159
|
+
dom_events: {
|
|
160
|
+
focus: () => {
|
|
161
|
+
if( this.m_props.editable && input.value.length==0 ) {
|
|
162
|
+
this.showPopup( );
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
input: ( ) => {
|
|
166
|
+
if( this.m_lockchg ) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const text = input.value;
|
|
171
|
+
this.m_selection = { id: undefined, text };
|
|
172
|
+
let items = this.showPopup( );
|
|
173
|
+
if( items && items.length && items[0].text==text ) {
|
|
174
|
+
this.m_selection = { id: items[0].id, text };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
125
177
|
}
|
|
126
178
|
});
|
|
179
|
+
|
|
180
|
+
this.m_ui_input = input;
|
|
127
181
|
}
|
|
128
182
|
else {
|
|
129
183
|
this.m_ui_input = new Component( {
|
|
@@ -162,7 +216,9 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
162
216
|
cls: 'gadget',
|
|
163
217
|
icon: 'var( --x4-icon-angle-down )',
|
|
164
218
|
tabIndex: false,
|
|
165
|
-
click: () =>
|
|
219
|
+
click: () => {
|
|
220
|
+
this.showPopup( false )
|
|
221
|
+
},
|
|
166
222
|
dom_events: {
|
|
167
223
|
focus: () => { this.dom.focus(); },
|
|
168
224
|
}
|
|
@@ -188,11 +244,21 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
188
244
|
* display the popup
|
|
189
245
|
*/
|
|
190
246
|
|
|
191
|
-
showPopup() {
|
|
247
|
+
showPopup( filter_items: boolean = true ) {
|
|
192
248
|
|
|
193
249
|
let props = this.m_props;
|
|
194
250
|
if (props.readOnly || this.hasClass("@disable") ) {
|
|
195
|
-
return;
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
let items = props.items;
|
|
255
|
+
if( isFunction( items ) ) {
|
|
256
|
+
const filter = filter_items ? (this.m_ui_input as Input).value : null;
|
|
257
|
+
items = items( filter );
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if( items.length==0 ) {
|
|
261
|
+
return null;
|
|
196
262
|
}
|
|
197
263
|
|
|
198
264
|
// need creation ?
|
|
@@ -205,10 +271,17 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
205
271
|
// prepare the combo listview
|
|
206
272
|
this.m_popup = new PopupListView({
|
|
207
273
|
cls: '@combo-popup',
|
|
208
|
-
items: props.items,
|
|
209
274
|
populate: props.populate,
|
|
210
275
|
renderItem: this.m_props.renderer,
|
|
211
|
-
selectionChange: (e) =>
|
|
276
|
+
selectionChange: (e) => {
|
|
277
|
+
|
|
278
|
+
this._selectItem(e);
|
|
279
|
+
|
|
280
|
+
if (!this.m_lockpop) {
|
|
281
|
+
this._hidePopup();
|
|
282
|
+
this.focus();
|
|
283
|
+
}
|
|
284
|
+
},
|
|
212
285
|
cancel: ( e ) => this.signal( 'cancel', e ),
|
|
213
286
|
style: {
|
|
214
287
|
fontFamily,
|
|
@@ -216,6 +289,8 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
216
289
|
}
|
|
217
290
|
});
|
|
218
291
|
}
|
|
292
|
+
|
|
293
|
+
this.m_popup.items = items;
|
|
219
294
|
|
|
220
295
|
let r1 = this.m_ui_button.getBoundingRect(),
|
|
221
296
|
r2 = this.m_ui_input.getBoundingRect();
|
|
@@ -225,10 +300,14 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
225
300
|
});
|
|
226
301
|
|
|
227
302
|
this.m_popup.displayAt(r2.left, r2.bottom);
|
|
303
|
+
this.m_popvis = true;
|
|
304
|
+
this.startTimer("focus-check", 100, true, () => this._checkFocus());
|
|
228
305
|
|
|
229
306
|
if( this.value!==undefined ) {
|
|
230
307
|
this.m_popup.selection = this.value;
|
|
231
308
|
}
|
|
309
|
+
|
|
310
|
+
return items;
|
|
232
311
|
}
|
|
233
312
|
|
|
234
313
|
/** @ignore
|
|
@@ -241,8 +320,10 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
241
320
|
return;
|
|
242
321
|
}
|
|
243
322
|
|
|
323
|
+
this.m_lockchg = true;
|
|
244
324
|
this._setInput( item, true );
|
|
245
|
-
|
|
325
|
+
this.m_lockchg = false;
|
|
326
|
+
|
|
246
327
|
this.m_selection = {
|
|
247
328
|
id: item.id,
|
|
248
329
|
text: item.text
|
|
@@ -250,9 +331,8 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
250
331
|
|
|
251
332
|
this.emit( 'selectionChange', EvSelectionChange( item ) );
|
|
252
333
|
this.emit( 'change', EvChange(item.id) );
|
|
253
|
-
this.m_ui_input.focus( );
|
|
254
|
-
|
|
255
|
-
this.m_popup.hide( );
|
|
334
|
+
//this.m_ui_input.focus( );
|
|
335
|
+
//this.m_popup.hide( );
|
|
256
336
|
}
|
|
257
337
|
|
|
258
338
|
/**
|
|
@@ -294,7 +374,15 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
294
374
|
}
|
|
295
375
|
|
|
296
376
|
public get valueText( ) {
|
|
297
|
-
|
|
377
|
+
if( this.m_selection ) {
|
|
378
|
+
return this.m_selection.text;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if( this.m_props.editable ) {
|
|
382
|
+
return (this.m_ui_input as Input).value;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return '';
|
|
298
386
|
}
|
|
299
387
|
|
|
300
388
|
/**
|
|
@@ -305,9 +393,9 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
305
393
|
let items = this.m_props.items;
|
|
306
394
|
|
|
307
395
|
if( isFunction(items) ) {
|
|
308
|
-
items = items( );
|
|
396
|
+
items = items( null );
|
|
309
397
|
}
|
|
310
|
-
|
|
398
|
+
|
|
311
399
|
const found = items.some( (v) => {
|
|
312
400
|
if (v.id === id) {
|
|
313
401
|
this._setInput( v );
|
|
@@ -326,6 +414,27 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
326
414
|
return this.m_ui_input instanceof Input ? this.m_ui_input : null;
|
|
327
415
|
}
|
|
328
416
|
|
|
417
|
+
_checkFocus() {
|
|
418
|
+
const focus = document.activeElement;
|
|
419
|
+
if (this.dom && this.dom.contains(focus) || focus==document.body ) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (this.m_popup && this.m_popup.dom && this.m_popup.dom.contains(focus)) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
this._hidePopup();
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
_hidePopup() {
|
|
431
|
+
if (this.m_popvis) {
|
|
432
|
+
this.m_popup.close();
|
|
433
|
+
this.m_popvis = false;
|
|
434
|
+
this.stopTimer("focus-check");
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
329
438
|
static storeProxy( props: ComboStoreProxyProps ): PopulateItems {
|
|
330
439
|
|
|
331
440
|
let view: DataView = props.store instanceof DataStore ? props.store.createView() : props.store;
|
|
@@ -343,20 +452,14 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
343
452
|
return result;
|
|
344
453
|
};
|
|
345
454
|
}
|
|
346
|
-
}
|
|
347
455
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
456
|
+
focus( ) {
|
|
457
|
+
if( this.m_props.editable ) {
|
|
458
|
+
this.m_ui_input.focus( );
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
super.focus( );
|
|
462
|
+
}
|
|
463
|
+
}
|
|
355
464
|
}
|
|
356
465
|
|
|
357
|
-
*/
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
package/lib/src/label.ts
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
**/
|
|
29
29
|
|
|
30
30
|
import { Component, CProps } from './component'
|
|
31
|
-
import { HtmlString } from './tools'
|
|
31
|
+
import { escapeHtml, HtmlString } from './tools'
|
|
32
32
|
import { Icon, IconID } from './icon'
|
|
33
33
|
|
|
34
34
|
// ============================================================================
|
|
@@ -69,7 +69,7 @@ export class Label extends Component<LabelProps>
|
|
|
69
69
|
|
|
70
70
|
let text: any = this.m_props.text;
|
|
71
71
|
if( this.m_props.multiline && !(text instanceof HtmlString) ) {
|
|
72
|
-
text = new HtmlString( (text
|
|
72
|
+
text = new HtmlString( escapeHtml(text,true) );
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
if( !props.icon ) {
|
|
@@ -102,7 +102,7 @@ export class Label extends Component<LabelProps>
|
|
|
102
102
|
|
|
103
103
|
let text: any = this.m_props.text;
|
|
104
104
|
if( this.m_props.multiline && !(text instanceof HtmlString) ) {
|
|
105
|
-
text = new HtmlString(
|
|
105
|
+
text = new HtmlString(escapeHtml(text,true) );
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
if( this.dom ) {
|
package/lib/src/listview.ts
CHANGED
|
@@ -62,7 +62,7 @@ export interface RenderListItem {
|
|
|
62
62
|
* callback to fill the list
|
|
63
63
|
*/
|
|
64
64
|
export interface PopulateItems {
|
|
65
|
-
(): ListViewItem[];
|
|
65
|
+
( filter: string ): ListViewItem[];
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/**
|
|
@@ -137,7 +137,7 @@ export class ListView extends VLayout<ListViewProps,ListViewEventMap> {
|
|
|
137
137
|
this._buildItems();
|
|
138
138
|
}
|
|
139
139
|
else if( this.m_props.populate ) {
|
|
140
|
-
this.items = this.m_props.populate( );
|
|
140
|
+
this.items = this.m_props.populate( null );
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
|
|
@@ -449,6 +449,9 @@ export class ListView extends VLayout<ListViewProps,ListViewEventMap> {
|
|
|
449
449
|
/** @ignore */
|
|
450
450
|
private _handleClick(e: MouseEvent) {
|
|
451
451
|
|
|
452
|
+
e.stopImmediatePropagation();
|
|
453
|
+
e.preventDefault( );
|
|
454
|
+
|
|
452
455
|
let dom = e.target as HTMLElement,
|
|
453
456
|
self = this.dom,
|
|
454
457
|
list_items = this.m_props.items as ListViewItem[]; // already created by build
|
package/lib/src/messagebox.ts
CHANGED
|
@@ -105,6 +105,27 @@ export class MessageBox extends Dialog<MessageBoxProps>
|
|
|
105
105
|
return msg;
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
+
static async showAsync( props: string | HtmlString | MessageBoxProps): Promise<string> {
|
|
109
|
+
return new Promise( (resolve, reject ) => {
|
|
110
|
+
|
|
111
|
+
let _props: MessageBoxProps;
|
|
112
|
+
|
|
113
|
+
const cb = ( btn: string ) => {
|
|
114
|
+
resolve( btn );
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (isString(props) || isHtmlString(props)) {
|
|
118
|
+
_props = { message: props, click: cb };
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
_props = { ...props, click: cb };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const msg = new MessageBox(_props);
|
|
125
|
+
msg.show();
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
108
129
|
/**
|
|
109
130
|
* display an alert message
|
|
110
131
|
*/
|
package/lib/src/tools.ts
CHANGED
|
@@ -346,7 +346,7 @@ export function sprintf(format: string, ...args) {
|
|
|
346
346
|
*/
|
|
347
347
|
export function escapeHtml(unsafe: string, nl_br = false): string {
|
|
348
348
|
if (!unsafe || unsafe.length == 0) {
|
|
349
|
-
return
|
|
349
|
+
return "";
|
|
350
350
|
}
|
|
351
351
|
|
|
352
352
|
let result = unsafe.replace(/[<>\&\"\']/g, function (c) {
|
package/lib/src/version.ts
CHANGED
package/lib/types/combobox.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ import { Component, CProps, ContainerEventMap } from './component';
|
|
|
33
33
|
import { EvChange, EvSelectionChange, EventCallback } from './x4events';
|
|
34
34
|
import { Input } from './input';
|
|
35
35
|
import { HLayout } from './layout';
|
|
36
|
-
import { ListViewItem,
|
|
36
|
+
import { ListViewItem, EvCancel, PopulateItems } from './listview';
|
|
37
37
|
import { DataStore, DataView, Record } from './datastore';
|
|
38
38
|
import { HtmlString } from './tools';
|
|
39
39
|
export interface ComboStoreProxyProps {
|
|
@@ -55,11 +55,11 @@ export interface ComboBoxProps extends CProps<ComboBoxEventMap> {
|
|
|
55
55
|
label?: string;
|
|
56
56
|
labelWidth?: number;
|
|
57
57
|
labelAlign?: 'left' | 'right';
|
|
58
|
-
items?: ListViewItem[];
|
|
59
|
-
populate?: PopulateItems;
|
|
58
|
+
items?: ListViewItem[] | PopulateItems;
|
|
60
59
|
value?: any;
|
|
61
60
|
renderer?: ComboItemRender;
|
|
62
61
|
selectionChange?: EventCallback<EvSelectionChange>;
|
|
62
|
+
editable?: boolean;
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
65
|
* @review use textedit
|
|
@@ -68,9 +68,12 @@ export declare class ComboBox extends HLayout<ComboBoxProps, ComboBoxEventMap> {
|
|
|
68
68
|
private m_ui_input;
|
|
69
69
|
private m_ui_button;
|
|
70
70
|
private m_popup;
|
|
71
|
+
private m_lockpop;
|
|
72
|
+
private m_lockchg;
|
|
73
|
+
private m_popvis;
|
|
71
74
|
private m_selection;
|
|
72
|
-
private m_defer_sel;
|
|
73
75
|
constructor(props: ComboBoxProps);
|
|
76
|
+
_onKey(e: any): void;
|
|
74
77
|
set items(items: ListViewItem[]);
|
|
75
78
|
/** @ignore */
|
|
76
79
|
render(props: ComboBoxProps): void;
|
|
@@ -78,7 +81,7 @@ export declare class ComboBox extends HLayout<ComboBoxProps, ComboBoxEventMap> {
|
|
|
78
81
|
/**
|
|
79
82
|
* display the popup
|
|
80
83
|
*/
|
|
81
|
-
showPopup():
|
|
84
|
+
showPopup(filter_items?: boolean): ListViewItem[];
|
|
82
85
|
/** @ignore
|
|
83
86
|
*/
|
|
84
87
|
private _selectItem;
|
|
@@ -96,6 +99,9 @@ export declare class ComboBox extends HLayout<ComboBoxProps, ComboBoxEventMap> {
|
|
|
96
99
|
*/
|
|
97
100
|
set value(id: any);
|
|
98
101
|
get input(): Input;
|
|
102
|
+
_checkFocus(): void;
|
|
103
|
+
_hidePopup(): void;
|
|
99
104
|
static storeProxy(props: ComboStoreProxyProps): PopulateItems;
|
|
105
|
+
focus(): void;
|
|
100
106
|
}
|
|
101
107
|
export {};
|
package/lib/types/listview.d.ts
CHANGED
|
@@ -46,6 +46,7 @@ export declare class MessageBox extends Dialog<MessageBoxProps> {
|
|
|
46
46
|
* display a messagebox
|
|
47
47
|
*/
|
|
48
48
|
static show(props: string | HtmlString | MessageBoxProps): MessageBox;
|
|
49
|
+
static showAsync(props: string | HtmlString | MessageBoxProps): Promise<string>;
|
|
49
50
|
/**
|
|
50
51
|
* display an alert message
|
|
51
52
|
*/
|
package/lib/types/version.d.ts
CHANGED