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.
@@ -35,7 +35,11 @@ import { TextEdit, TextEditProps } from './textedit';
35
35
  */
36
36
 
37
37
  interface AutoCompleteProps extends TextEditProps {
38
- enumValues: ( filter: string ) => string[];
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
- const items = this.m_props.enumValues( this.value );
92
- this.showPopup( items );
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
- showPopup( items: string[] ) {
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
- this.value = (e.selection as ListViewItem).id
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
- this.m_popup.items = items.map( c => ({ id: c, text: c }) );
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({
@@ -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: () => { this.dom.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
 
@@ -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 | ComponentOrString[] ) {
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 );
@@ -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>=0 && name<fields.length ) {
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 { EventCallback } from './x4events'
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?: EventCallback<EvBtnClick>; // shortcut for events: { 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
- let input = Component.getElement(inputs[i], TextEdit);
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.substr(0,5)=='data:';
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
- const img = new Component( {
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
- this.setContent( img );
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
- (<HTMLElement>this.dom.firstChild).setAttribute( 'src', src );
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
- (<HTMLElement>this.dom.firstChild).setAttribute( 'src', this.m_props.src );
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
- (<HTMLElement>this.dom.firstChild).setAttribute( 'src', this.m_props.src );
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( { dom: this.dom, src: this.m_lazysrc } );
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( ( el ) => {
186
+ Image.lazy_images_waiting.forEach( ( lazy ) => {
167
187
 
168
- let dom = el.dom,
169
- src = el.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( el );
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: 'new-password', // chrome ignore 'off' but not something else than 'on'
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,
@@ -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 left');
321
+ this.m_error_tip.displayAt(rc.right, rc.top-8, 'top right');
322
322
  this.addClass('@error');
323
323
  }
324
324
 
@@ -27,4 +27,4 @@
27
27
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
28
  **/
29
29
 
30
- export const x4js_version = "1.5.26";
30
+ export const x4js_version = "1.5.29";
@@ -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
- showPopup(items: string[]): void;
53
+ private _showPopup;
52
54
  protected _validate(value: string): boolean;
53
55
  validate(): boolean;
54
56
  private _checkFocus;
@@ -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;
@@ -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 | ComponentOrString[]);
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
@@ -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
@@ -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 { EventCallback } from './x4events';
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?: EventCallback<EvBtnClick>;
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