x4js 1.5.27 → 1.5.31
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 +7 -7
- package/lib/cjs/index.js.map +4 -4
- package/lib/esm/index.mjs +3295 -3186
- package/lib/esm/index.mjs.map +4 -4
- package/lib/src/autocomplete.ts +22 -5
- package/lib/src/combobox.ts +42 -2
- package/lib/src/component.ts +14 -0
- package/lib/src/datastore.ts +6 -2
- 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 +44 -4
- package/lib/src/router.ts +7 -3
- package/lib/src/textedit.ts +15 -26
- package/lib/src/version.ts +1 -1
- package/lib/src/x4.less +3 -5
- package/lib/styles/x4.css +2 -2
- package/lib/styles/x4.less +3 -5
- package/lib/types/autocomplete.d.ts +5 -1
- package/lib/types/combobox.d.ts +7 -3
- package/lib/types/component.d.ts +1 -0
- package/lib/types/form.d.ts +12 -3
- package/lib/types/image.d.ts +3 -2
- package/lib/types/input.d.ts +6 -0
- package/lib/types/router.d.ts +1 -1
- package/lib/types/textedit.d.ts +5 -2
- package/lib/types/version.d.ts +1 -1
- package/package.json +1 -1
package/lib/src/autocomplete.ts
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
28
|
**/
|
|
29
29
|
|
|
30
|
-
import { ListViewItem, PopupListView } from "./listview";
|
|
30
|
+
import { RenderListItem, ListViewItem, PopupListView } from "./listview";
|
|
31
31
|
import { TextEdit, TextEditProps } from './textedit';
|
|
32
32
|
|
|
33
33
|
/**
|
|
@@ -40,6 +40,7 @@ interface AutoCompleteProps extends TextEditProps {
|
|
|
40
40
|
|
|
41
41
|
// a way to change the real value vs displayed value in the popup list
|
|
42
42
|
selectValue?: ( text: string ) => string;
|
|
43
|
+
renderItem?: RenderListItem
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
/**
|
|
@@ -102,7 +103,7 @@ export class AutoComplete extends TextEdit<AutoCompleteProps> {
|
|
|
102
103
|
return;
|
|
103
104
|
}
|
|
104
105
|
|
|
105
|
-
this.
|
|
106
|
+
this._showPopup( items );
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
componentDisposed( ) {
|
|
@@ -113,11 +114,20 @@ export class AutoComplete extends TextEdit<AutoCompleteProps> {
|
|
|
113
114
|
super.componentDisposed( );
|
|
114
115
|
}
|
|
115
116
|
|
|
117
|
+
showPopup( show = true ) {
|
|
118
|
+
if( show ) {
|
|
119
|
+
this._onChange( );
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
this._hidePopup( );
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
116
126
|
/**
|
|
117
127
|
* display the popup
|
|
118
128
|
*/
|
|
119
129
|
|
|
120
|
-
|
|
130
|
+
private _showPopup( items: string[] ) {
|
|
121
131
|
|
|
122
132
|
let props = this.m_props;
|
|
123
133
|
if (props.readOnly || this.hasClass("@disable") ) {
|
|
@@ -152,11 +162,14 @@ export class AutoComplete extends TextEdit<AutoCompleteProps> {
|
|
|
152
162
|
style: {
|
|
153
163
|
fontFamily,
|
|
154
164
|
fontSize
|
|
155
|
-
}
|
|
165
|
+
},
|
|
166
|
+
renderItem: props.renderItem,
|
|
156
167
|
});
|
|
157
168
|
}
|
|
158
169
|
|
|
159
|
-
|
|
170
|
+
if( items ) {
|
|
171
|
+
this.m_popup.items = items.map( c => ({ id: c, text: c }) );
|
|
172
|
+
}
|
|
160
173
|
|
|
161
174
|
let r1 = this.m_ui_input.getBoundingRect();
|
|
162
175
|
this.m_popup.setStyle({
|
|
@@ -212,4 +225,8 @@ export class AutoComplete extends TextEdit<AutoCompleteProps> {
|
|
|
212
225
|
|
|
213
226
|
this.m_needval = true;
|
|
214
227
|
}
|
|
228
|
+
|
|
229
|
+
isPopupVisible( ) {
|
|
230
|
+
return this.m_popvis;
|
|
231
|
+
}
|
|
215
232
|
}
|
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
|
|
@@ -81,13 +86,21 @@ export interface ComboBoxProps extends CProps<ComboBoxEventMap> {
|
|
|
81
86
|
editable?: boolean;
|
|
82
87
|
}
|
|
83
88
|
|
|
89
|
+
abstract class InputLike extends Component {
|
|
90
|
+
abstract setValue( text: string );
|
|
91
|
+
abstract getValue( ): string;
|
|
92
|
+
abstract showError( text: string );
|
|
93
|
+
abstract clearError( );
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
84
97
|
/**
|
|
85
98
|
* @review use textedit
|
|
86
99
|
*/
|
|
87
100
|
|
|
88
101
|
export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
89
102
|
|
|
90
|
-
private m_ui_input: Input |
|
|
103
|
+
private m_ui_input: Input | InputLike;
|
|
91
104
|
private m_ui_button: Button;
|
|
92
105
|
private m_popup: PopupListView;
|
|
93
106
|
private m_lockpop: boolean;
|
|
@@ -147,6 +160,8 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
147
160
|
|
|
148
161
|
if( !props.renderer ) {
|
|
149
162
|
|
|
163
|
+
this.setClass('@required', props.required);
|
|
164
|
+
|
|
150
165
|
const input = new Input( {
|
|
151
166
|
flex : 1,
|
|
152
167
|
readOnly : this.m_props.editable ? false : true,
|
|
@@ -158,6 +173,7 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
158
173
|
},
|
|
159
174
|
dom_events: {
|
|
160
175
|
focus: () => {
|
|
176
|
+
this.clearError();
|
|
161
177
|
if( this.m_props.editable && input.value.length==0 ) {
|
|
162
178
|
this.showPopup( );
|
|
163
179
|
}
|
|
@@ -220,7 +236,10 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
220
236
|
this.showPopup( false )
|
|
221
237
|
},
|
|
222
238
|
dom_events: {
|
|
223
|
-
focus: () => {
|
|
239
|
+
focus: () => {
|
|
240
|
+
this.clearError();
|
|
241
|
+
this.dom.focus();
|
|
242
|
+
},
|
|
224
243
|
}
|
|
225
244
|
})
|
|
226
245
|
]
|
|
@@ -310,6 +329,27 @@ export class ComboBox extends HLayout<ComboBoxProps,ComboBoxEventMap> {
|
|
|
310
329
|
return items;
|
|
311
330
|
}
|
|
312
331
|
|
|
332
|
+
/**
|
|
333
|
+
*
|
|
334
|
+
*/
|
|
335
|
+
|
|
336
|
+
validate( ) {
|
|
337
|
+
if( this.m_props.required && !this.m_selection ) {
|
|
338
|
+
this.showError(_tr.global.required_field);
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
public showError(text: string) {
|
|
346
|
+
this.m_ui_input.showError( text );
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
public clearError() {
|
|
350
|
+
this.m_ui_input.clearError( );
|
|
351
|
+
}
|
|
352
|
+
|
|
313
353
|
/** @ignore
|
|
314
354
|
*/
|
|
315
355
|
|
package/lib/src/component.ts
CHANGED
|
@@ -279,6 +279,20 @@ export class Component<P extends CProps<CEventMap> = CProps<CEventMap>, E extend
|
|
|
279
279
|
}
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
+
removeChild( item: Component ) {
|
|
283
|
+
if( this.m_props.content ) {
|
|
284
|
+
if (!isArray(this.m_props.content)) {
|
|
285
|
+
this.m_props.content = [this.m_props.content];
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
this.m_props.content = this.m_props.content.filter( x => x!==item );
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if( this.dom && item.dom ) {
|
|
292
|
+
this.dom.removeChild( item.dom );
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
282
296
|
/**
|
|
283
297
|
*
|
|
284
298
|
*/
|
package/lib/src/datastore.ts
CHANGED
|
@@ -239,7 +239,7 @@ interface RecordConstructor {
|
|
|
239
239
|
*/
|
|
240
240
|
|
|
241
241
|
export function array( ctor: RecordConstructor, props?: MetaData ) {
|
|
242
|
-
return data.field( { ...props, type: 'array', model: new ctor() } )
|
|
242
|
+
return data.field( { ...props, type: 'array', model: ctor ? new ctor() : null } )
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
}
|
|
@@ -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
|
@@ -27,6 +27,8 @@
|
|
|
27
27
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
28
|
**/
|
|
29
29
|
|
|
30
|
+
import { x4document } from './x4dom'
|
|
31
|
+
import { Tooltip } from './tooltips';
|
|
30
32
|
import { Component, CProps, CEventMap, EvFocus } from './component'
|
|
31
33
|
//import { EvChange } from './x4_events';
|
|
32
34
|
|
|
@@ -67,10 +69,20 @@ export interface InputProps<P extends InputEventMap = InputEventMap> extends CPr
|
|
|
67
69
|
|
|
68
70
|
export class Input extends Component<InputProps,InputEventMap>
|
|
69
71
|
{
|
|
72
|
+
private m_error_tip: Tooltip;
|
|
73
|
+
|
|
70
74
|
constructor( props: InputProps ) {
|
|
71
75
|
super( props );
|
|
72
76
|
}
|
|
73
77
|
|
|
78
|
+
componentDisposed() {
|
|
79
|
+
if (this.m_error_tip) {
|
|
80
|
+
this.m_error_tip.dispose();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
super.componentDisposed();
|
|
84
|
+
}
|
|
85
|
+
|
|
74
86
|
/** @ignore */
|
|
75
87
|
render( props: InputProps ) {
|
|
76
88
|
|
|
@@ -105,6 +117,28 @@ export class Input extends Component<InputProps,InputEventMap>
|
|
|
105
117
|
}
|
|
106
118
|
}
|
|
107
119
|
|
|
120
|
+
public showError(text: string) {
|
|
121
|
+
|
|
122
|
+
if (!this.m_error_tip) {
|
|
123
|
+
this.m_error_tip = new Tooltip({ cls: 'error' });
|
|
124
|
+
x4document.body.appendChild(this.m_error_tip._build());
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let rc = this.getBoundingRect();
|
|
128
|
+
|
|
129
|
+
this.m_error_tip.text = text;
|
|
130
|
+
this.m_error_tip.displayAt(rc.right, rc.top-8, 'top right');
|
|
131
|
+
this.addClass('@error');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public clearError() {
|
|
135
|
+
|
|
136
|
+
if (this.m_error_tip) {
|
|
137
|
+
this.m_error_tip.hide();
|
|
138
|
+
this.removeClass('@error');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
108
142
|
public getType( ) {
|
|
109
143
|
return this.m_props.type;
|
|
110
144
|
}
|
|
@@ -114,7 +148,10 @@ export class Input extends Component<InputProps,InputEventMap>
|
|
|
114
148
|
*/
|
|
115
149
|
|
|
116
150
|
public get value( ) : string {
|
|
117
|
-
|
|
151
|
+
return this.getValue( );
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
public getValue( ): string {
|
|
118
155
|
if( this.dom ) {
|
|
119
156
|
this.m_props.value = (<HTMLInputElement>this.dom).value;
|
|
120
157
|
}
|
|
@@ -129,7 +166,7 @@ export class Input extends Component<InputProps,InputEventMap>
|
|
|
129
166
|
}
|
|
130
167
|
|
|
131
168
|
return this.m_props.value;
|
|
132
|
-
|
|
169
|
+
}
|
|
133
170
|
|
|
134
171
|
/**
|
|
135
172
|
* Change the editor value
|
|
@@ -137,7 +174,10 @@ export class Input extends Component<InputProps,InputEventMap>
|
|
|
137
174
|
*/
|
|
138
175
|
|
|
139
176
|
public set value( value: string ) {
|
|
140
|
-
|
|
177
|
+
this.setValue( value );
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public setValue( value: string ) {
|
|
141
181
|
this.m_props.value = value;
|
|
142
182
|
|
|
143
183
|
if( this.dom ) {
|
|
@@ -190,7 +230,7 @@ export class Input extends Component<InputProps,InputEventMap>
|
|
|
190
230
|
}
|
|
191
231
|
|
|
192
232
|
public setStoreValue( v: any ) {
|
|
193
|
-
|
|
233
|
+
this.clearError( );
|
|
194
234
|
if( this.m_props.value_hook ) {
|
|
195
235
|
return this.m_props.value_hook.set( v );
|
|
196
236
|
}
|
package/lib/src/router.ts
CHANGED
|
@@ -154,7 +154,7 @@ export class Router extends EventSource< RouterEventMap > {
|
|
|
154
154
|
return this.m_useHash ? '/'+x4document.location.hash.substring(1) : x4document.location.pathname;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
navigate( uri: string, notify = true ) {
|
|
157
|
+
navigate( uri: string, notify = true, replace = false ) {
|
|
158
158
|
|
|
159
159
|
if( !uri.startsWith('/') ) {
|
|
160
160
|
uri = '/'+uri;
|
|
@@ -170,11 +170,15 @@ export class Router extends EventSource< RouterEventMap > {
|
|
|
170
170
|
}
|
|
171
171
|
|
|
172
172
|
if( this.m_useHash ) {
|
|
173
|
-
while( uri.
|
|
173
|
+
while( uri.at(0)=='/' ) {
|
|
174
174
|
uri = uri.substring( 1 );
|
|
175
175
|
}
|
|
176
176
|
|
|
177
|
-
|
|
177
|
+
uri = '#'+uri;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if( replace ) {
|
|
181
|
+
window.history.replaceState({}, '', uri );
|
|
178
182
|
}
|
|
179
183
|
else {
|
|
180
184
|
window.history.pushState({}, '', uri );
|
package/lib/src/textedit.ts
CHANGED
|
@@ -93,8 +93,7 @@ export class TextEdit<T extends TextEditProps = TextEditProps, E extends TextEdi
|
|
|
93
93
|
|
|
94
94
|
private m_cal_popup: PopupCalendar;
|
|
95
95
|
protected m_ui_input: Input;
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
|
|
98
97
|
constructor(props: T) {
|
|
99
98
|
super(props);
|
|
100
99
|
this.addClass( '@hlayout' );
|
|
@@ -109,14 +108,6 @@ export class TextEdit<T extends TextEditProps = TextEditProps, E extends TextEdi
|
|
|
109
108
|
}
|
|
110
109
|
}
|
|
111
110
|
|
|
112
|
-
componentDisposed() {
|
|
113
|
-
if (this.m_error_tip) {
|
|
114
|
-
this.m_error_tip.dispose();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
super.componentDisposed();
|
|
118
|
-
}
|
|
119
|
-
|
|
120
111
|
focus() {
|
|
121
112
|
this.m_ui_input.focus();
|
|
122
113
|
}
|
|
@@ -309,28 +300,18 @@ export class TextEdit<T extends TextEditProps = TextEditProps, E extends TextEdi
|
|
|
309
300
|
}
|
|
310
301
|
|
|
311
302
|
public showError(text: string) {
|
|
312
|
-
|
|
313
|
-
if (!this.m_error_tip) {
|
|
314
|
-
this.m_error_tip = new Tooltip({ cls: 'error' });
|
|
315
|
-
x4document.body.appendChild(this.m_error_tip._build());
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
let rc = this.m_ui_input.getBoundingRect();
|
|
319
|
-
|
|
320
|
-
this.m_error_tip.text = text;
|
|
321
|
-
this.m_error_tip.displayAt(rc.right, rc.top, 'top left');
|
|
322
|
-
this.addClass('@error');
|
|
303
|
+
this.m_ui_input.showError( text );
|
|
323
304
|
}
|
|
324
305
|
|
|
325
306
|
public clearError() {
|
|
326
|
-
|
|
327
|
-
if (this.m_error_tip) {
|
|
328
|
-
this.m_error_tip.hide();
|
|
329
|
-
this.removeClass('@error');
|
|
330
|
-
}
|
|
307
|
+
this.m_ui_input.clearError( );
|
|
331
308
|
}
|
|
332
309
|
|
|
333
310
|
public get value(): string {
|
|
311
|
+
return this.getValue( );
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
public getValue( ) : string {
|
|
334
315
|
if (this.m_ui_input) {
|
|
335
316
|
return this.m_ui_input.value;
|
|
336
317
|
}
|
|
@@ -339,7 +320,15 @@ export class TextEdit<T extends TextEditProps = TextEditProps, E extends TextEdi
|
|
|
339
320
|
}
|
|
340
321
|
}
|
|
341
322
|
|
|
323
|
+
/**
|
|
324
|
+
*
|
|
325
|
+
*/
|
|
326
|
+
|
|
342
327
|
public set value(value: string) {
|
|
328
|
+
this.setValue( value );
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
public setValue( value: string ) {
|
|
343
332
|
if (this.m_ui_input) {
|
|
344
333
|
this.m_ui_input.value = value;
|
|
345
334
|
}
|