x4js 1.4.43 → 1.4.46
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/action.d.ts +2 -2
- package/lib/action.js +2 -3
- package/lib/application.js +1 -2
- package/lib/button.js +4 -0
- package/lib/form.d.ts +2 -2
- package/lib/gridview.d.ts +4 -0
- package/lib/gridview.js +41 -15
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/listview.d.ts +2 -1
- package/lib/listview.js +7 -3
- package/lib/sidebarview.d.ts +2 -1
- package/lib/sidebarview.js +3 -1
- package/lib/svgcomponent.d.ts +19 -3
- package/lib/svgcomponent.js +37 -2
- package/lib/textedit.d.ts +3 -3
- package/lib/tools.d.ts +7 -0
- package/lib/tools.js +50 -2
- package/lib/treeview.js +6 -4
- package/lib/version.d.ts +1 -0
- package/lib/version.js +4 -0
- package/lib/x4.css +24 -15
- package/package.json +1 -1
- package/src/action.ts +2 -2
- package/src/application.ts +1 -3
- package/src/autocomplete.ts +196 -0
- package/src/button.ts +5 -1
- package/src/component.ts +1 -2
- package/src/form.ts +2 -2
- package/src/gridview.ts +48 -18
- package/src/index.ts +2 -0
- package/src/listview.ts +9 -3
- package/src/sidebarview.ts +5 -3
- package/src/svgcomponent.ts +55 -6
- package/src/textedit.ts +3 -3
- package/src/tools.ts +61 -1
- package/src/treeview.ts +7 -5
- package/src/version.ts +1 -0
- package/src/x4.less +28 -22
package/package.json
CHANGED
package/src/action.ts
CHANGED
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
28
|
**/
|
|
29
29
|
|
|
30
|
-
import { BasicEvent } from './x4events'
|
|
30
|
+
import { BasicEvent, EvChange } from './x4events'
|
|
31
31
|
import { BaseComponent, BaseComponentEventMap, BaseComponentProps } from './base_component'
|
|
32
32
|
import { IconID } from "./icon"
|
|
33
|
-
import {
|
|
33
|
+
import { EventHandler } from './component';
|
|
34
34
|
|
|
35
35
|
//TODO: implement all
|
|
36
36
|
|
package/src/application.ts
CHANGED
|
@@ -30,11 +30,9 @@
|
|
|
30
30
|
import { x4document } from './x4dom'
|
|
31
31
|
import { EvMessage } from './x4events'
|
|
32
32
|
import { BaseComponent, BaseComponentEventMap, BaseComponentProps } from './base_component'
|
|
33
|
-
import { Component } from './component'
|
|
33
|
+
import { Component, flyWrap } from './component'
|
|
34
34
|
import { Settings } from './settings'
|
|
35
|
-
import { deferCall } from './tools'
|
|
36
35
|
import { _tr } from './i18n'
|
|
37
|
-
import { flyWrap } from 'x4js'
|
|
38
36
|
|
|
39
37
|
const _x4_touch_time = Symbol( );
|
|
40
38
|
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ___ ___ __
|
|
3
|
+
* \ \/ / / _
|
|
4
|
+
* \ / /_| |_
|
|
5
|
+
* / \____ _|
|
|
6
|
+
* /__/\__\ |_|
|
|
7
|
+
*
|
|
8
|
+
* @file autocomplete.ts
|
|
9
|
+
* @author Etienne Cochard
|
|
10
|
+
*
|
|
11
|
+
* Copyright (c) 2019-2022 R-libre ingenierie
|
|
12
|
+
*
|
|
13
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
* in the Software without restriction, including without limitation the rights
|
|
16
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
17
|
+
* of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
18
|
+
* subject to the following conditions:
|
|
19
|
+
* The above copyright notice and this permission notice shall be included in all copies
|
|
20
|
+
* or substantial portions of the Software.
|
|
21
|
+
*
|
|
22
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
23
|
+
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
24
|
+
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
25
|
+
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
26
|
+
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
27
|
+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
|
+
**/
|
|
29
|
+
|
|
30
|
+
import { ListViewItem, PopupListView } from "./listview";
|
|
31
|
+
import { TextEdit, TextEditProps } from './textedit';
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
*
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
interface EditSugProps extends TextEditProps {
|
|
38
|
+
enumValues: ( filter: string ) => string[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
*
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
export class EditSug extends TextEdit<EditSugProps> {
|
|
46
|
+
|
|
47
|
+
private m_popup: PopupListView;
|
|
48
|
+
private m_popvis: boolean;
|
|
49
|
+
private m_needval: boolean;
|
|
50
|
+
private m_lockpop: boolean;
|
|
51
|
+
|
|
52
|
+
constructor( props: EditSugProps ) {
|
|
53
|
+
super( props );
|
|
54
|
+
|
|
55
|
+
this.setDomEvent( "input", ( ) => this._onChange( ) );
|
|
56
|
+
this.setDomEvent( "focusin", ( ) => this._onFocus( ) );
|
|
57
|
+
this.startTimer( "focus-check", 100, true, () => this._checkFocus() );
|
|
58
|
+
|
|
59
|
+
this.m_popvis = false;
|
|
60
|
+
this.m_needval = false;
|
|
61
|
+
this.m_lockpop = false;
|
|
62
|
+
|
|
63
|
+
this.setDomEvent( "keydown", e => this._onKey(e) );
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
_onKey( e: KeyboardEvent ) {
|
|
67
|
+
if( this.m_popvis ) {
|
|
68
|
+
if( e.key=="ArrowUp" || e.key=="ArrowDown" ) {
|
|
69
|
+
this.m_lockpop = true;
|
|
70
|
+
this.m_popup.handleKey( e );
|
|
71
|
+
this.m_lockpop = false;
|
|
72
|
+
|
|
73
|
+
e.preventDefault( );
|
|
74
|
+
e.stopPropagation( );
|
|
75
|
+
}
|
|
76
|
+
else if( e.key=="Escape" ) {
|
|
77
|
+
this._hidePopup( );
|
|
78
|
+
|
|
79
|
+
e.preventDefault( );
|
|
80
|
+
e.stopPropagation( );
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else if( e.key=="ArrowDown" ) {
|
|
84
|
+
this._onChange( );
|
|
85
|
+
e.preventDefault( );
|
|
86
|
+
e.stopPropagation( );
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private _onChange( ) {
|
|
91
|
+
const items = this.m_props.enumValues( this.value );
|
|
92
|
+
this.showPopup( items );
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
componentDisposed( ) {
|
|
96
|
+
if( this.m_popup ) {
|
|
97
|
+
this._hidePopup( );
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
super.componentDisposed( );
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* display the popup
|
|
105
|
+
*/
|
|
106
|
+
|
|
107
|
+
showPopup( items: string[] ) {
|
|
108
|
+
|
|
109
|
+
let props = this.m_props;
|
|
110
|
+
if (props.readOnly || this.hasClass("@disable") ) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// need creation ?
|
|
115
|
+
|
|
116
|
+
if( !this.m_popup ) {
|
|
117
|
+
let cstyle = this.getComputedStyle( );
|
|
118
|
+
let fontFamily = cstyle.value( 'fontFamily' );
|
|
119
|
+
let fontSize = cstyle.value( 'fontSize' );
|
|
120
|
+
|
|
121
|
+
// prepare the combo listview
|
|
122
|
+
this.m_popup = new PopupListView({
|
|
123
|
+
cls: '@combo-popup',
|
|
124
|
+
attrs: {
|
|
125
|
+
tabindex: 0
|
|
126
|
+
},
|
|
127
|
+
selectionChange: (e) => {
|
|
128
|
+
this.value = (e.selection as ListViewItem).id
|
|
129
|
+
if( !this.m_lockpop ) {
|
|
130
|
+
this._hidePopup( );
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
style: {
|
|
134
|
+
fontFamily,
|
|
135
|
+
fontSize
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
this.m_popup.items = items.map( c => ({ id: c, text: c }) );
|
|
141
|
+
|
|
142
|
+
let r1 = this.m_ui_input.getBoundingRect();
|
|
143
|
+
this.m_popup.setStyle({
|
|
144
|
+
minWidth: r1.width,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
this.m_popup.displayAt(r1.left, r1.bottom);
|
|
148
|
+
this.m_popvis = true;
|
|
149
|
+
|
|
150
|
+
//if( this.value!==undefined ) {
|
|
151
|
+
// this.m_popup.selection = this.value;
|
|
152
|
+
//}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
protected override _validate(value: string): boolean {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
override validate( ): boolean {
|
|
160
|
+
return super._validate( this.value );
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
private _checkFocus( ) {
|
|
164
|
+
const focus = document.activeElement;
|
|
165
|
+
if( this.dom.contains(focus) ) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if( this.m_popup && this.m_popup.dom && this.m_popup.dom.contains(focus) ) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
this._hidePopup( );
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private _hidePopup( ) {
|
|
177
|
+
|
|
178
|
+
if( this.m_popvis ) {
|
|
179
|
+
this.m_popup.close();
|
|
180
|
+
this.m_popvis = false;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if( this.m_needval ) {
|
|
184
|
+
this.validate( );
|
|
185
|
+
this.m_needval = false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
private _onFocus( ) {
|
|
190
|
+
if( this.value.length==0 ) {
|
|
191
|
+
this._onChange( );
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
this.m_needval = true;
|
|
195
|
+
}
|
|
196
|
+
}
|
package/src/button.ts
CHANGED
|
@@ -104,6 +104,10 @@ export class BaseButton<P extends ButtonProps = ButtonProps, E extends ButtonEve
|
|
|
104
104
|
const ui_label = new Label({ flex: 1, text: text ?? '', align: props.align, ref: 'label' });
|
|
105
105
|
const ui_ricon = props.rightIcon ? new Icon({ icon: props.rightIcon, cls: 'right', ref: 'r_icon' }) : null;
|
|
106
106
|
|
|
107
|
+
if( text===undefined ) {
|
|
108
|
+
ui_label.addClass( "@hidden" );
|
|
109
|
+
}
|
|
110
|
+
|
|
107
111
|
this.setContent([ui_icon, ui_label, ui_ricon]);
|
|
108
112
|
this._setTabIndex(props.tabIndex);
|
|
109
113
|
}
|
|
@@ -203,7 +207,7 @@ export class BaseButton<P extends ButtonProps = ButtonProps, E extends ButtonEve
|
|
|
203
207
|
this.m_props.text = text;
|
|
204
208
|
|
|
205
209
|
let label = this.itemWithRef<Label>('label');
|
|
206
|
-
if (label) { label.text = text; }
|
|
210
|
+
if (label) { label.text = text; label.removeClass("@hidden") }
|
|
207
211
|
}
|
|
208
212
|
|
|
209
213
|
public get text(): string | HtmlString {
|
package/src/component.ts
CHANGED
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
* create Container class
|
|
34
34
|
*/
|
|
35
35
|
|
|
36
|
-
import { pascalCase, Rect, isString, isArray, Size,
|
|
36
|
+
import { pascalCase, Rect, isString, isArray, Size, isNumber, asap, HtmlString, isHtmlString, Constructor, getMousePos } from './tools';
|
|
37
37
|
import { x4document } from './x4dom';
|
|
38
38
|
|
|
39
39
|
import { Stylesheet, ComputedStyle } from './styles';
|
|
@@ -41,7 +41,6 @@ import { _tr } from './i18n';
|
|
|
41
41
|
import { BasicEvent, EventCallback } from './x4events';
|
|
42
42
|
import { BaseComponent, BaseComponentProps, BaseComponentEventMap } from './base_component';
|
|
43
43
|
import { IDOMEvents, X4ElementEventMap } from './dom_events';
|
|
44
|
-
import { IconID } from 'x4js';
|
|
45
44
|
|
|
46
45
|
export { HtmlString, isHtmlString, html } from './tools'
|
|
47
46
|
|
package/src/form.ts
CHANGED
|
@@ -59,7 +59,7 @@ export interface FormProps extends CProps<FormEventMap> {
|
|
|
59
59
|
*
|
|
60
60
|
*/
|
|
61
61
|
|
|
62
|
-
export class Form extends
|
|
62
|
+
export class Form<T extends FormProps = FormProps, E extends FormEventMap = FormEventMap> extends VLayout<T, E>
|
|
63
63
|
{
|
|
64
64
|
protected m_height: string | number;
|
|
65
65
|
protected m_container: Container;
|
|
@@ -67,7 +67,7 @@ export class Form extends VLayout<FormProps, FormEventMap>
|
|
|
67
67
|
protected m_dirty: boolean;
|
|
68
68
|
protected m_watchChanges: boolean;
|
|
69
69
|
|
|
70
|
-
constructor(props:
|
|
70
|
+
constructor(props: T) {
|
|
71
71
|
|
|
72
72
|
let content = props.content;
|
|
73
73
|
props.content = null;
|
package/src/gridview.ts
CHANGED
|
@@ -41,7 +41,7 @@ import { Component, ContainerEventMap, EvSize, EvDblClick, CProps, flyWrap, html
|
|
|
41
41
|
import { Label } from './label'
|
|
42
42
|
import { _tr } from './i18n'
|
|
43
43
|
import * as Formatters from './formatters'
|
|
44
|
-
import { downloadData } from './tools'
|
|
44
|
+
import { downloadData, isFunction } from './tools'
|
|
45
45
|
import { DataView, DataStore, Record } from './datastore'
|
|
46
46
|
|
|
47
47
|
import { EvContextMenu, EvSelectionChange, BasicEvent, EventDisposer } from "./x4events";
|
|
@@ -134,10 +134,19 @@ class ColHeader extends Component {
|
|
|
134
134
|
return this.m_sorted;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
set sorted( v ) {
|
|
137
|
+
//set sorted( v ) {
|
|
138
|
+
// this.m_sorted = v;
|
|
139
|
+
// this.m_sens = 'dn';
|
|
140
|
+
// this.itemWithRef<Icon>( 'sorter' ).show( v );
|
|
141
|
+
//}
|
|
142
|
+
|
|
143
|
+
sort( v: boolean, sens: "up" | "dn" ) {
|
|
138
144
|
this.m_sorted = v;
|
|
139
|
-
|
|
140
|
-
|
|
145
|
+
this.m_sens = sens;
|
|
146
|
+
|
|
147
|
+
const ic = this.itemWithRef<Icon>('sorter');
|
|
148
|
+
ic.icon = this.m_sens == 'up' ? 'var( --x4-icon-arrow-down )' : 'var( --x4-icon-arrow-up )';
|
|
149
|
+
ic.show(v);
|
|
141
150
|
}
|
|
142
151
|
|
|
143
152
|
get sens( ) {
|
|
@@ -146,7 +155,7 @@ class ColHeader extends Component {
|
|
|
146
155
|
|
|
147
156
|
toggleSens( ) {
|
|
148
157
|
this.m_sens = this.m_sens=='up' ? 'dn' : 'up';
|
|
149
|
-
this.itemWithRef<Icon>( 'sorter' ).icon = this.m_sens=='
|
|
158
|
+
this.itemWithRef<Icon>( 'sorter' ).icon = this.m_sens=='up' ? 'var( --x4-icon-arrow-down )' : 'var( --x4-icon-arrow-up )';
|
|
150
159
|
}
|
|
151
160
|
}
|
|
152
161
|
|
|
@@ -588,7 +597,21 @@ export class GridView extends VLayout<GridViewProps, GridViewEventMap> {
|
|
|
588
597
|
*
|
|
589
598
|
*/
|
|
590
599
|
|
|
591
|
-
|
|
600
|
+
sortCol( name: string, asc = true ) {
|
|
601
|
+
const col = this.m_columns.find(c => c.id==name );
|
|
602
|
+
if( col===undefined ) {
|
|
603
|
+
console.assert( false, "unknown field "+name+" in grid.sortCol" );
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
this._sortCol( col, asc ? "dn" : "up" );
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
/**
|
|
611
|
+
*
|
|
612
|
+
*/
|
|
613
|
+
|
|
614
|
+
private _sortCol(col: GridColumn, sens: "up" | "dn" = "up" ) {
|
|
592
615
|
|
|
593
616
|
if (col.sortable === false) {
|
|
594
617
|
return;
|
|
@@ -596,7 +619,7 @@ export class GridView extends VLayout<GridViewProps, GridViewEventMap> {
|
|
|
596
619
|
|
|
597
620
|
this.m_columns.forEach((c) => {
|
|
598
621
|
if (c !== col) {
|
|
599
|
-
(c as GridColumnInternal).$hdr.
|
|
622
|
+
(c as GridColumnInternal).$hdr.sort( false, "dn" );
|
|
600
623
|
}
|
|
601
624
|
});
|
|
602
625
|
|
|
@@ -606,7 +629,7 @@ export class GridView extends VLayout<GridViewProps, GridViewEventMap> {
|
|
|
606
629
|
$hdr.toggleSens( );
|
|
607
630
|
}
|
|
608
631
|
else {
|
|
609
|
-
$hdr.
|
|
632
|
+
$hdr.sort( true, sens );
|
|
610
633
|
}
|
|
611
634
|
|
|
612
635
|
if (this.m_dataview) {
|
|
@@ -1137,17 +1160,24 @@ export class GridView extends VLayout<GridViewProps, GridViewEventMap> {
|
|
|
1137
1160
|
if( cid ) {
|
|
1138
1161
|
let col = this.m_columns[cid];
|
|
1139
1162
|
|
|
1140
|
-
let
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1163
|
+
let value = rec[col.id];
|
|
1164
|
+
if( value!==undefined ) {
|
|
1165
|
+
if( isFunction(value) ) { // FooterRenderer
|
|
1166
|
+
value( c );
|
|
1167
|
+
}
|
|
1168
|
+
else {
|
|
1169
|
+
let text;
|
|
1170
|
+
const fmt = col.formatter;
|
|
1171
|
+
if (fmt && fmt instanceof Function) {
|
|
1172
|
+
text = fmt(value, rec);
|
|
1173
|
+
}
|
|
1174
|
+
else {
|
|
1175
|
+
text = value;
|
|
1176
|
+
}
|
|
1149
1177
|
|
|
1150
|
-
|
|
1178
|
+
c.setContent( text, false );
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1151
1181
|
}
|
|
1152
1182
|
});
|
|
1153
1183
|
}
|
package/src/index.ts
CHANGED
package/src/listview.ts
CHANGED
|
@@ -122,7 +122,7 @@ export class ListView extends VLayout<ListViewProps,ListViewEventMap> {
|
|
|
122
122
|
constructor(props: ListViewProps) {
|
|
123
123
|
super(props);
|
|
124
124
|
|
|
125
|
-
this.setDomEvent('keydown', (e) => this.
|
|
125
|
+
this.setDomEvent('keydown', (e) => this.handleKey(e));
|
|
126
126
|
this.setDomEvent('click', (e) => this._handleClick(e));
|
|
127
127
|
this.setDomEvent('dblclick', (e) => this._handleClick(e));
|
|
128
128
|
this.setDomEvent('contextmenu', (e) => this._handleCtxMenu(e));
|
|
@@ -198,7 +198,7 @@ export class ListView extends VLayout<ListViewProps,ListViewEventMap> {
|
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
-
|
|
201
|
+
public handleKey(ev: KeyboardEvent) {
|
|
202
202
|
|
|
203
203
|
let moveSel = (sens) => {
|
|
204
204
|
|
|
@@ -237,12 +237,14 @@ export class ListView extends VLayout<ListViewProps,ListViewEventMap> {
|
|
|
237
237
|
switch (ev.key) {
|
|
238
238
|
case 'ArrowDown': {
|
|
239
239
|
moveSel(1);
|
|
240
|
+
ev.preventDefault( );
|
|
240
241
|
ev.stopPropagation();
|
|
241
242
|
break;
|
|
242
243
|
}
|
|
243
244
|
|
|
244
245
|
case 'ArrowUp': {
|
|
245
246
|
moveSel(-1);
|
|
247
|
+
ev.preventDefault( );
|
|
246
248
|
ev.stopPropagation();
|
|
247
249
|
break;
|
|
248
250
|
}
|
|
@@ -705,7 +707,11 @@ export class PopupListView extends Popup<PopupListViewProps,PopupListViewEventMa
|
|
|
705
707
|
this.m_list.items = items;
|
|
706
708
|
}
|
|
707
709
|
|
|
708
|
-
|
|
710
|
+
public handleKey( ev: KeyboardEvent ) {
|
|
711
|
+
this.m_list.handleKey( ev );
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
|
|
709
715
|
// todo: move into popup
|
|
710
716
|
private _handleClick = (e: MouseEvent) => {
|
|
711
717
|
if (!this.dom) {
|
package/src/sidebarview.ts
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
28
28
|
**/
|
|
29
29
|
|
|
30
|
-
import { Component, CProps, Flex } from './component'
|
|
30
|
+
import { Component, CProps, Flex, Separator } from './component'
|
|
31
31
|
import { HLayout, VLayout } from './layout'
|
|
32
32
|
import { Button } from './button'
|
|
33
33
|
import { CardView, CardViewProps, ICardViewItem } from './cardview'
|
|
@@ -37,13 +37,14 @@ export interface SideBarItem extends ICardViewItem {
|
|
|
37
37
|
|
|
38
38
|
export interface SideBarProps extends CardViewProps {
|
|
39
39
|
bar_sizable?: boolean;
|
|
40
|
+
bar_width?: number;
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
/**
|
|
43
44
|
*
|
|
44
45
|
*/
|
|
45
46
|
|
|
46
|
-
export class SideBarView extends CardView {
|
|
47
|
+
export class SideBarView extends CardView<SideBarProps> {
|
|
47
48
|
m_sidebar: VLayout;
|
|
48
49
|
m_content: Component;
|
|
49
50
|
|
|
@@ -55,7 +56,7 @@ export class SideBarView extends CardView {
|
|
|
55
56
|
|
|
56
57
|
this.m_sidebar = new VLayout( {
|
|
57
58
|
cls: '@side-bar',
|
|
58
|
-
|
|
59
|
+
width: props.bar_width ?? undefined,
|
|
59
60
|
});
|
|
60
61
|
|
|
61
62
|
this.m_content = new HLayout( { flex: 1, cls: '@tab-container' } );
|
|
@@ -78,6 +79,7 @@ export class SideBarView extends CardView {
|
|
|
78
79
|
|
|
79
80
|
this.setContent( [
|
|
80
81
|
this.m_sidebar,
|
|
82
|
+
this.m_props.bar_sizable ? new Separator( { orientation: "horizontal", sizing: "before" }) : undefined,
|
|
81
83
|
this.m_content
|
|
82
84
|
] );
|
|
83
85
|
}
|
package/src/svgcomponent.ts
CHANGED
|
@@ -192,9 +192,22 @@ abstract class SVGItem {
|
|
|
192
192
|
return result+'"';
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
+
/**
|
|
196
|
+
*
|
|
197
|
+
*/
|
|
198
|
+
|
|
195
199
|
renderContent( ): string {
|
|
196
200
|
return '';
|
|
197
201
|
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
*
|
|
205
|
+
*/
|
|
206
|
+
|
|
207
|
+
clip( id: string ) {
|
|
208
|
+
this.attr( "clip-path", `url(#${id})` );
|
|
209
|
+
return this;
|
|
210
|
+
}
|
|
198
211
|
}
|
|
199
212
|
|
|
200
213
|
/**
|
|
@@ -391,12 +404,13 @@ class SVGGradient extends SVGItem {
|
|
|
391
404
|
*
|
|
392
405
|
*/
|
|
393
406
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
private m_items: SVGItem[];
|
|
407
|
+
class SVGGroup extends SVGItem {
|
|
408
|
+
protected m_items: SVGItem[];
|
|
397
409
|
|
|
398
|
-
constructor( ) {
|
|
399
|
-
|
|
410
|
+
constructor( tag = "g" ) {
|
|
411
|
+
super( tag )
|
|
412
|
+
|
|
413
|
+
this.m_items = [];
|
|
400
414
|
}
|
|
401
415
|
|
|
402
416
|
path( ) {
|
|
@@ -445,7 +459,7 @@ export class SVGPathBuilder
|
|
|
445
459
|
this.m_items = [];
|
|
446
460
|
}
|
|
447
461
|
|
|
448
|
-
|
|
462
|
+
renderContent( ) {
|
|
449
463
|
let result: string[] = [];
|
|
450
464
|
this.m_items.forEach( i => {
|
|
451
465
|
result.push( i.render() );
|
|
@@ -455,6 +469,41 @@ export class SVGPathBuilder
|
|
|
455
469
|
}
|
|
456
470
|
}
|
|
457
471
|
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
*
|
|
475
|
+
*/
|
|
476
|
+
|
|
477
|
+
export class SVGPathBuilder extends SVGGroup
|
|
478
|
+
{
|
|
479
|
+
private static g_clip_id = 1;
|
|
480
|
+
|
|
481
|
+
constructor( ) {
|
|
482
|
+
super( '' );
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
addClip( x: number, y: number, w: number, h: number ) {
|
|
486
|
+
|
|
487
|
+
const id = 'c-'+SVGPathBuilder.g_clip_id++;
|
|
488
|
+
const clip = new SVGGroup( 'clipPath' );
|
|
489
|
+
clip.attr('id', id );
|
|
490
|
+
clip.rect( x, y, w, h );
|
|
491
|
+
|
|
492
|
+
this.m_items.push(clip);
|
|
493
|
+
return id;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
render() {
|
|
497
|
+
|
|
498
|
+
let result = [];
|
|
499
|
+
this.m_items.forEach(i => {
|
|
500
|
+
result.push(i.render());
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
return result.join('\n');
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
458
507
|
/**
|
|
459
508
|
*
|
|
460
509
|
*/
|
package/src/textedit.ts
CHANGED
|
@@ -87,13 +87,13 @@ export interface TextEditProps extends InputProps<TextEditEventMap> {
|
|
|
87
87
|
* TextEdit is a single line editor, it can have a label and an error descriptor.
|
|
88
88
|
*/
|
|
89
89
|
|
|
90
|
-
export class TextEdit<T extends TextEditProps = TextEditProps> extends Component<
|
|
90
|
+
export class TextEdit<T extends TextEditProps = TextEditProps, E extends TextEditEventMap = TextEditEventMap > extends Component<T, E> {
|
|
91
91
|
|
|
92
92
|
private m_cal_popup: PopupCalendar;
|
|
93
93
|
protected m_ui_input: Input;
|
|
94
94
|
private m_error_tip: Tooltip;
|
|
95
95
|
|
|
96
|
-
constructor(props:
|
|
96
|
+
constructor(props: T) {
|
|
97
97
|
super(props);
|
|
98
98
|
this.addClass( '@hlayout' );
|
|
99
99
|
this.mapPropEvents( props, 'change', 'click', 'focus' );
|
|
@@ -410,7 +410,7 @@ export class TextEdit<T extends TextEditProps = TextEditProps> extends Component
|
|
|
410
410
|
return this._validate(this.value);
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
-
|
|
413
|
+
protected _validate(value: string): boolean {
|
|
414
414
|
let props = this.m_props;
|
|
415
415
|
let update = false;
|
|
416
416
|
|
package/src/tools.ts
CHANGED
|
@@ -496,7 +496,7 @@ export function date_clone(date: Date): Date {
|
|
|
496
496
|
export function date_calc_weeknum(date: Date): number {
|
|
497
497
|
const firstDayOfYear = new Date(date.getFullYear(), 0, 1);
|
|
498
498
|
const pastDaysOfYear = (date.valueOf() - firstDayOfYear.valueOf()) / 86400000;
|
|
499
|
-
return Math.
|
|
499
|
+
return Math.floor((pastDaysOfYear + firstDayOfYear.getDay() + 1) / 7);
|
|
500
500
|
}
|
|
501
501
|
|
|
502
502
|
|
|
@@ -1406,3 +1406,63 @@ function shuffle(str: string, maxlength?: number) {
|
|
|
1406
1406
|
|
|
1407
1407
|
return shuffled;
|
|
1408
1408
|
}
|
|
1409
|
+
|
|
1410
|
+
|
|
1411
|
+
|
|
1412
|
+
/**
|
|
1413
|
+
* taken from live-server
|
|
1414
|
+
* https://github.com/tapio/live-server
|
|
1415
|
+
* @param host
|
|
1416
|
+
* @param port
|
|
1417
|
+
*/
|
|
1418
|
+
|
|
1419
|
+
export function installHMR(host = "127.0.0.1", port = "9876", reloadCallback?: Function ) {
|
|
1420
|
+
|
|
1421
|
+
let tm;
|
|
1422
|
+
|
|
1423
|
+
function refreshCSS() {
|
|
1424
|
+
|
|
1425
|
+
document.body.style.visibility = "hidden";
|
|
1426
|
+
|
|
1427
|
+
let sheets = [].slice.call(document.getElementsByTagName("link"));
|
|
1428
|
+
let head = document.getElementsByTagName("head")[0];
|
|
1429
|
+
|
|
1430
|
+
for (let i = 0; i < sheets.length; ++i) {
|
|
1431
|
+
let elem = sheets[i];
|
|
1432
|
+
head.removeChild(elem);
|
|
1433
|
+
|
|
1434
|
+
let rel = elem.rel;
|
|
1435
|
+
if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") {
|
|
1436
|
+
let url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, '');
|
|
1437
|
+
elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
head.appendChild(elem);
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
if( tm ) { clearTimeout(tm); }
|
|
1444
|
+
tm = setTimeout( () => {
|
|
1445
|
+
document.body.style.visibility = "unset";
|
|
1446
|
+
}, 50 );
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
const protocol = window.location.protocol === 'https:' ? 'wss://' : 'ws://';
|
|
1450
|
+
const address = `${protocol}${host}:${port}/ws`;
|
|
1451
|
+
const socket = new WebSocket(address);
|
|
1452
|
+
|
|
1453
|
+
socket.onmessage = function (msg) {
|
|
1454
|
+
if (msg.data == 'reload') {
|
|
1455
|
+
if( reloadCallback ) {
|
|
1456
|
+
reloadCallback( );
|
|
1457
|
+
}
|
|
1458
|
+
else {
|
|
1459
|
+
window.location.reload();
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
else if (msg.data == 'refreshcss') {
|
|
1463
|
+
refreshCSS();
|
|
1464
|
+
}
|
|
1465
|
+
};
|
|
1466
|
+
|
|
1467
|
+
console.log('Live reload enabled.');
|
|
1468
|
+
}
|