x4js 1.5.26 → 1.5.29
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/cjs/index.js +8 -8
- package/lib/cjs/index.js.map +4 -4
- package/lib/esm/index.mjs +3136 -3045
- package/lib/esm/index.mjs.map +4 -4
- package/lib/src/autocomplete.ts +31 -7
- package/lib/src/combobox.ts +51 -1
- package/lib/src/component.ts +4 -2
- package/lib/src/datastore.ts +7 -3
- package/lib/src/form.ts +43 -5
- package/lib/src/icon.ts +8 -0
- package/lib/src/image.ts +38 -17
- package/lib/src/input.ts +1 -1
- package/lib/src/textedit.ts +1 -1
- package/lib/src/version.ts +1 -1
- package/lib/types/autocomplete.d.ts +4 -2
- package/lib/types/combobox.d.ts +8 -3
- package/lib/types/component.d.ts +2 -1
- package/lib/types/datastore.d.ts +2 -2
- package/lib/types/form.d.ts +12 -3
- package/lib/types/image.d.ts +3 -2
- package/lib/types/version.d.ts +1 -1
- package/package.json +1 -1
package/lib/src/autocomplete.ts
CHANGED
|
@@ -35,7 +35,11 @@ import { TextEdit, TextEditProps } from './textedit';
|
|
|
35
35
|
*/
|
|
36
36
|
|
|
37
37
|
interface AutoCompleteProps extends TextEditProps {
|
|
38
|
-
|
|
38
|
+
// return an array of values to display in the popup list
|
|
39
|
+
enumValues: ( filter: string ) => string[] | Promise<string[]>;
|
|
40
|
+
|
|
41
|
+
// a way to change the real value vs displayed value in the popup list
|
|
42
|
+
selectValue?: ( text: string ) => string;
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
/**
|
|
@@ -87,9 +91,18 @@ export class AutoComplete extends TextEdit<AutoCompleteProps> {
|
|
|
87
91
|
}
|
|
88
92
|
}
|
|
89
93
|
|
|
90
|
-
private _onChange( ) {
|
|
91
|
-
|
|
92
|
-
|
|
94
|
+
private async _onChange( ) {
|
|
95
|
+
let items = this.m_props.enumValues( this.value );
|
|
96
|
+
if( items instanceof Promise ) {
|
|
97
|
+
items = await items;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if( items.length==0 ) {
|
|
101
|
+
this._hidePopup( );
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
this._showPopup( items );
|
|
93
106
|
}
|
|
94
107
|
|
|
95
108
|
componentDisposed( ) {
|
|
@@ -100,11 +113,15 @@ export class AutoComplete extends TextEdit<AutoCompleteProps> {
|
|
|
100
113
|
super.componentDisposed( );
|
|
101
114
|
}
|
|
102
115
|
|
|
116
|
+
showPopup( ) {
|
|
117
|
+
this._onChange( );
|
|
118
|
+
}
|
|
119
|
+
|
|
103
120
|
/**
|
|
104
121
|
* display the popup
|
|
105
122
|
*/
|
|
106
123
|
|
|
107
|
-
|
|
124
|
+
private _showPopup( items: string[] ) {
|
|
108
125
|
|
|
109
126
|
let props = this.m_props;
|
|
110
127
|
if (props.readOnly || this.hasClass("@disable") ) {
|
|
@@ -125,7 +142,12 @@ export class AutoComplete extends TextEdit<AutoCompleteProps> {
|
|
|
125
142
|
tabindex: 0
|
|
126
143
|
},
|
|
127
144
|
selectionChange: (e) => {
|
|
128
|
-
|
|
145
|
+
let value = (e.selection as ListViewItem).id
|
|
146
|
+
if( this.m_props.selectValue ) {
|
|
147
|
+
value = this.m_props.selectValue( value );
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
this.value = value;
|
|
129
151
|
if( !this.m_lockpop ) {
|
|
130
152
|
this._hidePopup( );
|
|
131
153
|
this.focus( );
|
|
@@ -138,7 +160,9 @@ export class AutoComplete extends TextEdit<AutoCompleteProps> {
|
|
|
138
160
|
});
|
|
139
161
|
}
|
|
140
162
|
|
|
141
|
-
|
|
163
|
+
if( items ) {
|
|
164
|
+
this.m_popup.items = items.map( c => ({ id: c, text: c }) );
|
|
165
|
+
}
|
|
142
166
|
|
|
143
167
|
let r1 = this.m_ui_input.getBoundingRect();
|
|
144
168
|
this.m_popup.setStyle({
|
package/lib/src/combobox.ts
CHANGED
|
@@ -31,6 +31,8 @@
|
|
|
31
31
|
* TODO: replace custom combo list by listview or gridview
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
|
+
import { x4document } from './x4dom'
|
|
35
|
+
|
|
34
36
|
import { Component, CProps, ContainerEventMap } from './component'
|
|
35
37
|
import { EvChange, EvSelectionChange, EventCallback } from './x4events'
|
|
36
38
|
|
|
@@ -41,6 +43,8 @@ import { HLayout } from './layout'
|
|
|
41
43
|
import { PopupListView, ListViewItem, EvCancel, PopulateItems } from './listview';
|
|
42
44
|
import { DataStore, DataView, Record } from './datastore'
|
|
43
45
|
import { isFunction, HtmlString } from './tools'
|
|
46
|
+
import { Tooltip } from './tooltips'
|
|
47
|
+
import { _tr } from './i18n'
|
|
44
48
|
|
|
45
49
|
export interface ComboStoreProxyProps {
|
|
46
50
|
store: DataView | DataStore;
|
|
@@ -65,6 +69,7 @@ export interface ComboBoxProps extends CProps<ComboBoxEventMap> {
|
|
|
65
69
|
tabIndex?: number | boolean;
|
|
66
70
|
name?: string;
|
|
67
71
|
readOnly?: boolean;
|
|
72
|
+
required?: true;
|
|
68
73
|
|
|
69
74
|
label?: string;
|
|
70
75
|
labelWidth?: number; // < 0 for flex
|
|
@@ -94,6 +99,7 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
94
99
|
private m_lockchg: boolean;
|
|
95
100
|
private m_popvis: boolean;
|
|
96
101
|
private m_selection: ListViewItem;
|
|
102
|
+
private m_error_tip: Tooltip;
|
|
97
103
|
|
|
98
104
|
constructor(props: ComboBoxProps) {
|
|
99
105
|
super(props);
|
|
@@ -147,6 +153,8 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
147
153
|
|
|
148
154
|
if( !props.renderer ) {
|
|
149
155
|
|
|
156
|
+
this.setClass('@required', props.required);
|
|
157
|
+
|
|
150
158
|
const input = new Input( {
|
|
151
159
|
flex : 1,
|
|
152
160
|
readOnly : this.m_props.editable ? false : true,
|
|
@@ -158,6 +166,7 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
158
166
|
},
|
|
159
167
|
dom_events: {
|
|
160
168
|
focus: () => {
|
|
169
|
+
this.clearError();
|
|
161
170
|
if( this.m_props.editable && input.value.length==0 ) {
|
|
162
171
|
this.showPopup( );
|
|
163
172
|
}
|
|
@@ -220,7 +229,10 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
220
229
|
this.showPopup( false )
|
|
221
230
|
},
|
|
222
231
|
dom_events: {
|
|
223
|
-
focus: () => {
|
|
232
|
+
focus: () => {
|
|
233
|
+
this.clearError();
|
|
234
|
+
this.dom.focus();
|
|
235
|
+
},
|
|
224
236
|
}
|
|
225
237
|
})
|
|
226
238
|
]
|
|
@@ -233,6 +245,10 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
233
245
|
}
|
|
234
246
|
|
|
235
247
|
componentDisposed( ) {
|
|
248
|
+
if (this.m_error_tip) {
|
|
249
|
+
this.m_error_tip.dispose();
|
|
250
|
+
}
|
|
251
|
+
|
|
236
252
|
if( this.m_popup ) {
|
|
237
253
|
this.m_popup.close( );
|
|
238
254
|
}
|
|
@@ -310,6 +326,40 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
310
326
|
return items;
|
|
311
327
|
}
|
|
312
328
|
|
|
329
|
+
/**
|
|
330
|
+
*
|
|
331
|
+
*/
|
|
332
|
+
|
|
333
|
+
validate( ) {
|
|
334
|
+
if( this.m_props.required && !this.m_selection ) {
|
|
335
|
+
this.showError(_tr.global.required_field);
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
public showError(text: string) {
|
|
343
|
+
|
|
344
|
+
if (!this.m_error_tip) {
|
|
345
|
+
this.m_error_tip = new Tooltip({ cls: 'error' });
|
|
346
|
+
x4document.body.appendChild(this.m_error_tip._build());
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
let rc = this.m_ui_input.getBoundingRect();
|
|
350
|
+
this.m_error_tip.text = text;
|
|
351
|
+
this.m_error_tip.displayAt(rc.right, rc.top-8, 'top right');
|
|
352
|
+
|
|
353
|
+
this.addClass('@error');
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
public clearError() {
|
|
357
|
+
if (this.m_error_tip) {
|
|
358
|
+
this.m_error_tip.hide();
|
|
359
|
+
this.removeClass('@error');
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
313
363
|
/** @ignore
|
|
314
364
|
*/
|
|
315
365
|
|
package/lib/src/component.ts
CHANGED
|
@@ -2206,9 +2206,11 @@ export class Container<P extends ContainerProps = ContainerProps, E extends Cont
|
|
|
2206
2206
|
|
|
2207
2207
|
private m_shortcuts: Shortcut[];
|
|
2208
2208
|
|
|
2209
|
-
constructor( props: P
|
|
2209
|
+
constructor( props: P );
|
|
2210
|
+
constructor( items: ComponentOrString[], cls?: string );
|
|
2211
|
+
constructor( props: P | ComponentOrString[], cls?: string ) {
|
|
2210
2212
|
if( isArray(props) ) {
|
|
2211
|
-
super( {content: props} as P );
|
|
2213
|
+
super( {content: props,cls} as P );
|
|
2212
2214
|
}
|
|
2213
2215
|
else {
|
|
2214
2216
|
super( props );
|
package/lib/src/datastore.ts
CHANGED
|
@@ -38,12 +38,12 @@ export type CalcCallback = () => string;
|
|
|
38
38
|
export type FieldType = 'string' | 'int' | 'float' | 'date' | 'bool' | 'array' | 'object' | 'any' | 'calc';
|
|
39
39
|
export type DataIndex = Uint32Array;
|
|
40
40
|
|
|
41
|
-
interface EvDataChange extends BasicEvent {
|
|
41
|
+
export interface EvDataChange extends BasicEvent {
|
|
42
42
|
type: string;
|
|
43
43
|
id: any;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
function EvDataChange( type: 'create' | 'update' | 'delete' | 'data' | 'change', id?: any ) {
|
|
46
|
+
export function EvDataChange( type: 'create' | 'update' | 'delete' | 'data' | 'change', id?: any ) {
|
|
47
47
|
return BasicEvent<EvDataChange>( { type, id } );
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -433,7 +433,11 @@ export class Record {
|
|
|
433
433
|
return undefined;
|
|
434
434
|
}
|
|
435
435
|
}
|
|
436
|
-
else if( name
|
|
436
|
+
else if( name<fields.length ) {
|
|
437
|
+
if( name<0 ) {
|
|
438
|
+
return undefined
|
|
439
|
+
}
|
|
440
|
+
|
|
437
441
|
idx = name;
|
|
438
442
|
}
|
|
439
443
|
else {
|
package/lib/src/form.ts
CHANGED
|
@@ -27,17 +27,23 @@
|
|
|
27
27
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
28
|
**/
|
|
29
29
|
|
|
30
|
-
import { Component, Container, CProps, ContainerEventMap, ComponentContent, flyWrap } from './component'
|
|
30
|
+
import { Component, Container, CProps, ContainerEventMap, ComponentContent, flyWrap, EventHandler } from './component'
|
|
31
31
|
import { HLayout, VLayout } from './layout'
|
|
32
32
|
import { Button } from './button'
|
|
33
33
|
import { Input } from './input'
|
|
34
34
|
import { TextEdit } from './textedit'
|
|
35
35
|
import { ajaxRequest, RequestProps } from './request'
|
|
36
|
-
import {
|
|
36
|
+
import { BasicEvent } from './x4events'
|
|
37
37
|
import { EvBtnClick } from './dialog'
|
|
38
|
+
import { ComboBox } from './combobox'
|
|
38
39
|
|
|
39
40
|
import { _tr } from './i18n'
|
|
40
41
|
|
|
42
|
+
|
|
43
|
+
export interface EvDirty extends BasicEvent {
|
|
44
|
+
dirty: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
41
47
|
// ============================================================================
|
|
42
48
|
// [FORM]
|
|
43
49
|
// ============================================================================
|
|
@@ -47,12 +53,14 @@ export type FormButtons = (FormBtn | Button | Component)[];
|
|
|
47
53
|
|
|
48
54
|
export interface FormEventMap extends ContainerEventMap {
|
|
49
55
|
btnClick?: EvBtnClick;
|
|
56
|
+
dirty?: EvDirty;
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
export interface FormProps extends CProps<FormEventMap> {
|
|
53
60
|
disableSuggestions?: boolean;
|
|
54
61
|
buttons?: FormButtons;
|
|
55
|
-
btnClick?:
|
|
62
|
+
btnClick?: EventHandler<EvBtnClick>; // shortcut for events: { btnClick: ... }
|
|
63
|
+
dirty?: EventHandler<EvDirty>;
|
|
56
64
|
}
|
|
57
65
|
|
|
58
66
|
/**
|
|
@@ -79,7 +87,7 @@ export class Form<T extends FormProps = FormProps, E extends FormEventMap = Form
|
|
|
79
87
|
super(props);
|
|
80
88
|
|
|
81
89
|
this.setTag( props.disableSuggestions ? 'section' : 'form');
|
|
82
|
-
this.mapPropEvents(props, 'btnClick');
|
|
90
|
+
this.mapPropEvents(props, 'btnClick', 'dirty');
|
|
83
91
|
this.updateContent(content, props.buttons, height);
|
|
84
92
|
|
|
85
93
|
this.m_dirty = false;
|
|
@@ -221,10 +229,17 @@ export class Form<T extends FormProps = FormProps, E extends FormEventMap = Form
|
|
|
221
229
|
result = true;
|
|
222
230
|
|
|
223
231
|
for (let i = 0; i < inputs.length; i++) {
|
|
224
|
-
|
|
232
|
+
const input = Component.getElement(inputs[i], TextEdit);
|
|
225
233
|
if (input && !input.validate()) {
|
|
226
234
|
result = false;
|
|
227
235
|
}
|
|
236
|
+
else {
|
|
237
|
+
const combo = Component.getElement(inputs[i], ComboBox);
|
|
238
|
+
if( combo && !combo.validate() ) {
|
|
239
|
+
result = false;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
228
243
|
}
|
|
229
244
|
|
|
230
245
|
return result;
|
|
@@ -278,6 +293,28 @@ export class Form<T extends FormProps = FormProps, E extends FormEventMap = Form
|
|
|
278
293
|
this.setDirty(false);
|
|
279
294
|
}
|
|
280
295
|
|
|
296
|
+
/**
|
|
297
|
+
*
|
|
298
|
+
*/
|
|
299
|
+
|
|
300
|
+
public clearValues() {
|
|
301
|
+
|
|
302
|
+
let elements = this._getElements();
|
|
303
|
+
for (let e = 0; e < elements.length; e++) {
|
|
304
|
+
|
|
305
|
+
let input = <HTMLInputElement>elements[e];
|
|
306
|
+
|
|
307
|
+
let item = Component.getElement(input);
|
|
308
|
+
if (!item.hasAttribute("name")) {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
(<Input>item).setStoreValue( null );
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
this.setDirty(false);
|
|
316
|
+
}
|
|
317
|
+
|
|
281
318
|
|
|
282
319
|
/**
|
|
283
320
|
* values are not escaped
|
|
@@ -363,6 +400,7 @@ export class Form<T extends FormProps = FormProps, E extends FormEventMap = Form
|
|
|
363
400
|
|
|
364
401
|
setDirty(set = true) {
|
|
365
402
|
this.m_dirty = set;
|
|
403
|
+
this.emit( 'dirty', { dirty: set } );
|
|
366
404
|
}
|
|
367
405
|
|
|
368
406
|
/**
|
package/lib/src/icon.ts
CHANGED
|
@@ -58,12 +58,20 @@ interface LoadingEventMap extends EventMap {
|
|
|
58
58
|
|
|
59
59
|
function trimQuotes( str:string ): string {
|
|
60
60
|
const l = str.length;
|
|
61
|
+
|
|
62
|
+
//chrome
|
|
61
63
|
if( str[0]=='"' && str[l-1]=='"' ) {
|
|
62
64
|
str = str.substring( 1, l-1 )
|
|
63
65
|
str = str.replaceAll( '\\"', "'" );
|
|
64
66
|
return str;
|
|
65
67
|
}
|
|
66
68
|
|
|
69
|
+
//firefox
|
|
70
|
+
if( str[0]=="'" && str[l-1]=="'" ) {
|
|
71
|
+
str = str.substring( 1, l-1 )
|
|
72
|
+
return str;
|
|
73
|
+
}
|
|
74
|
+
|
|
67
75
|
return str;
|
|
68
76
|
}
|
|
69
77
|
|
package/lib/src/image.ts
CHANGED
|
@@ -28,25 +28,30 @@
|
|
|
28
28
|
**/
|
|
29
29
|
|
|
30
30
|
import { x4document } from './x4dom'
|
|
31
|
-
|
|
32
31
|
import { Component, CProps, html } from './component'
|
|
33
32
|
|
|
33
|
+
interface LazyLoad {
|
|
34
|
+
el: Component;
|
|
35
|
+
src: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
34
38
|
// ============================================================================
|
|
35
39
|
// [IMAGE]
|
|
36
40
|
// ============================================================================
|
|
37
41
|
|
|
38
|
-
interface ImageProps extends CProps
|
|
42
|
+
export interface ImageProps extends CProps
|
|
39
43
|
{
|
|
40
44
|
src: string;
|
|
41
45
|
alt?: string;
|
|
42
46
|
lazy?: boolean; // mark image as lazy loading
|
|
43
47
|
alignment?: 'fill' | 'contain' | 'cover' | 'scale-down' | 'none';
|
|
48
|
+
overlays?: Component[];
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
const emptyImageSrc = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
|
|
47
52
|
|
|
48
53
|
function _isStaticImage( src: string ) {
|
|
49
|
-
return src.
|
|
54
|
+
return src.substring(0,5)=='data:';
|
|
50
55
|
}
|
|
51
56
|
|
|
52
57
|
|
|
@@ -58,6 +63,7 @@ export class Image extends Component<ImageProps>
|
|
|
58
63
|
{
|
|
59
64
|
protected m_created: boolean;
|
|
60
65
|
protected m_lazysrc: string; // expected
|
|
66
|
+
private m_img: Component;
|
|
61
67
|
|
|
62
68
|
constructor(props: ImageProps) {
|
|
63
69
|
super(props);
|
|
@@ -83,7 +89,7 @@ export class Image extends Component<ImageProps>
|
|
|
83
89
|
render( ) {
|
|
84
90
|
let mp = this.m_props;
|
|
85
91
|
|
|
86
|
-
|
|
92
|
+
this.m_img = new Component( {
|
|
87
93
|
tag: 'img',
|
|
88
94
|
attrs: {
|
|
89
95
|
draggable: false,
|
|
@@ -95,7 +101,13 @@ export class Image extends Component<ImageProps>
|
|
|
95
101
|
}
|
|
96
102
|
});
|
|
97
103
|
|
|
98
|
-
|
|
104
|
+
if( mp.overlays ) {
|
|
105
|
+
mp.overlays.forEach( x => x.addClass('@fit') );
|
|
106
|
+
this.setContent( [this.m_img,...mp.overlays] );
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
this.setContent( this.m_img );
|
|
110
|
+
}
|
|
99
111
|
}
|
|
100
112
|
|
|
101
113
|
/**
|
|
@@ -107,14 +119,18 @@ export class Image extends Component<ImageProps>
|
|
|
107
119
|
|
|
108
120
|
if( !src ) {
|
|
109
121
|
src = emptyImageSrc;
|
|
122
|
+
this.addClass( 'empty' );
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
this.removeClass( 'empty' );
|
|
110
126
|
}
|
|
111
127
|
|
|
112
128
|
if( !this.m_props.lazy ) {
|
|
113
129
|
this.m_props.src = src;
|
|
114
130
|
this.m_lazysrc = src;
|
|
115
131
|
|
|
116
|
-
if( this.dom ) {
|
|
117
|
-
|
|
132
|
+
if( this.m_img.dom ) {
|
|
133
|
+
this.m_img.dom.setAttribute( 'src', src );
|
|
118
134
|
}
|
|
119
135
|
}
|
|
120
136
|
else if( force || this.m_lazysrc!=src ) {
|
|
@@ -123,15 +139,15 @@ export class Image extends Component<ImageProps>
|
|
|
123
139
|
this.m_props.src = src;
|
|
124
140
|
this.m_lazysrc = src;
|
|
125
141
|
|
|
126
|
-
if( this.dom ) {
|
|
127
|
-
|
|
142
|
+
if( this.m_img.dom ) {
|
|
143
|
+
this.m_img.dom.setAttribute( 'src', this.m_props.src );
|
|
128
144
|
}
|
|
129
145
|
}
|
|
130
146
|
else {
|
|
131
147
|
// clear current image while waiting
|
|
132
148
|
this.m_props.src = emptyImageSrc;
|
|
133
|
-
if( this.dom ) {
|
|
134
|
-
|
|
149
|
+
if( this.m_img.dom ) {
|
|
150
|
+
this.m_img.dom.setAttribute( 'src', this.m_props.src );
|
|
135
151
|
}
|
|
136
152
|
|
|
137
153
|
this.m_lazysrc = src;
|
|
@@ -148,14 +164,18 @@ export class Image extends Component<ImageProps>
|
|
|
148
164
|
|
|
149
165
|
if( this.m_lazysrc && !_isStaticImage(this.m_lazysrc) ) {
|
|
150
166
|
// we do not push Components in a static array...
|
|
151
|
-
Image.lazy_images_waiting.push( {
|
|
167
|
+
Image.lazy_images_waiting.push( {
|
|
168
|
+
el: this,
|
|
169
|
+
src: this.m_lazysrc
|
|
170
|
+
} );
|
|
171
|
+
|
|
152
172
|
if( Image.lazy_image_timer===undefined ) {
|
|
153
173
|
Image.lazy_image_timer = setInterval( Image.lazyWatch as TimerHandler, 10 );
|
|
154
174
|
}
|
|
155
175
|
}
|
|
156
176
|
}
|
|
157
177
|
|
|
158
|
-
private static lazy_images_waiting = [];
|
|
178
|
+
private static lazy_images_waiting: LazyLoad[] = [];
|
|
159
179
|
private static lazy_image_timer: number = undefined;
|
|
160
180
|
|
|
161
181
|
private static lazyWatch( ) {
|
|
@@ -163,10 +183,10 @@ export class Image extends Component<ImageProps>
|
|
|
163
183
|
let newList = [];
|
|
164
184
|
let done = 0;
|
|
165
185
|
|
|
166
|
-
Image.lazy_images_waiting.forEach( (
|
|
186
|
+
Image.lazy_images_waiting.forEach( ( lazy ) => {
|
|
167
187
|
|
|
168
|
-
let dom = el.dom,
|
|
169
|
-
src =
|
|
188
|
+
let dom = lazy.el.dom,
|
|
189
|
+
src = lazy.src;
|
|
170
190
|
|
|
171
191
|
// skip deleted elements
|
|
172
192
|
if( !dom || dom.offsetParent === null ) {
|
|
@@ -185,11 +205,12 @@ export class Image extends Component<ImageProps>
|
|
|
185
205
|
// ok, we load the image
|
|
186
206
|
let img = <HTMLElement>dom.firstChild;
|
|
187
207
|
img.setAttribute( 'src', src );
|
|
208
|
+
lazy.el.removeClass( 'empty' );
|
|
188
209
|
done++;
|
|
189
210
|
}
|
|
190
211
|
else {
|
|
191
212
|
// still not visible: may be next time
|
|
192
|
-
newList.push(
|
|
213
|
+
newList.push( lazy );
|
|
193
214
|
}
|
|
194
215
|
} );
|
|
195
216
|
|
package/lib/src/input.ts
CHANGED
|
@@ -84,7 +84,7 @@ export class Input extends Component<InputProps,InputEventMap>
|
|
|
84
84
|
placeholder: props.placeHolder,
|
|
85
85
|
autofocus: props.autoFocus,
|
|
86
86
|
readonly: props.readOnly,
|
|
87
|
-
autocomplete: '
|
|
87
|
+
autocomplete: 'off', // chrome ignore 'off' but not something else than 'on'
|
|
88
88
|
tabIndex: props.tabIndex,
|
|
89
89
|
spellcheck: props.spellcheck===false ? 'false' : undefined,
|
|
90
90
|
min: props.min,
|
package/lib/src/textedit.ts
CHANGED
|
@@ -318,7 +318,7 @@ export class TextEdit<T extends TextEditProps = TextEditProps, E extends TextEdi
|
|
|
318
318
|
let rc = this.m_ui_input.getBoundingRect();
|
|
319
319
|
|
|
320
320
|
this.m_error_tip.text = text;
|
|
321
|
-
this.m_error_tip.displayAt(rc.right, rc.top, 'top
|
|
321
|
+
this.m_error_tip.displayAt(rc.right, rc.top-8, 'top right');
|
|
322
322
|
this.addClass('@error');
|
|
323
323
|
}
|
|
324
324
|
|
package/lib/src/version.ts
CHANGED
|
@@ -31,7 +31,8 @@ import { TextEdit, TextEditProps } from './textedit';
|
|
|
31
31
|
*
|
|
32
32
|
*/
|
|
33
33
|
interface AutoCompleteProps extends TextEditProps {
|
|
34
|
-
enumValues: (filter: string) => string[]
|
|
34
|
+
enumValues: (filter: string) => string[] | Promise<string[]>;
|
|
35
|
+
selectValue?: (text: string) => string;
|
|
35
36
|
}
|
|
36
37
|
/**
|
|
37
38
|
*
|
|
@@ -45,10 +46,11 @@ export declare class AutoComplete extends TextEdit<AutoCompleteProps> {
|
|
|
45
46
|
_onKey(e: KeyboardEvent): void;
|
|
46
47
|
private _onChange;
|
|
47
48
|
componentDisposed(): void;
|
|
49
|
+
showPopup(): void;
|
|
48
50
|
/**
|
|
49
51
|
* display the popup
|
|
50
52
|
*/
|
|
51
|
-
|
|
53
|
+
private _showPopup;
|
|
52
54
|
protected _validate(value: string): boolean;
|
|
53
55
|
validate(): boolean;
|
|
54
56
|
private _checkFocus;
|
package/lib/types/combobox.d.ts
CHANGED
|
@@ -26,9 +26,6 @@
|
|
|
26
26
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
27
27
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
28
|
**/
|
|
29
|
-
/**
|
|
30
|
-
* TODO: replace custom combo list by listview or gridview
|
|
31
|
-
*/
|
|
32
29
|
import { Component, CProps, ContainerEventMap } from './component';
|
|
33
30
|
import { EvChange, EvSelectionChange, EventCallback } from './x4events';
|
|
34
31
|
import { Input } from './input';
|
|
@@ -52,6 +49,7 @@ export interface ComboBoxProps extends CProps<ComboBoxEventMap> {
|
|
|
52
49
|
tabIndex?: number | boolean;
|
|
53
50
|
name?: string;
|
|
54
51
|
readOnly?: boolean;
|
|
52
|
+
required?: true;
|
|
55
53
|
label?: string;
|
|
56
54
|
labelWidth?: number;
|
|
57
55
|
labelAlign?: 'left' | 'right';
|
|
@@ -72,6 +70,7 @@ export declare class ComboBox extends HLayout<ComboBoxProps, ComboBoxEventMap> {
|
|
|
72
70
|
private m_lockchg;
|
|
73
71
|
private m_popvis;
|
|
74
72
|
private m_selection;
|
|
73
|
+
private m_error_tip;
|
|
75
74
|
constructor(props: ComboBoxProps);
|
|
76
75
|
_onKey(e: any): void;
|
|
77
76
|
set items(items: ListViewItem[]);
|
|
@@ -82,6 +81,12 @@ export declare class ComboBox extends HLayout<ComboBoxProps, ComboBoxEventMap> {
|
|
|
82
81
|
* display the popup
|
|
83
82
|
*/
|
|
84
83
|
showPopup(filter_items?: boolean): ListViewItem[];
|
|
84
|
+
/**
|
|
85
|
+
*
|
|
86
|
+
*/
|
|
87
|
+
validate(): boolean;
|
|
88
|
+
showError(text: string): void;
|
|
89
|
+
clearError(): void;
|
|
85
90
|
/** @ignore
|
|
86
91
|
*/
|
|
87
92
|
private _selectItem;
|
package/lib/types/component.d.ts
CHANGED
|
@@ -584,7 +584,8 @@ export interface ContainerProps<E extends ContainerEventMap = ContainerEventMap>
|
|
|
584
584
|
*/
|
|
585
585
|
export declare class Container<P extends ContainerProps = ContainerProps, E extends ContainerEventMap = ContainerEventMap> extends Component<P, E> {
|
|
586
586
|
private m_shortcuts;
|
|
587
|
-
constructor(props: P
|
|
587
|
+
constructor(props: P);
|
|
588
|
+
constructor(items: ComponentOrString[], cls?: string);
|
|
588
589
|
/**
|
|
589
590
|
* add an application shortcut
|
|
590
591
|
* @param sequence key sequence Shift+Ctrl+Alt+K
|
package/lib/types/datastore.d.ts
CHANGED
|
@@ -32,11 +32,11 @@ export type ChangeCallback = (type: string, id?: any) => void;
|
|
|
32
32
|
export type CalcCallback = () => string;
|
|
33
33
|
export type FieldType = 'string' | 'int' | 'float' | 'date' | 'bool' | 'array' | 'object' | 'any' | 'calc';
|
|
34
34
|
export type DataIndex = Uint32Array;
|
|
35
|
-
interface EvDataChange extends BasicEvent {
|
|
35
|
+
export interface EvDataChange extends BasicEvent {
|
|
36
36
|
type: string;
|
|
37
37
|
id: any;
|
|
38
38
|
}
|
|
39
|
-
declare function EvDataChange(type: 'create' | 'update' | 'delete' | 'data' | 'change', id?: any): EvDataChange;
|
|
39
|
+
export declare function EvDataChange(type: 'create' | 'update' | 'delete' | 'data' | 'change', id?: any): EvDataChange;
|
|
40
40
|
/**
|
|
41
41
|
* fields definition
|
|
42
42
|
* field with index=0 is record id
|
package/lib/types/form.d.ts
CHANGED
|
@@ -26,21 +26,26 @@
|
|
|
26
26
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
27
27
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
28
|
**/
|
|
29
|
-
import { Component, Container, CProps, ContainerEventMap, ComponentContent } from './component';
|
|
29
|
+
import { Component, Container, CProps, ContainerEventMap, ComponentContent, EventHandler } from './component';
|
|
30
30
|
import { HLayout, VLayout } from './layout';
|
|
31
31
|
import { Button } from './button';
|
|
32
32
|
import { RequestProps } from './request';
|
|
33
|
-
import {
|
|
33
|
+
import { BasicEvent } from './x4events';
|
|
34
34
|
import { EvBtnClick } from './dialog';
|
|
35
|
+
export interface EvDirty extends BasicEvent {
|
|
36
|
+
dirty: boolean;
|
|
37
|
+
}
|
|
35
38
|
export type FormBtn = 'ok' | 'cancel' | 'ignore' | 'yes' | 'no' | 'close' | 'save' | 'dontsave';
|
|
36
39
|
export type FormButtons = (FormBtn | Button | Component)[];
|
|
37
40
|
export interface FormEventMap extends ContainerEventMap {
|
|
38
41
|
btnClick?: EvBtnClick;
|
|
42
|
+
dirty?: EvDirty;
|
|
39
43
|
}
|
|
40
44
|
export interface FormProps extends CProps<FormEventMap> {
|
|
41
45
|
disableSuggestions?: boolean;
|
|
42
46
|
buttons?: FormButtons;
|
|
43
|
-
btnClick?:
|
|
47
|
+
btnClick?: EventHandler<EvBtnClick>;
|
|
48
|
+
dirty?: EventHandler<EvDirty>;
|
|
44
49
|
}
|
|
45
50
|
/**
|
|
46
51
|
*
|
|
@@ -107,6 +112,10 @@ export declare class Form<T extends FormProps = FormProps, E extends FormEventMa
|
|
|
107
112
|
*
|
|
108
113
|
*/
|
|
109
114
|
setValues(values: any): void;
|
|
115
|
+
/**
|
|
116
|
+
*
|
|
117
|
+
*/
|
|
118
|
+
clearValues(): void;
|
|
110
119
|
/**
|
|
111
120
|
* values are not escaped
|
|
112
121
|
* checkbox set true when checked
|